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

Commit 0bf995e9 authored by George Chan's avatar George Chan
Browse files

Cleaning and improving readability of UsbDataAdvancedProtectionHook.

Test: m
Bug: 395965739
Flag: android.security.aapm_feature_usb_data_protection
Change-Id: I8c2e29e675b6bc115af30b46a2e47c98d9720af7
parent d03cfaf7
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() {