Loading services/core/java/com/android/server/security/advancedprotection/features/UsbDataAdvancedProtectionHook.java +149 −86 Original line number Diff line number Diff line Loading @@ -25,6 +25,10 @@ import static android.hardware.usb.UsbPortStatus.DATA_ROLE_NONE; import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_FORCE; import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_BC_1_2; import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_INPUT_POWER_LIMITED; import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK; import static android.hardware.usb.UsbPortStatus.POWER_BRICK_STATUS_CONNECTED; import static android.hardware.usb.UsbPortStatus.POWER_BRICK_STATUS_DISCONNECTED; import static android.hardware.usb.UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN; import static android.hardware.usb.InternalUsbDataSignalDisableReason.USB_DISABLE_REASON_APM; import android.app.KeyguardManager; Loading Loading @@ -53,15 +57,13 @@ import android.os.Looper; import android.os.RemoteException; import android.os.SystemProperties; import android.os.UserHandle; import android.os.SystemClock; import android.security.Flags; import android.util.Slog; import com.android.server.LocalServices; import java.lang.Runnable; import java.util.function.Consumer; import java.util.concurrent.Executor; import android.security.advancedprotection.AdvancedProtectionFeature; import com.android.internal.R; Loading @@ -86,6 +88,11 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { "ro.usb.data_protection.disable_when_locked.supported"; private static final String USB_DATA_PROTECTION_REPLUG_REQUIRED_UPON_ENABLE_SYSTEM_PROPERTY = "ro.usb.data_protection.apm.replug_required_upon_enable"; private static final String USB_DATA_PROTECTION_POWER_BRICK_CONNECTION_CHECK_TIMEOUT_SYSTEM_PROPERTY = "ro.usb.data_protection.apm.power_brick_connection_check_timeout"; private static final String USB_DATA_PROTECTION_PD_COMPLIANCE_CHECK_TIMEOUT_SYSTEM_PROPERTY = "ro.usb.data_protection.apm.pd_compliance_check_timeout"; private static final String USB_DATA_PROTECTION_DATA_REQUIRED_FOR_HIGH_POWER_CHARGE_SYSTEM_PROPERTY = "ro.usb.data_protection.apm.data_required_for_high_power_charge"; Loading @@ -94,11 +101,19 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { private static final String EXTRA_SILENCE_DATA_NOTIFICATION = "silence_data_notification"; private static final String EXTRA_SILENCE_POWER_NOTIFICATION = "silence_power_notification"; private static final int DELAY_DISABLE_MS = 3000; private static final int DELAY_DISABLE_MILLIS = 5000; private static final int USB_DATA_CHANGE_MAX_RETRY_ATTEMPTS = 3; private static final long USB_PORT_POWER_BRICK_CONNECTION_CHECK_TIMEOUT_DEFAULT_MILLIS = 3000; private static final long USB_PD_COMPLIANCE_CHECK_TIMEOUT_DEFAULT_MILLIS = 1000; private final Context mContext; // We use handlers for tasks that may need to be updated by broadcasts events. private final Handler mDelayedDisableHandler = new Handler(Looper.getMainLooper()); private final Handler mDelayedNotificationHandler = new Handler(Looper.getMainLooper()); private AdvancedProtectionFeature mFeature = new AdvancedProtectionFeature(FEATURE_ID_DISALLOW_USB); private final Context mContext; private UsbManager mUsbManager; private IUsbManagerInternal mUsbManagerInternal; Loading @@ -107,16 +122,19 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { private NotificationManager mNotificationManager; private NotificationChannel mNotificationChannel; private PendingIntent mHelpPendingIntent; private UsbPortStatus mLastUsbPortStatus; // TODO(b/418846176): Move these to a system property private long mUsbPortPowerBrickConnectionCheckTimeoutMillis; private long mUsbPortPdComplianceCheckTimeoutMillis; private boolean mCanSetUsbDataSignal = false; private boolean mDataRequiredForHighPowerCharge = false; private boolean mReplugRequiredUponEnable = false; private boolean mSilenceDataNotification = false; private boolean mSilencePowerNotification = false; private AdvancedProtectionFeature mFeature = new AdvancedProtectionFeature(FEATURE_ID_DISALLOW_USB); private boolean mBroadcastReceiverIsRegistered = false; private PendingIntent mHelpPendingIntent; private boolean mIsAfterFirstUnlock = false; public UsbDataAdvancedProtectionHook(Context context, boolean enabled) { Loading Loading @@ -155,13 +173,11 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { } Slog.i(TAG, "onAdvancedProtectionChanged: " + enabled); if (enabled) { Slog.i(TAG, "onAdvancedProtectionChanged: enabled"); if (mUsbProtectionBroadcastReceiver == null) { initialize(); } if (!mBroadcastReceiverIsRegistered) { registerReceiver(); setupNotificationIntents(); } setUsbDataSignalIfPossible(false); } else { Loading @@ -181,7 +197,16 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { mReplugRequiredUponEnable = SystemProperties.getBoolean( USB_DATA_PROTECTION_REPLUG_REQUIRED_UPON_ENABLE_SYSTEM_PROPERTY, false); mUsbPortPowerBrickConnectionCheckTimeoutMillis = SystemProperties.getLong( USB_DATA_PROTECTION_POWER_BRICK_CONNECTION_CHECK_TIMEOUT_SYSTEM_PROPERTY, USB_PORT_POWER_BRICK_CONNECTION_CHECK_TIMEOUT_DEFAULT_MILLIS); mUsbPortPdComplianceCheckTimeoutMillis = SystemProperties.getLong( USB_DATA_PROTECTION_PD_COMPLIANCE_CHECK_TIMEOUT_SYSTEM_PROPERTY, USB_PD_COMPLIANCE_CHECK_TIMEOUT_DEFAULT_MILLIS); initializeNotifications(); setupNotificationIntents(); mUsbProtectionBroadcastReceiver = new BroadcastReceiver() { @Override Loading @@ -191,6 +216,7 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { && !mKeyguardManager.isKeyguardLocked()) { mIsAfterFirstUnlock = true; mDelayedDisableHandler.removeCallbacksAndMessages(null); cleanUpNotificationHandlerTasks(); setUsbDataSignalIfPossible(true); } else if (ACTION_SCREEN_OFF.equals(intent.getAction()) Loading @@ -198,11 +224,20 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { setUsbDataSignalIfPossible(false); } else if (ACTION_USB_PORT_CHANGED.equals(intent.getAction())) { UsbPortStatus portStatus = intent.getParcelableExtra( UsbManager.EXTRA_PORT_STATUS, UsbPortStatus.class); // If we cannot retrieve the port status, then we skip this event. if (portStatus == null) { Slog.w( TAG, "UsbPort Changed: USB Data protection failed to" + " retrieve port status"); return; } mLastUsbPortStatus = portStatus; if (Build.IS_DEBUGGABLE) { dumpUsbDevices(portStatus); } Loading @@ -211,62 +246,58 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { updateDelayedDisableTask(portStatus); } if (isUsbConnected(portStatus)) { if (!portStatus.isConnected()) { cleanUpNotificationHandlerTasks(); clearExistingNotification(); /* * Due to limitations of current APIs, we cannot cannot fully * rely on power brick and pd compliance check to be accurate * until it's passed the check timeouts unless the value is * POWER_BRICK_STATUS_CONNECTED or isCompliant=true * respectively. */ } else if (portStatus.getCurrentPowerRole() == POWER_ROLE_SINK) { long pbCheckDuration = portStatus.getPowerBrickConnectionStatus() != POWER_BRICK_STATUS_CONNECTED ? mUsbPortPowerBrickConnectionCheckTimeoutMillis : 0; long pdCheckDuration = !portStatus.isPdCompliant() ? mUsbPortPdComplianceCheckTimeoutMillis : 0; long delayTimeMillis = pbCheckDuration + pdCheckDuration; if (delayTimeMillis <= 0) { cleanUpNotificationHandlerTasks(); determineUsbChargeStateAndSendNotification(portStatus); } else { if (isUsbPortConnectionPowerBrick(portStatus)) { // For cases where high speed chargers do not use USB-PD // PPS, or uses BC1.2 if (mDataRequiredForHighPowerCharge || isUsbChargingComplianceWarningPresent( portStatus)) { sendPowerNotificationIfDeviceLocked(portStatus); updateDelayedNotificationTask(delayTimeMillis); } } else { if (isPortPowerSinking(portStatus) && (mDataRequiredForHighPowerCharge || !portStatus.isPdCompliant() || isUsbChargingComplianceWarningPresent( portStatus))) { sendPowerAndDataNotificationIfDeviceLocked(portStatus); } else { cleanUpNotificationHandlerTasks(); sendDataNotificationIfDeviceLocked(portStatus); } } } } } catch (Exception e) { Slog.e(TAG, "USB Data protection failed with: " + e.getMessage()); } } private boolean isUsbChargingComplianceWarningPresent( UsbPortStatus portStatus) { if (portStatus != null) { for (int warning : portStatus.getComplianceWarnings()) { if (warning == COMPLIANCE_WARNING_BC_1_2 || warning == COMPLIANCE_WARNING_INPUT_POWER_LIMITED) { return true; } } } return false; } private boolean isUsbConnected(UsbPortStatus portStatus) { return portStatus != null && !portStatus.isConnected(); private void updateDelayedNotificationTask(long delayTimeMillis) { if (!mDelayedNotificationHandler.hasMessagesOrCallbacks() && delayTimeMillis > 0) { boolean taskPosted = mDelayedNotificationHandler.postDelayed( () -> { determineUsbChargeStateAndSendNotification( mLastUsbPortStatus); }, delayTimeMillis); if (!taskPosted) { Slog.w(TAG, "Delayed Disable Task: Failed to post task"); } private boolean isUsbPortConnectionPowerBrick(UsbPortStatus portStatus) { return portStatus != null && portStatus.getPowerBrickConnectionStatus() == UsbPortStatus.POWER_BRICK_STATUS_CONNECTED; } private boolean isPortPowerSinking(UsbPortStatus portStatus) { return portStatus != null && portStatus.getCurrentPowerRole() == UsbPortStatus.POWER_ROLE_SINK; } private void updateDelayedDisableTask(UsbPortStatus portStatus) { Loading @@ -274,16 +305,46 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { if (usbPortIsConnectedAndDataEnabled(portStatus)) { mDelayedDisableHandler.removeCallbacksAndMessages(null); } else if (!mDelayedDisableHandler.hasMessagesOrCallbacks()) { boolean taskPosted = mDelayedDisableHandler.postDelayed( () -> { if (mKeyguardManager.isKeyguardLocked()) { setUsbDataSignalIfPossible(false); } }, DELAY_DISABLE_MS); DELAY_DISABLE_MILLIS); if (!taskPosted) { Slog.w(TAG, "Delayed Disable Task: Failed to post task"); } } } private void determineUsbChargeStateAndSendNotification( UsbPortStatus portStatus) { clearExistingNotification(); if (portStatus.getPowerBrickConnectionStatus() == POWER_BRICK_STATUS_CONNECTED) { if (mDataRequiredForHighPowerCharge) { sendPowerNotificationIfDeviceLocked(portStatus); } } else { if (portStatus.isPdCompliant()) { if (mDataRequiredForHighPowerCharge) { sendPowerAndDataNotificationIfDeviceLocked(portStatus); } else { sendDataNotificationIfDeviceLocked(portStatus); } } else { sendPowerAndDataNotificationIfDeviceLocked(portStatus); } } } private void cleanUpNotificationHandlerTasks() { mDelayedNotificationHandler.removeCallbacksAndMessages(null); } private boolean usbPortIsConnectedAndDataEnabled(UsbPortStatus portStatus) { return portStatus != null && portStatus.isConnected() Loading @@ -293,9 +354,6 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { // TODO:(b/401540215) Remove this as part of pre-release cleanup private void dumpUsbDevices(UsbPortStatus portStatus) { Slog.d(TAG, "dumpUsbDevices: " + portStatus.toString()); Slog.d(TAG, "dumpUsbDevices: PD-compliance: " + portStatus.isPdCompliant()); Slog.d(TAG, "dumpUsbDevices: "); Map<String, UsbDevice> portStatusMap = mUsbManager.getDeviceList(); for (UsbDevice device : portStatusMap.values()) { Slog.d(TAG, "Device: " + device.getDeviceName()); Loading Loading @@ -349,6 +407,10 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { silencePendingIntent); } // Intent may fail to initialize in BFU state, so we may need to initialize it lazily. if (mHelpPendingIntent == null) { setupNotificationIntents(); } if (mHelpPendingIntent != null) { notif.setContentIntent(mHelpPendingIntent); } Loading @@ -373,7 +435,8 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { if (mReplugRequiredUponEnable) { notificationTitle = mContext.getString( R.string.usb_apm_usb_plugged_in_when_locked_replug_notification_title); R.string .usb_apm_usb_plugged_in_when_locked_replug_notification_title); notificationBody = mContext.getString( R.string Loading Loading @@ -407,7 +470,8 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { if (mReplugRequiredUponEnable) { notificationTitle = mContext.getString( R.string.usb_apm_usb_plugged_in_when_locked_replug_notification_title); R.string .usb_apm_usb_plugged_in_when_locked_replug_notification_title); notificationBody = mContext.getString( R.string Loading Loading @@ -445,7 +509,8 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { if (mReplugRequiredUponEnable) { notificationTitle = mContext.getString( R.string.usb_apm_usb_plugged_in_when_locked_replug_notification_title); R.string .usb_apm_usb_plugged_in_when_locked_replug_notification_title); notificationBody = mContext.getString( R.string Loading Loading @@ -480,15 +545,15 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { * We check if there is already an existing USB connection and skip the USB * disablement if there is one unless it is in BFU state. */ if (!status && (deviceHaveUsbDataConnection() && mIsAfterFirstUnlock)) { if (!status && deviceHaveUsbDataConnection() && mIsAfterFirstUnlock) { Slog.i(TAG, "USB Data protection toggle skipped due to existing USB connection"); return; } int usbChangeStateReattempts = 0; while (usbChangeStateReattempts < USB_DATA_CHANGE_MAX_RETRY_ATTEMPTS) { try { if (mUsbManagerInternal.enableUsbDataSignal( status, USB_DISABLE_REASON_APM)) { if (mUsbManagerInternal.enableUsbDataSignal(status, USB_DISABLE_REASON_APM)) { break; } else { Slog.e(TAG, "USB Data protection toggle attempt failed"); Loading Loading @@ -528,9 +593,10 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { } private boolean usbPortIsConnectedWithDataEnabled(UsbPort usbPort) { return usbPort.getStatus() != null && usbPort.getStatus().isConnected() && usbPort.getStatus().getCurrentDataRole() != DATA_ROLE_NONE; UsbPortStatus usbPortStatus = usbPort.getStatus(); return usbPortStatus != null && usbPortStatus.isConnected() && usbPortStatus.getCurrentDataRole() != DATA_ROLE_NONE; } private void registerReceiver() { Loading Loading @@ -559,6 +625,7 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { mBroadcastReceiverIsRegistered = false; } // TODO:(b/428090717) Fix intent resolution during boot time private void setupNotificationIntents() { try { String helpIntentActivityUri = Loading @@ -573,16 +640,12 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(helpIntent, 0); if (resolveInfo != null && resolveInfo.activityInfo != null) { mHelpPendingIntent = PendingIntent.getActivityAsUser( mContext, 0, helpIntent, PendingIntent.FLAG_IMMUTABLE, null, UserHandle.ALL); PendingIntent.getActivity( mContext, 0, helpIntent, PendingIntent.FLAG_IMMUTABLE, null); } else { Slog.w(TAG, "Failed to resolve help intent " + resolveInfo); } Slog.d(TAG, "setupNotificationIntents setup successfully: " + mHelpPendingIntent); } catch (Exception e) { Slog.e(TAG, "Failed to setup notification intents", e); } Loading Loading
services/core/java/com/android/server/security/advancedprotection/features/UsbDataAdvancedProtectionHook.java +149 −86 Original line number Diff line number Diff line Loading @@ -25,6 +25,10 @@ import static android.hardware.usb.UsbPortStatus.DATA_ROLE_NONE; import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_FORCE; import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_BC_1_2; import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_INPUT_POWER_LIMITED; import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK; import static android.hardware.usb.UsbPortStatus.POWER_BRICK_STATUS_CONNECTED; import static android.hardware.usb.UsbPortStatus.POWER_BRICK_STATUS_DISCONNECTED; import static android.hardware.usb.UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN; import static android.hardware.usb.InternalUsbDataSignalDisableReason.USB_DISABLE_REASON_APM; import android.app.KeyguardManager; Loading Loading @@ -53,15 +57,13 @@ import android.os.Looper; import android.os.RemoteException; import android.os.SystemProperties; import android.os.UserHandle; import android.os.SystemClock; import android.security.Flags; import android.util.Slog; import com.android.server.LocalServices; import java.lang.Runnable; import java.util.function.Consumer; import java.util.concurrent.Executor; import android.security.advancedprotection.AdvancedProtectionFeature; import com.android.internal.R; Loading @@ -86,6 +88,11 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { "ro.usb.data_protection.disable_when_locked.supported"; private static final String USB_DATA_PROTECTION_REPLUG_REQUIRED_UPON_ENABLE_SYSTEM_PROPERTY = "ro.usb.data_protection.apm.replug_required_upon_enable"; private static final String USB_DATA_PROTECTION_POWER_BRICK_CONNECTION_CHECK_TIMEOUT_SYSTEM_PROPERTY = "ro.usb.data_protection.apm.power_brick_connection_check_timeout"; private static final String USB_DATA_PROTECTION_PD_COMPLIANCE_CHECK_TIMEOUT_SYSTEM_PROPERTY = "ro.usb.data_protection.apm.pd_compliance_check_timeout"; private static final String USB_DATA_PROTECTION_DATA_REQUIRED_FOR_HIGH_POWER_CHARGE_SYSTEM_PROPERTY = "ro.usb.data_protection.apm.data_required_for_high_power_charge"; Loading @@ -94,11 +101,19 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { private static final String EXTRA_SILENCE_DATA_NOTIFICATION = "silence_data_notification"; private static final String EXTRA_SILENCE_POWER_NOTIFICATION = "silence_power_notification"; private static final int DELAY_DISABLE_MS = 3000; private static final int DELAY_DISABLE_MILLIS = 5000; private static final int USB_DATA_CHANGE_MAX_RETRY_ATTEMPTS = 3; private static final long USB_PORT_POWER_BRICK_CONNECTION_CHECK_TIMEOUT_DEFAULT_MILLIS = 3000; private static final long USB_PD_COMPLIANCE_CHECK_TIMEOUT_DEFAULT_MILLIS = 1000; private final Context mContext; // We use handlers for tasks that may need to be updated by broadcasts events. private final Handler mDelayedDisableHandler = new Handler(Looper.getMainLooper()); private final Handler mDelayedNotificationHandler = new Handler(Looper.getMainLooper()); private AdvancedProtectionFeature mFeature = new AdvancedProtectionFeature(FEATURE_ID_DISALLOW_USB); private final Context mContext; private UsbManager mUsbManager; private IUsbManagerInternal mUsbManagerInternal; Loading @@ -107,16 +122,19 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { private NotificationManager mNotificationManager; private NotificationChannel mNotificationChannel; private PendingIntent mHelpPendingIntent; private UsbPortStatus mLastUsbPortStatus; // TODO(b/418846176): Move these to a system property private long mUsbPortPowerBrickConnectionCheckTimeoutMillis; private long mUsbPortPdComplianceCheckTimeoutMillis; private boolean mCanSetUsbDataSignal = false; private boolean mDataRequiredForHighPowerCharge = false; private boolean mReplugRequiredUponEnable = false; private boolean mSilenceDataNotification = false; private boolean mSilencePowerNotification = false; private AdvancedProtectionFeature mFeature = new AdvancedProtectionFeature(FEATURE_ID_DISALLOW_USB); private boolean mBroadcastReceiverIsRegistered = false; private PendingIntent mHelpPendingIntent; private boolean mIsAfterFirstUnlock = false; public UsbDataAdvancedProtectionHook(Context context, boolean enabled) { Loading Loading @@ -155,13 +173,11 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { } Slog.i(TAG, "onAdvancedProtectionChanged: " + enabled); if (enabled) { Slog.i(TAG, "onAdvancedProtectionChanged: enabled"); if (mUsbProtectionBroadcastReceiver == null) { initialize(); } if (!mBroadcastReceiverIsRegistered) { registerReceiver(); setupNotificationIntents(); } setUsbDataSignalIfPossible(false); } else { Loading @@ -181,7 +197,16 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { mReplugRequiredUponEnable = SystemProperties.getBoolean( USB_DATA_PROTECTION_REPLUG_REQUIRED_UPON_ENABLE_SYSTEM_PROPERTY, false); mUsbPortPowerBrickConnectionCheckTimeoutMillis = SystemProperties.getLong( USB_DATA_PROTECTION_POWER_BRICK_CONNECTION_CHECK_TIMEOUT_SYSTEM_PROPERTY, USB_PORT_POWER_BRICK_CONNECTION_CHECK_TIMEOUT_DEFAULT_MILLIS); mUsbPortPdComplianceCheckTimeoutMillis = SystemProperties.getLong( USB_DATA_PROTECTION_PD_COMPLIANCE_CHECK_TIMEOUT_SYSTEM_PROPERTY, USB_PD_COMPLIANCE_CHECK_TIMEOUT_DEFAULT_MILLIS); initializeNotifications(); setupNotificationIntents(); mUsbProtectionBroadcastReceiver = new BroadcastReceiver() { @Override Loading @@ -191,6 +216,7 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { && !mKeyguardManager.isKeyguardLocked()) { mIsAfterFirstUnlock = true; mDelayedDisableHandler.removeCallbacksAndMessages(null); cleanUpNotificationHandlerTasks(); setUsbDataSignalIfPossible(true); } else if (ACTION_SCREEN_OFF.equals(intent.getAction()) Loading @@ -198,11 +224,20 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { setUsbDataSignalIfPossible(false); } else if (ACTION_USB_PORT_CHANGED.equals(intent.getAction())) { UsbPortStatus portStatus = intent.getParcelableExtra( UsbManager.EXTRA_PORT_STATUS, UsbPortStatus.class); // If we cannot retrieve the port status, then we skip this event. if (portStatus == null) { Slog.w( TAG, "UsbPort Changed: USB Data protection failed to" + " retrieve port status"); return; } mLastUsbPortStatus = portStatus; if (Build.IS_DEBUGGABLE) { dumpUsbDevices(portStatus); } Loading @@ -211,62 +246,58 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { updateDelayedDisableTask(portStatus); } if (isUsbConnected(portStatus)) { if (!portStatus.isConnected()) { cleanUpNotificationHandlerTasks(); clearExistingNotification(); /* * Due to limitations of current APIs, we cannot cannot fully * rely on power brick and pd compliance check to be accurate * until it's passed the check timeouts unless the value is * POWER_BRICK_STATUS_CONNECTED or isCompliant=true * respectively. */ } else if (portStatus.getCurrentPowerRole() == POWER_ROLE_SINK) { long pbCheckDuration = portStatus.getPowerBrickConnectionStatus() != POWER_BRICK_STATUS_CONNECTED ? mUsbPortPowerBrickConnectionCheckTimeoutMillis : 0; long pdCheckDuration = !portStatus.isPdCompliant() ? mUsbPortPdComplianceCheckTimeoutMillis : 0; long delayTimeMillis = pbCheckDuration + pdCheckDuration; if (delayTimeMillis <= 0) { cleanUpNotificationHandlerTasks(); determineUsbChargeStateAndSendNotification(portStatus); } else { if (isUsbPortConnectionPowerBrick(portStatus)) { // For cases where high speed chargers do not use USB-PD // PPS, or uses BC1.2 if (mDataRequiredForHighPowerCharge || isUsbChargingComplianceWarningPresent( portStatus)) { sendPowerNotificationIfDeviceLocked(portStatus); updateDelayedNotificationTask(delayTimeMillis); } } else { if (isPortPowerSinking(portStatus) && (mDataRequiredForHighPowerCharge || !portStatus.isPdCompliant() || isUsbChargingComplianceWarningPresent( portStatus))) { sendPowerAndDataNotificationIfDeviceLocked(portStatus); } else { cleanUpNotificationHandlerTasks(); sendDataNotificationIfDeviceLocked(portStatus); } } } } } catch (Exception e) { Slog.e(TAG, "USB Data protection failed with: " + e.getMessage()); } } private boolean isUsbChargingComplianceWarningPresent( UsbPortStatus portStatus) { if (portStatus != null) { for (int warning : portStatus.getComplianceWarnings()) { if (warning == COMPLIANCE_WARNING_BC_1_2 || warning == COMPLIANCE_WARNING_INPUT_POWER_LIMITED) { return true; } } } return false; } private boolean isUsbConnected(UsbPortStatus portStatus) { return portStatus != null && !portStatus.isConnected(); private void updateDelayedNotificationTask(long delayTimeMillis) { if (!mDelayedNotificationHandler.hasMessagesOrCallbacks() && delayTimeMillis > 0) { boolean taskPosted = mDelayedNotificationHandler.postDelayed( () -> { determineUsbChargeStateAndSendNotification( mLastUsbPortStatus); }, delayTimeMillis); if (!taskPosted) { Slog.w(TAG, "Delayed Disable Task: Failed to post task"); } private boolean isUsbPortConnectionPowerBrick(UsbPortStatus portStatus) { return portStatus != null && portStatus.getPowerBrickConnectionStatus() == UsbPortStatus.POWER_BRICK_STATUS_CONNECTED; } private boolean isPortPowerSinking(UsbPortStatus portStatus) { return portStatus != null && portStatus.getCurrentPowerRole() == UsbPortStatus.POWER_ROLE_SINK; } private void updateDelayedDisableTask(UsbPortStatus portStatus) { Loading @@ -274,16 +305,46 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { if (usbPortIsConnectedAndDataEnabled(portStatus)) { mDelayedDisableHandler.removeCallbacksAndMessages(null); } else if (!mDelayedDisableHandler.hasMessagesOrCallbacks()) { boolean taskPosted = mDelayedDisableHandler.postDelayed( () -> { if (mKeyguardManager.isKeyguardLocked()) { setUsbDataSignalIfPossible(false); } }, DELAY_DISABLE_MS); DELAY_DISABLE_MILLIS); if (!taskPosted) { Slog.w(TAG, "Delayed Disable Task: Failed to post task"); } } } private void determineUsbChargeStateAndSendNotification( UsbPortStatus portStatus) { clearExistingNotification(); if (portStatus.getPowerBrickConnectionStatus() == POWER_BRICK_STATUS_CONNECTED) { if (mDataRequiredForHighPowerCharge) { sendPowerNotificationIfDeviceLocked(portStatus); } } else { if (portStatus.isPdCompliant()) { if (mDataRequiredForHighPowerCharge) { sendPowerAndDataNotificationIfDeviceLocked(portStatus); } else { sendDataNotificationIfDeviceLocked(portStatus); } } else { sendPowerAndDataNotificationIfDeviceLocked(portStatus); } } } private void cleanUpNotificationHandlerTasks() { mDelayedNotificationHandler.removeCallbacksAndMessages(null); } private boolean usbPortIsConnectedAndDataEnabled(UsbPortStatus portStatus) { return portStatus != null && portStatus.isConnected() Loading @@ -293,9 +354,6 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { // TODO:(b/401540215) Remove this as part of pre-release cleanup private void dumpUsbDevices(UsbPortStatus portStatus) { Slog.d(TAG, "dumpUsbDevices: " + portStatus.toString()); Slog.d(TAG, "dumpUsbDevices: PD-compliance: " + portStatus.isPdCompliant()); Slog.d(TAG, "dumpUsbDevices: "); Map<String, UsbDevice> portStatusMap = mUsbManager.getDeviceList(); for (UsbDevice device : portStatusMap.values()) { Slog.d(TAG, "Device: " + device.getDeviceName()); Loading Loading @@ -349,6 +407,10 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { silencePendingIntent); } // Intent may fail to initialize in BFU state, so we may need to initialize it lazily. if (mHelpPendingIntent == null) { setupNotificationIntents(); } if (mHelpPendingIntent != null) { notif.setContentIntent(mHelpPendingIntent); } Loading @@ -373,7 +435,8 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { if (mReplugRequiredUponEnable) { notificationTitle = mContext.getString( R.string.usb_apm_usb_plugged_in_when_locked_replug_notification_title); R.string .usb_apm_usb_plugged_in_when_locked_replug_notification_title); notificationBody = mContext.getString( R.string Loading Loading @@ -407,7 +470,8 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { if (mReplugRequiredUponEnable) { notificationTitle = mContext.getString( R.string.usb_apm_usb_plugged_in_when_locked_replug_notification_title); R.string .usb_apm_usb_plugged_in_when_locked_replug_notification_title); notificationBody = mContext.getString( R.string Loading Loading @@ -445,7 +509,8 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { if (mReplugRequiredUponEnable) { notificationTitle = mContext.getString( R.string.usb_apm_usb_plugged_in_when_locked_replug_notification_title); R.string .usb_apm_usb_plugged_in_when_locked_replug_notification_title); notificationBody = mContext.getString( R.string Loading Loading @@ -480,15 +545,15 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { * We check if there is already an existing USB connection and skip the USB * disablement if there is one unless it is in BFU state. */ if (!status && (deviceHaveUsbDataConnection() && mIsAfterFirstUnlock)) { if (!status && deviceHaveUsbDataConnection() && mIsAfterFirstUnlock) { Slog.i(TAG, "USB Data protection toggle skipped due to existing USB connection"); return; } int usbChangeStateReattempts = 0; while (usbChangeStateReattempts < USB_DATA_CHANGE_MAX_RETRY_ATTEMPTS) { try { if (mUsbManagerInternal.enableUsbDataSignal( status, USB_DISABLE_REASON_APM)) { if (mUsbManagerInternal.enableUsbDataSignal(status, USB_DISABLE_REASON_APM)) { break; } else { Slog.e(TAG, "USB Data protection toggle attempt failed"); Loading Loading @@ -528,9 +593,10 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { } private boolean usbPortIsConnectedWithDataEnabled(UsbPort usbPort) { return usbPort.getStatus() != null && usbPort.getStatus().isConnected() && usbPort.getStatus().getCurrentDataRole() != DATA_ROLE_NONE; UsbPortStatus usbPortStatus = usbPort.getStatus(); return usbPortStatus != null && usbPortStatus.isConnected() && usbPortStatus.getCurrentDataRole() != DATA_ROLE_NONE; } private void registerReceiver() { Loading Loading @@ -559,6 +625,7 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { mBroadcastReceiverIsRegistered = false; } // TODO:(b/428090717) Fix intent resolution during boot time private void setupNotificationIntents() { try { String helpIntentActivityUri = Loading @@ -573,16 +640,12 @@ public class UsbDataAdvancedProtectionHook extends AdvancedProtectionHook { ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(helpIntent, 0); if (resolveInfo != null && resolveInfo.activityInfo != null) { mHelpPendingIntent = PendingIntent.getActivityAsUser( mContext, 0, helpIntent, PendingIntent.FLAG_IMMUTABLE, null, UserHandle.ALL); PendingIntent.getActivity( mContext, 0, helpIntent, PendingIntent.FLAG_IMMUTABLE, null); } else { Slog.w(TAG, "Failed to resolve help intent " + resolveInfo); } Slog.d(TAG, "setupNotificationIntents setup successfully: " + mHelpPendingIntent); } catch (Exception e) { Slog.e(TAG, "Failed to setup notification intents", e); } Loading