From c62f918e0eabd5c036ba43172d36f587157feed6 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Wed, 19 Feb 2014 11:18:02 -0800 Subject: UsbDeviceManager: Fix race condition entering USB accessory mode When switching USB modes there are often spurious connect and disconnect events that occur before reenumeration is complete. There is currently a 1000ms timer to "debounce" the disconnect events. But with some USB accessories, this timeout is not long enough, which results in an endless cycle of attempts to enter USB accessory mode when the phone is connected. To fix this, we now wait up to 10 seconds for the host to successfully configure the device when entering USB accessory mode before giving up. This is separate from the existing debounce timer, so the behavior of the USB state change broadcasts are not affected. Bug: 12877769 Change-Id: I7aa61f8a618546d749a7ddfc97bf103029a73d03 --- .../com/android/server/usb/UsbDeviceManager.java | 32 ++++++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java index 5a60de0f269b..8a5e2914f562 100644 --- a/services/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/java/com/android/server/usb/UsbDeviceManager.java @@ -98,6 +98,13 @@ public class UsbDeviceManager { // which need debouncing. private static final int UPDATE_DELAY = 1000; + // Time we received a request to enter USB accessory mode + private long mAccessoryModeRequestTime = 0; + + // Timeout for entering USB request mode. + // Request is cancelled if host does not configure device within 10 seconds. + private static final int ACCESSORY_REQUEST_TIMEOUT = 10 * 1000; + private static final String BOOT_MODE_PROPERTY = "ro.bootmode"; private UsbHandler mHandler; @@ -205,6 +212,8 @@ public class UsbDeviceManager { } private void startAccessoryMode() { + if (!mHasUsbAccessory) return; + mAccessoryStrings = nativeGetAccessoryStrings(); boolean enableAudio = (nativeGetAudioMode() == AUDIO_MODE_SOURCE); // don't start accessory mode if our mandatory strings have not been set @@ -223,6 +232,7 @@ public class UsbDeviceManager { } if (functions != null) { + mAccessoryModeRequestTime = SystemClock.elapsedRealtime(); setCurrentFunctions(functions, false); } } @@ -456,6 +466,8 @@ public class UsbDeviceManager { } private void setEnabledFunctions(String functions, boolean makeDefault) { + if (DEBUG) Slog.d(TAG, "setEnabledFunctions " + functions + + " makeDefault: " + makeDefault); // Do not update persystent.sys.usb.config if the device is booted up // with OEM specific mode. @@ -517,9 +529,17 @@ public class UsbDeviceManager { } private void updateCurrentAccessory() { - if (!mHasUsbAccessory) return; + // We are entering accessory mode if we have received a request from the host + // and the request has not timed out yet. + boolean enteringAccessoryMode = + mAccessoryModeRequestTime > 0 && + SystemClock.elapsedRealtime() < + mAccessoryModeRequestTime + ACCESSORY_REQUEST_TIMEOUT; + + if (mConfigured && enteringAccessoryMode) { + // successfully entered accessory mode + mAccessoryModeRequestTime = 0; - if (mConfigured) { if (mAccessoryStrings != null) { mCurrentAccessory = new UsbAccessory(mAccessoryStrings); Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory); @@ -530,7 +550,7 @@ public class UsbDeviceManager { } else { Slog.e(TAG, "nativeGetAccessoryStrings failed"); } - } else if (!mConnected) { + } else if (!enteringAccessoryMode) { // make sure accessory mode is off // and restore default functions Slog.d(TAG, "exited USB accessory mode"); @@ -560,6 +580,8 @@ public class UsbDeviceManager { } } + if (DEBUG) Slog.d(TAG, "broadcasting " + intent + " connected: " + mConnected + + " configured: " + mConfigured); mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } @@ -599,9 +621,7 @@ public class UsbDeviceManager { if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ACCESSORY)) { updateCurrentAccessory(); - } - - if (!mConnected) { + } else if (!mConnected) { // restore defaults when USB is disconnected setEnabledFunctions(mDefaultFunctions, false); } -- cgit v1.2.3-59-g8ed1b