Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 46a67de1 authored by George Chan's avatar George Chan Committed by Android (Google) Code Review
Browse files

Merge "Cleaning and improving readability of UsbDataAdvancedProtectionHook." into main

parents 54d27f03 0bf995e9
Loading
Loading
Loading
Loading
+70 −72
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import static android.content.Intent.ACTION_SCREEN_OFF;
import static android.content.Intent.ACTION_USER_PRESENT;
import static android.hardware.usb.UsbManager.ACTION_USB_PORT_CHANGED;
import static android.security.advancedprotection.AdvancedProtectionManager.FEATURE_ID_DISALLOW_USB;
import static android.hardware.usb.UsbPortStatus.DATA_ROLE_NONE;
import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_FORCE;

import android.app.KeyguardManager;
import android.app.Notification;
@@ -33,15 +35,18 @@ import android.hardware.usb.ParcelableUsbPort;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
import android.hardware.usb.IUsbManagerInternal;
import android.hardware.usb.UsbPort;
import android.hardware.usb.UsbPortStatus;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Slog;

import com.android.server.LocalServices;
import java.lang.Runnable;

import java.util.function.Consumer;
@@ -52,6 +57,7 @@ import android.security.advancedprotection.AdvancedProtectionFeature;
import com.android.internal.R;

import java.util.Map;
import java.util.Objects;

/**
 * AAPM Feature for managing and protecting USB data signal from attacks.
@@ -65,11 +71,13 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook {
    private static final String CHANNEL_NAME = "BackgroundInstallUiNotificationChannel";
    private static final int APM_USB_FEATURE_CHANNEL_ID = 1;
    private static final int DELAY_DISABLE_MS = 1000;
    private static final int OS_USB_DISABLE_REASON_LOCKDOWN_MODE = 1;

    private final Context mContext;
    private final Handler mDelayedDisableHandler = new Handler(Looper.getMainLooper());

    private UsbManager mUsbManager;
    private IUsbManagerInternal mUsbManagerInternal;
    private BroadcastReceiver mUsbProtectionBroadcastReceiver;
    private KeyguardManager mKeyguardManager;
    private NotificationManager mNotificationManager;
@@ -85,6 +93,8 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook {
        super(context, enabled);
        mContext = context;
        mUsbManager = mContext.getSystemService(UsbManager.class);
        mUsbManagerInternal = Objects.requireNonNull(
            LocalServices.getService(IUsbManagerInternal.class));
        onAdvancedProtectionChanged(enabled);
    }

@@ -117,9 +127,7 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook {
            if (mBroadcastReceiverIsRegistered) {
                unregisterReceiver();
            }
            if (!mUsbManager.enableUsbDataSignal(true)) {
                Slog.e(TAG, "USB Data protection toggle failed");
            }
            setUsbDataSignalIfPossible(true);
        }
    }

@@ -134,66 +142,51 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook {
                            if (ACTION_USER_PRESENT.equals(intent.getAction())
                                    && !mKeyguardManager.isKeyguardLocked()) {
                                mDelayedDisableHandler.removeCallbacksAndMessages(null);
                                setUsbDataSignalIfNoConnectedDevices(true);
                                setUsbDataSignalIfPossible(true);

                            } else if (ACTION_SCREEN_OFF.equals(intent.getAction())
                                    && mKeyguardManager.isKeyguardLocked()) {
                                setUsbDataSignalIfNoConnectedDevices(false);
                                setUsbDataSignalIfPossible(false);

                            } else if (ACTION_USB_PORT_CHANGED.equals(intent.getAction())) {
                                if (Build.IS_DEBUGGABLE) {
                                    dumpUsbDevices();
                                }
                                setDelayedDisableTaskIfDisconnectedAndLocked(intent);
                                if(mKeyguardManager.isKeyguardLocked()) {
                                    updateDelayedDisableTask(intent);
                                }
                                sendNotificationIfDeviceLocked(intent);

                            }
                        } catch (Exception e) {
                            Slog.e(TAG, "USB Data protection failed with: " + e.getMessage());
                        }
                    }

                    private boolean getUsbPortStatusIsConnectedAndDataEnabled(Intent intent) {
                        UsbPortStatus portStatus =
                                intent.getParcelableExtra(
                                        UsbManager.EXTRA_PORT_STATUS, UsbPortStatus.class);
                        return portStatus != null
                                && portStatus.isConnected()
                                && portStatus.getUsbDataStatus()
                                        != UsbPortStatus.DATA_STATUS_DISABLED_FORCE;
                    }

                    private void setDelayedDisableTaskIfDisconnectedAndLocked(Intent intent) {
                        if(mKeyguardManager.isKeyguardLocked()) {
                            if(getUsbPortStatusIsConnectedAndDataEnabled(intent)) {
                    private void updateDelayedDisableTask(Intent intent) {
                        // For recovered intermittent/unreliable USB connections
                        if(usbPortIsConnectedAndDataEnabled(intent)) {
                            mDelayedDisableHandler.removeCallbacksAndMessages(null);
                        } else if(!mDelayedDisableHandler.hasMessagesOrCallbacks()) {
                            mDelayedDisableHandler.postDelayed(() -> {
                                    disableChangedUsbPortIfDisconnected(intent);
                                }, DELAY_DISABLE_MS);
                                if (mKeyguardManager.isKeyguardLocked()) {
                                    setUsbDataSignalIfPossible(false);
                                }
                            }, DELAY_DISABLE_MS);
                        }
                    }

                    private void disableChangedUsbPortIfDisconnected(Intent intent) {
                    private boolean usbPortIsConnectedAndDataEnabled(Intent intent) {
                        UsbPortStatus portStatus =
                                intent.getParcelableExtra(
                                        UsbManager.EXTRA_PORT_STATUS, UsbPortStatus.class);
                        if (Build.IS_DEBUGGABLE) {
                            Slog.i(
                                    TAG,
                                    "disableChangedUsbPortIfDisconnected: " + portStatus == null
                                            ? "null"
                                            : portStatus.toString());
                        }

                        if (mKeyguardManager.isKeyguardLocked()
                                && portStatus != null && !portStatus.isConnected()
                        ) {
                            intent.getParcelableExtra(
                                            UsbManager.EXTRA_PORT, ParcelableUsbPort.class)
                                    .getUsbPort(mUsbManager)
                                    .enableUsbData(false);
                        }
                        return portStatus != null
                                && portStatus.isConnected()
                                && portStatus.getUsbDataStatus()
                                        != UsbPortStatus.DATA_STATUS_DISABLED_FORCE;
                    }

                    // TODO: b/401540215 Remove this as part of pre-release cleanup
                    private void dumpUsbDevices() {
                        Slog.d(TAG, "dumpUsbDevices: ");
                        Map<String, UsbDevice> portStatusMap = mUsbManager.getDeviceList();
@@ -238,9 +231,7 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook {
            UsbPortStatus portStatus =
                    intent.getParcelableExtra(UsbManager.EXTRA_PORT_STATUS, UsbPortStatus.class);
            if (mKeyguardManager.isKeyguardLocked()
                    && portStatus != null
                    && portStatus.isConnected()
                    && portStatus.getUsbDataStatus() == UsbPortStatus.DATA_STATUS_DISABLED_FORCE) {
                    && usbPortIsConnectedWithDataDisabled(portStatus)) {
                sendNotification(
                        mContext.getString(
                                R.string.usb_apm_usb_plugged_in_when_locked_notification_title),
@@ -251,39 +242,46 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook {
        }
    }

    private void setUsbDataSignalIfNoConnectedDevices(boolean status) {
        // disable all ports that don't have an active data connection
        if (!status) {
    private boolean usbPortIsConnectedWithDataDisabled(UsbPortStatus portStatus) {
        return portStatus != null
                && portStatus.isConnected()
                && portStatus.getUsbDataStatus() == DATA_STATUS_DISABLED_FORCE;
    }

    private void setUsbDataSignalIfPossible(boolean status) {
        if (!status && deviceHaveUsbDataConnection()) {
            return;
        }
        try {
            if (!mUsbManagerInternal.enableUsbDataSignal(status,
                    OS_USB_DISABLE_REASON_LOCKDOWN_MODE)) {
                Slog.e(TAG, "USB Data protection toggle failed");
            }
        } catch (RemoteException e) {
            Slog.e(TAG, "RemoteException thrown when calling enableUsbDataSignal", e);
        }
    }

    private boolean deviceHaveUsbDataConnection() {
        for (UsbPort usbPort : mUsbManager.getPorts()) {
            if (Build.IS_DEBUGGABLE) {
                Slog.i(
                        TAG,
                            "setUsbDataSignal: false " + usbPort.getStatus() == null
                        "setUsbDataSignal: false, Port status: " + usbPort.getStatus() == null
                                ? "null"
                                : usbPort.getStatus().toString());
            }
                if (usbPort.getStatus() == null
                        || !usbPort.getStatus().isConnected()
                        || usbPort.getStatus().getCurrentDataRole()
                                == UsbPortStatus.DATA_ROLE_NONE) {
                    usbPort.enableUsbData(false);
            if (usbPortIsConnectedWithDataEnabled(usbPort)) {
                return true;
            }
        }
        return false;
    }
        // Always re-enable all if true
        else {
            if (!mUsbManager.enableUsbDataSignal(status)) {
                Slog.e(TAG, "USB Data protection toggle failed");
            }
            for (UsbPort usbPort : mUsbManager.getPorts()) {
                usbPort.resetUsbPort(mContext.getMainExecutor(),
                new Consumer<Integer>() {
                    public void accept(Integer status) {
                        Slog.i(TAG, "Consumer status: " + status);
                    }
                });
            }
        }

    private boolean usbPortIsConnectedWithDataEnabled(UsbPort usbPort) {
        return usbPort.getStatus() != null
                && usbPort.getStatus().isConnected()
                && usbPort.getStatus().getCurrentDataRole() != DATA_ROLE_NONE;
    }

    private void registerReceiver() {