diff options
author | Jerry Zhang <zhangjerry@google.com> | 2018-01-09 17:53:04 -0800 |
---|---|---|
committer | Jerry Zhang <zhangjerry@google.com> | 2018-01-31 11:40:48 -0800 |
commit | 327b809ad11a5094248652014227470c4be329e6 (patch) | |
tree | 9779e98e6ab294d0455b67d7a764a892007cce6a | |
parent | 1810393c5a5fa0d9f8579e0eeabd7b334482163c (diff) |
Refactor and clean up USB, add tests
Change UsbManager apis to use long instead of string, to match
usb hal. Change UsbDeviceManager internals to match as well.
Remove isFunctionEnabled and add getEnabledFunctions. Callers
would often call isFunctionEnabled for every possible function
to get the list of functions, so getEnabledFunctions reduces the
number of aidl calls.
Separate out dependencies between UsbHandler and UsbDeviceManager
and staticize the UsbHandler classes. Add unit tests with
mocked out dependencies to test state transitions for UsbHandler.
Bug: 62876645
Test: atest UsbTests
Change-Id: I785c4c24121a70e725de9742c6af50a6bf1baea0
-rw-r--r-- | Android.bp | 1 | ||||
-rw-r--r-- | cmds/svc/src/com/android/commands/svc/UsbCommand.java | 43 | ||||
-rw-r--r-- | core/java/android/hardware/usb/IUsbManager.aidl | 18 | ||||
-rw-r--r-- | core/java/android/hardware/usb/UsbManager.java | 260 | ||||
-rw-r--r-- | services/core/java/com/android/server/connectivity/Tethering.java | 3 | ||||
-rw-r--r-- | services/usb/java/com/android/server/usb/UsbDeviceManager.java | 786 | ||||
-rw-r--r-- | services/usb/java/com/android/server/usb/UsbService.java | 65 | ||||
-rw-r--r-- | tests/UsbTests/Android.mk | 44 | ||||
-rw-r--r-- | tests/UsbTests/AndroidManifest.xml | 30 | ||||
-rw-r--r-- | tests/UsbTests/AndroidTest.xml | 29 | ||||
-rw-r--r-- | tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java | 316 | ||||
-rw-r--r-- | tests/net/java/com/android/server/connectivity/TetheringTest.java | 2 |
12 files changed, 1065 insertions, 532 deletions
diff --git a/Android.bp b/Android.bp index 129d6769cb98..d5e04f9f4e2d 100644 --- a/Android.bp +++ b/Android.bp @@ -676,6 +676,7 @@ java_library { "android.hardware.vibrator-V1.1-java-constants", "android.hardware.wifi-V1.0-java-constants", "android.hardware.radio-V1.0-java", + "android.hardware.usb.gadget-V1.0-java", ], // Loaded with System.loadLibrary by android.view.textclassifier diff --git a/cmds/svc/src/com/android/commands/svc/UsbCommand.java b/cmds/svc/src/com/android/commands/svc/UsbCommand.java index 34f6d7de0cc9..3893be49e739 100644 --- a/cmds/svc/src/com/android/commands/svc/UsbCommand.java +++ b/cmds/svc/src/com/android/commands/svc/UsbCommand.java @@ -21,7 +21,6 @@ import android.hardware.usb.IUsbManager; import android.hardware.usb.UsbManager; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.SystemProperties; public class UsbCommand extends Svc.Command { public UsbCommand() { @@ -37,41 +36,41 @@ public class UsbCommand extends Svc.Command { public String longHelp() { return shortHelp() + "\n" + "\n" - + "usage: svc usb setFunction [function] [usbDataUnlocked=false]\n" - + " Set the current usb function and optionally the data lock state.\n\n" + + "usage: svc usb setFunctions [function]\n" + + " Set the current usb function. If function is blank, sets to charging.\n" + " svc usb setScreenUnlockedFunctions [function]\n" - + " Sets the functions which, if the device was charging," - + " become current on screen unlock.\n" - + " svc usb getFunction\n" - + " Gets the list of currently enabled functions\n"; + + " Sets the functions which, if the device was charging, become current on" + + "screen unlock. If function is blank, turn off this feature.\n" + + " svc usb getFunctions\n" + + " Gets the list of currently enabled functions\n\n" + + "possible values of [function] are any of 'mtp', 'ptp', 'rndis', 'midi'\n"; } @Override public void run(String[] args) { - boolean validCommand = false; if (args.length >= 2) { - if ("setFunction".equals(args[1])) { - IUsbManager usbMgr = IUsbManager.Stub.asInterface(ServiceManager.getService( - Context.USB_SERVICE)); - boolean unlockData = false; - if (args.length >= 4) { - unlockData = Boolean.valueOf(args[3]); - } + IUsbManager usbMgr = IUsbManager.Stub.asInterface(ServiceManager.getService( + Context.USB_SERVICE)); + if ("setFunctions".equals(args[1])) { try { - usbMgr.setCurrentFunction((args.length >=3 ? args[2] : null), unlockData); + usbMgr.setCurrentFunctions(UsbManager.usbFunctionsFromString( + args.length >= 3 ? args[2] : "")); } catch (RemoteException e) { System.err.println("Error communicating with UsbManager: " + e); } return; - } else if ("getFunction".equals(args[1])) { - System.err.println(SystemProperties.get("sys.usb.config")); + } else if ("getFunctions".equals(args[1])) { + try { + System.err.println( + UsbManager.usbFunctionsToString(usbMgr.getCurrentFunctions())); + } catch (RemoteException e) { + System.err.println("Error communicating with UsbManager: " + e); + } return; } else if ("setScreenUnlockedFunctions".equals(args[1])) { - IUsbManager usbMgr = IUsbManager.Stub.asInterface(ServiceManager.getService( - Context.USB_SERVICE)); try { - usbMgr.setScreenUnlockedFunctions((args.length >= 3 ? args[2] : - UsbManager.USB_FUNCTION_NONE)); + usbMgr.setScreenUnlockedFunctions(UsbManager.usbFunctionsFromString( + args.length >= 3 ? args[2] : "")); } catch (RemoteException e) { System.err.println("Error communicating with UsbManager: " + e); } diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl index 398dda174ba1..91bbdc7dde80 100644 --- a/core/java/android/hardware/usb/IUsbManager.aidl +++ b/core/java/android/hardware/usb/IUsbManager.aidl @@ -88,18 +88,22 @@ interface IUsbManager /* Returns true if the specified USB function is enabled. */ boolean isFunctionEnabled(String function); - /* Sets the current USB function as well as whether USB data - * (for example, MTP exposed pictures) should be made available - * on the USB connection. Unlocking data should only be done with - * user involvement, since exposing pictures or other data could - * leak sensitive user information. - */ + /* Sets the current USB function. */ + void setCurrentFunctions(long functions); + + /* Compatibility version of setCurrentFunctions(long). */ void setCurrentFunction(String function, boolean usbDataUnlocked); + /* Gets the current USB functions. */ + long getCurrentFunctions(); + /* Sets the screen unlocked USB function(s), which will be set automatically * when the screen is unlocked. */ - void setScreenUnlockedFunctions(String function); + void setScreenUnlockedFunctions(long functions); + + /* Gets the current screen unlocked functions. */ + long getScreenUnlockedFunctions(); /* Allow USB debugging from the attached host. If alwaysAllow is true, add the * the public key to list of host keys that the user has approved. diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java index 7617c2bd196f..8daecac5a109 100644 --- a/core/java/android/hardware/usb/UsbManager.java +++ b/core/java/android/hardware/usb/UsbManager.java @@ -28,6 +28,7 @@ import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager.NameNotFoundException; +import android.hardware.usb.gadget.V1_0.GadgetFunction; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.Process; @@ -37,6 +38,8 @@ import android.util.Log; import com.android.internal.util.Preconditions; import java.util.HashMap; +import java.util.Map; +import java.util.StringJoiner; /** * This class allows you to access the state of USB and communicate with USB devices. @@ -70,7 +73,7 @@ public class UsbManager { * MTP function is enabled * <li> {@link #USB_FUNCTION_PTP} boolean extra indicating whether the * PTP function is enabled - * <li> {@link #USB_FUNCTION_PTP} boolean extra indicating whether the + * <li> {@link #USB_FUNCTION_ACCESSORY} boolean extra indicating whether the * accessory function is enabled * <li> {@link #USB_FUNCTION_AUDIO_SOURCE} boolean extra indicating whether the * audio source function is enabled @@ -196,8 +199,7 @@ public class UsbManager { /** * A placeholder indicating that no USB function is being specified. - * Used to distinguish between selecting no function vs. the default function in - * {@link #setCurrentFunction(String)}. + * Used for compatibility with old init scripts to indicate no functions vs. charging function. * * {@hide} */ @@ -298,6 +300,69 @@ public class UsbManager { */ public static final String EXTRA_PERMISSION_GRANTED = "permission"; + /** + * Code for the charging usb function. Passed into {@link #setCurrentFunctions(long)} + * {@hide} + */ + public static final long FUNCTION_NONE = 0; + + /** + * Code for the mtp usb function. Passed as a mask into {@link #setCurrentFunctions(long)} + * {@hide} + */ + public static final long FUNCTION_MTP = GadgetFunction.MTP; + + /** + * Code for the ptp usb function. Passed as a mask into {@link #setCurrentFunctions(long)} + * {@hide} + */ + public static final long FUNCTION_PTP = GadgetFunction.PTP; + + /** + * Code for the rndis usb function. Passed as a mask into {@link #setCurrentFunctions(long)} + * {@hide} + */ + public static final long FUNCTION_RNDIS = GadgetFunction.RNDIS; + + /** + * Code for the midi usb function. Passed as a mask into {@link #setCurrentFunctions(long)} + * {@hide} + */ + public static final long FUNCTION_MIDI = GadgetFunction.MIDI; + + /** + * Code for the accessory usb function. + * {@hide} + */ + public static final long FUNCTION_ACCESSORY = GadgetFunction.ACCESSORY; + + /** + * Code for the audio source usb function. + * {@hide} + */ + public static final long FUNCTION_AUDIO_SOURCE = GadgetFunction.AUDIO_SOURCE; + + /** + * Code for the adb usb function. + * {@hide} + */ + public static final long FUNCTION_ADB = GadgetFunction.ADB; + + private static final long SETTABLE_FUNCTIONS = FUNCTION_MTP | FUNCTION_PTP | FUNCTION_RNDIS + | FUNCTION_MIDI; + + private static final Map<String, Long> FUNCTION_NAME_TO_CODE = new HashMap<>(); + + static { + FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_MTP, FUNCTION_MTP); + FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_PTP, FUNCTION_PTP); + FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_RNDIS, FUNCTION_RNDIS); + FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_MIDI, FUNCTION_MIDI); + FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_ACCESSORY, FUNCTION_ACCESSORY); + FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_AUDIO_SOURCE, FUNCTION_AUDIO_SOURCE); + FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_ADB, FUNCTION_ADB); + } + private final Context mContext; private final IUsbManager mService; @@ -548,15 +613,14 @@ public class UsbManager { * services offered by the device. * </p> * + * @deprecated use getCurrentFunctions() instead. * @param function name of the USB function * @return true if the USB function is enabled * * {@hide} */ + @Deprecated public boolean isFunctionEnabled(String function) { - if (mService == null) { - return false; - } try { return mService.isFunctionEnabled(function); } catch (RemoteException e) { @@ -565,7 +629,7 @@ public class UsbManager { } /** - * Sets the current USB function when in device mode. + * Sets the current USB functions when in device mode. * <p> * USB functions represent interfaces which are published to the host to access * services offered by the device. @@ -574,27 +638,59 @@ public class UsbManager { * automatically activate additional functions such as {@link #USB_FUNCTION_ADB} * or {@link #USB_FUNCTION_ACCESSORY} based on other settings and states. * </p><p> - * The allowed values are: {@link #USB_FUNCTION_NONE}, {@link #USB_FUNCTION_AUDIO_SOURCE}, - * {@link #USB_FUNCTION_MIDI}, {@link #USB_FUNCTION_MTP}, {@link #USB_FUNCTION_PTP}, - * or {@link #USB_FUNCTION_RNDIS}. - * </p><p> - * Also sets whether USB data (for example, MTP exposed pictures) should be made available - * on the USB connection when in device mode. Unlocking usb data should only be done with - * user involvement, since exposing pictures or other data could leak sensitive - * user information. + * An argument of 0 indicates that the device is charging, and can pick any + * appropriate function for that purpose. * </p><p> * Note: This function is asynchronous and may fail silently without applying * the requested changes. * </p> * - * @param function name of the USB function, or null to restore the default function - * @param usbDataUnlocked whether user data is accessible + * @param functions the USB function(s) to set, as a bitwise mask. + * Must satisfy {@link UsbManager#areSettableFunctions} + * + * {@hide} + */ + public void setCurrentFunctions(long functions) { + try { + mService.setCurrentFunctions(functions); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Sets the current USB functions when in device mode. + * + * @deprecated use setCurrentFunctions(long) instead. + * @param functions the USB function(s) to set. + * @param usbDataUnlocked unused + + * {@hide} + */ + @Deprecated + public void setCurrentFunction(String functions, boolean usbDataUnlocked) { + try { + mService.setCurrentFunction(functions, usbDataUnlocked); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns the current USB functions in device mode. + * <p> + * This function returns the state of primary USB functions and can return a + * mask containing any usb function(s) except for ADB. + * </p> + * + * @return The currently enabled functions, in a bitwise mask. + * A zero mask indicates that the current function is the charging function. * * {@hide} */ - public void setCurrentFunction(String function, boolean usbDataUnlocked) { + public long getCurrentFunctions() { try { - mService.setCurrentFunction(function, usbDataUnlocked); + return mService.getCurrentFunctions(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -604,23 +700,37 @@ public class UsbManager { * Sets the screen unlocked functions, which are persisted and set as the current functions * whenever the screen is unlocked. * <p> - * The allowed values are: {@link #USB_FUNCTION_NONE}, - * {@link #USB_FUNCTION_MIDI}, {@link #USB_FUNCTION_MTP}, {@link #USB_FUNCTION_PTP}, - * or {@link #USB_FUNCTION_RNDIS}. - * {@link #USB_FUNCTION_NONE} has the effect of switching off this feature, so functions + * A zero mask has the effect of switching off this feature, so functions * no longer change on screen unlock. * </p><p> * Note: When the screen is on, this method will apply given functions as current functions, * which is asynchronous and may fail silently without applying the requested changes. * </p> * - * @param function function to set as default + * @param functions functions to set, in a bitwise mask. + * Must satisfy {@link UsbManager#areSettableFunctions} * * {@hide} */ - public void setScreenUnlockedFunctions(String function) { + public void setScreenUnlockedFunctions(long functions) { try { - mService.setScreenUnlockedFunctions(function); + mService.setScreenUnlockedFunctions(functions); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Gets the current screen unlocked functions. + * + * @return The currently set screen enabled functions. + * A zero mask indicates that the screen unlocked functions feature is not enabled. + * + * {@hide} + */ + public long getScreenUnlockedFunctions() { + try { + return mService.getScreenUnlockedFunctions(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -719,51 +829,71 @@ public class UsbManager { } } - /** @hide */ - public static String addFunction(String functions, String function) { - if (USB_FUNCTION_NONE.equals(functions)) { - return function; - } - if (!containsFunction(functions, function)) { - if (functions.length() > 0) { - functions += ","; - } - functions += function; - } - return functions; + /** + * Returns whether the given functions are valid inputs to UsbManager. + * Currently the empty functions or any of MTP, PTP, RNDIS, MIDI are accepted. + * + * @return Whether the mask is settable. + * + * {@hide} + */ + public static boolean areSettableFunctions(long functions) { + return functions == FUNCTION_NONE + || ((~SETTABLE_FUNCTIONS & functions) == 0 && Long.bitCount(functions) == 1); } - /** @hide */ - public static String removeFunction(String functions, String function) { - String[] split = functions.split(","); - for (int i = 0; i < split.length; i++) { - if (function.equals(split[i])) { - split[i] = null; - } + /** + * Converts the given function mask to string. Maintains ordering with respect to init scripts. + * + * @return String representation of given mask + * + * {@hide} + */ + public static String usbFunctionsToString(long functions) { + StringJoiner joiner = new StringJoiner(","); + if ((functions & FUNCTION_MTP) != 0) { + joiner.add(UsbManager.USB_FUNCTION_MTP); } - if (split.length == 1 && split[0] == null) { - return USB_FUNCTION_NONE; + if ((functions & FUNCTION_PTP) != 0) { + joiner.add(UsbManager.USB_FUNCTION_PTP); } - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < split.length; i++) { - String s = split[i]; - if (s != null) { - if (builder.length() > 0) { - builder.append(","); - } - builder.append(s); - } + if ((functions & FUNCTION_RNDIS) != 0) { + joiner.add(UsbManager.USB_FUNCTION_RNDIS); + } + if ((functions & FUNCTION_MIDI) != 0) { + joiner.add(UsbManager.USB_FUNCTION_MIDI); + } + if ((functions & FUNCTION_ACCESSORY) != 0) { + joiner.add(UsbManager.USB_FUNCTION_ACCESSORY); + } + if ((functions & FUNCTION_AUDIO_SOURCE) != 0) { + joiner.add(UsbManager.USB_FUNCTION_AUDIO_SOURCE); } - return builder.toString(); + if ((functions & FUNCTION_ADB) != 0) { + joiner.add(UsbManager.USB_FUNCTION_ADB); + } + return joiner.toString(); } - /** @hide */ - public static boolean containsFunction(String functions, String function) { - int index = functions.indexOf(function); - if (index < 0) return false; - if (index > 0 && functions.charAt(index - 1) != ',') return false; - int charAfter = index + function.length(); - if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false; - return true; + /** + * Parses a string of usb functions that are comma separated. + * + * @return A mask of all valid functions in the string + * + * {@hide} + */ + public static long usbFunctionsFromString(String functions) { + if (functions == null || functions.equals(USB_FUNCTION_NONE)) { + return FUNCTION_NONE; + } + long ret = 0; + for (String function : functions.split(",")) { + if (FUNCTION_NAME_TO_CODE.containsKey(function)) { + ret |= FUNCTION_NAME_TO_CODE.get(function); + } else if (function.length() > 0) { + throw new IllegalArgumentException("Invalid usb function " + functions); + } + } + return ret; } } diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index be6c4a12d114..9a9cdbde3987 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -1095,7 +1095,8 @@ public class Tethering extends BaseNetworkObserver { if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")"); UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE); synchronized (mPublicSync) { - usbManager.setCurrentFunction(enable ? UsbManager.USB_FUNCTION_RNDIS : null, false); + usbManager.setCurrentFunctions(enable ? UsbManager.FUNCTION_RNDIS + : UsbManager.FUNCTION_NONE); } return ConnectivityManager.TETHER_ERROR_NO_ERROR; } diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index e3e5e3e1b10b..1ea2f976b80c 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -41,7 +41,6 @@ import android.hardware.usb.UsbInterface; import android.hardware.usb.UsbManager; import android.hardware.usb.UsbPort; import android.hardware.usb.UsbPortStatus; -import android.hardware.usb.gadget.V1_0.GadgetFunction; import android.hardware.usb.gadget.V1_0.IUsbGadget; import android.hardware.usb.gadget.V1_0.IUsbGadgetCallback; import android.hardware.usb.gadget.V1_0.Status; @@ -68,6 +67,8 @@ import android.util.Pair; import android.util.Slog; import com.android.internal.annotations.GuardedBy; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.os.SomeArgs; @@ -86,21 +87,20 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Scanner; import java.util.Set; -import java.util.StringJoiner; /** * UsbDeviceManager manages USB state in device mode. */ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver { - private static final String TAG = "UsbDeviceManager"; + private static final String TAG = UsbDeviceManager.class.getSimpleName(); private static final boolean DEBUG = false; /** * The SharedPreference setting per user that stores the screen unlocked functions between * sessions. */ - private static final String UNLOCKED_CONFIG_PREF = "usb-screen-unlocked-config-%d"; + static final String UNLOCKED_CONFIG_PREF = "usb-screen-unlocked-config-%d"; /** * ro.bootmode value when phone boots into usual Android. @@ -156,8 +156,6 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver private static final String ADB_NOTIFICATION_CHANNEL_ID_TV = "usbdevicemanager.adb.tv"; private UsbHandler mHandler; - private boolean mBootCompleted; - private boolean mSystemReady; private final Object mLock = new Object(); @@ -165,22 +163,13 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver private final ContentResolver mContentResolver; @GuardedBy("mLock") private UsbProfileGroupSettingsManager mCurrentSettings; - private NotificationManager mNotificationManager; private final boolean mHasUsbAccessory; - private boolean mUseUsbNotification; - private boolean mAdbEnabled; - private boolean mAudioSourceEnabled; - private boolean mMidiEnabled; - private int mMidiCard; - private int mMidiDevice; + @GuardedBy("mLock") private String[] mAccessoryStrings; private UsbDebuggingManager mDebuggingManager; - private final UsbAlsaManager mUsbAlsaManager; - private final UsbSettingsManager mSettingsManager; - private Intent mBroadcastedIntent; - private boolean mPendingBootBroadcast; + private final UEventObserver mUEventObserver; + private static Set<Integer> sBlackListedInterfaces; - private SharedPreferences mSettings; static { sBlackListedInterfaces = new HashSet<>(); @@ -213,7 +202,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver /* * Listens for uevent messages from the kernel to monitor the USB state */ - private final UEventObserver mUEventObserver = new UEventObserver() { + private final class UsbUEventObserver extends UEventObserver { @Override public void onUEvent(UEventObserver.UEvent event) { if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString()); @@ -227,7 +216,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver startAccessoryMode(); } } - }; + } @Override public void onKeyguardStateChanged(boolean isShowing) { @@ -257,8 +246,6 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver public UsbDeviceManager(Context context, UsbAlsaManager alsaManager, UsbSettingsManager settingsManager) { mContext = context; - mUsbAlsaManager = alsaManager; - mSettingsManager = settingsManager; mContentResolver = context.getContentResolver(); PackageManager pm = mContext.getPackageManager(); mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY); @@ -274,16 +261,24 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver Slog.i(TAG, "USB GADGET HAL not present in the device", e); } + boolean secureAdbEnabled = SystemProperties.getBoolean("ro.adb.secure", false); + boolean dataEncrypted = "1".equals(SystemProperties.get("vold.decrypt")); + if (secureAdbEnabled && !dataEncrypted) { + mDebuggingManager = new UsbDebuggingManager(context); + } + if (halNotPresent) { /** * Initialze the legacy UsbHandler */ - mHandler = new UsbHandlerLegacy(FgThread.get().getLooper(), mContext); + mHandler = new UsbHandlerLegacy(FgThread.get().getLooper(), mContext, this, + mDebuggingManager, alsaManager, settingsManager); } else { /** * Initialize HAL based UsbHandler */ - mHandler = new UsbHandlerHal(FgThread.get().getLooper()); + mHandler = new UsbHandlerHal(FgThread.get().getLooper(), mContext, this, + mDebuggingManager, alsaManager, settingsManager); } if (nativeIsStartRequested()) { @@ -291,12 +286,6 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver startAccessoryMode(); } - boolean secureAdbEnabled = SystemProperties.getBoolean("ro.adb.secure", false); - boolean dataEncrypted = "1".equals(SystemProperties.get("vold.decrypt")); - if (secureAdbEnabled && !dataEncrypted) { - mDebuggingManager = new UsbDebuggingManager(context); - } - BroadcastReceiver portReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -347,41 +336,35 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver mContext.registerReceiver(languageChangedReceiver, new IntentFilter(Intent.ACTION_LOCALE_CHANGED)); + + // Watch for USB configuration changes + mUEventObserver = new UsbUEventObserver(); + mUEventObserver.startObserving(USB_STATE_MATCH); + mUEventObserver.startObserving(ACCESSORY_START_MATCH); + + // register observer to listen for settings changes + mContentResolver.registerContentObserver( + Settings.Global.getUriFor(Settings.Global.ADB_ENABLED), + false, new AdbSettingsObserver()); } - private UsbProfileGroupSettingsManager getCurrentSettings() { + UsbProfileGroupSettingsManager getCurrentSettings() { synchronized (mLock) { return mCurrentSettings; } } + String[] getAccessoryStrings() { + synchronized (mLock) { + return mAccessoryStrings; + } + } + public void systemReady() { if (DEBUG) Slog.d(TAG, "systemReady"); LocalServices.getService(ActivityManagerInternal.class).registerScreenObserver(this); - mNotificationManager = (NotificationManager) - mContext.getSystemService(Context.NOTIFICATION_SERVICE); - - // Ensure that the notification channels are set up - if (isTv()) { - // TV-specific notification channel - mNotificationManager.createNotificationChannel( - new NotificationChannel(ADB_NOTIFICATION_CHANNEL_ID_TV, - mContext.getString( - com.android.internal.R.string - .adb_debugging_notification_channel_tv), - NotificationManager.IMPORTANCE_HIGH)); - } - - // We do not show the USB notification if the primary volume supports mass storage. - // The legacy mass storage UI will be used instead. - boolean massStorageSupported; - final StorageManager storageManager = StorageManager.from(mContext); - final StorageVolume primary = storageManager.getPrimaryVolume(); - massStorageSupported = primary != null && primary.allowMassStorage(); - mUseUsbNotification = !massStorageSupported && mContext.getResources().getBoolean( - com.android.internal.R.bool.config_usbChargingMessage); mHandler.sendEmptyMessage(MSG_SYSTEM_READY); } @@ -410,21 +393,19 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver boolean enableAccessory = (mAccessoryStrings != null && mAccessoryStrings[UsbAccessory.MANUFACTURER_STRING] != null && mAccessoryStrings[UsbAccessory.MODEL_STRING] != null); - String functions = null; - if (enableAccessory && enableAudio) { - functions = UsbManager.USB_FUNCTION_ACCESSORY + "," - + UsbManager.USB_FUNCTION_AUDIO_SOURCE; - } else if (enableAccessory) { - functions = UsbManager.USB_FUNCTION_ACCESSORY; - } else if (enableAudio) { - functions = UsbManager.USB_FUNCTION_AUDIO_SOURCE; + long functions = UsbManager.FUNCTION_NONE; + if (enableAccessory) { + functions |= UsbManager.FUNCTION_ACCESSORY; + } + if (enableAudio) { + functions |= UsbManager.FUNCTION_AUDIO_SOURCE; } - if (functions != null) { + if (functions != UsbManager.FUNCTION_NONE) { mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_ACCESSORY_MODE_ENTER_TIMEOUT), ACCESSORY_REQUEST_TIMEOUT); - setCurrentFunctions(functions, false); + setCurrentFunctions(functions); } } @@ -451,19 +432,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver } } - private boolean isTv() { - return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK); - } - - private SharedPreferences getPinnedSharedPrefs(Context context) { - final File prefsFile = new File(new File( - Environment.getDataUserCePackageDirectory(StorageManager.UUID_PRIVATE_INTERNAL, - context.getUserId(), context.getPackageName()), "shared_prefs"), - UsbDeviceManager.class.getSimpleName() + ".xml"); - return context.getSharedPreferences(prefsFile, Context.MODE_PRIVATE); - } - - private abstract class UsbHandler extends Handler { + abstract static class UsbHandler extends Handler { // current USB state private boolean mConnected; @@ -471,21 +440,40 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver private boolean mSourcePower; private boolean mSinkPower; private boolean mConfigured; - protected boolean mUsbDataUnlocked; private boolean mAudioAccessoryConnected; private boolean mAudioAccessorySupported; - protected String mCurrentFunctions; - protected boolean mCurrentFunctionsApplied; + private UsbAccessory mCurrentAccessory; private int mUsbNotificationId; private boolean mAdbNotificationShown; - private int mCurrentUser; private boolean mUsbCharging; private boolean mHideUsbNotification; private boolean mSupportsAllCombinations; - private String mScreenUnlockedFunctions = UsbManager.USB_FUNCTION_NONE; private boolean mScreenLocked; - protected boolean mCurrentUsbFunctionsRequested; + private boolean mSystemReady; + private Intent mBroadcastedIntent; + private boolean mPendingBootBroadcast; + private boolean mAudioSourceEnabled; + private boolean mMidiEnabled; + private int mMidiCard; + private int mMidiDevice; + + private final Context mContext; + private final UsbDebuggingManager mDebuggingManager; + private final UsbAlsaManager mUsbAlsaManager; + private final UsbSettingsManager mSettingsManager; + private NotificationManager mNotificationManager; + + protected long mScreenUnlockedFunctions; + protected boolean mAdbEnabled; + protected boolean mBootCompleted; + protected boolean mCurrentFunctionsApplied; + protected boolean mUseUsbNotification; + protected long mCurrentFunctions; + protected final UsbDeviceManager mUsbDeviceManager; + protected final ContentResolver mContentResolver; + protected SharedPreferences mSettings; + protected int mCurrentUser; protected boolean mCurrentUsbFunctionsReceived; /** @@ -494,31 +482,36 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver */ protected static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config"; - public UsbHandler(Looper looper) { + UsbHandler(Looper looper, Context context, UsbDeviceManager deviceManager, + UsbDebuggingManager debuggingManager, UsbAlsaManager alsaManager, + UsbSettingsManager settingsManager) { super(looper); + mContext = context; + mDebuggingManager = debuggingManager; + mUsbDeviceManager = deviceManager; + mUsbAlsaManager = alsaManager; + mSettingsManager = settingsManager; + mContentResolver = context.getContentResolver(); mCurrentUser = ActivityManager.getCurrentUser(); + mScreenUnlockedFunctions = UsbManager.FUNCTION_NONE; mScreenLocked = true; /* * Use the normal bootmode persistent prop to maintain state of adb across * all boot modes. */ - mAdbEnabled = UsbManager.containsFunction( - SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY), - UsbManager.USB_FUNCTION_ADB); + mAdbEnabled = (UsbManager.usbFunctionsFromString(getSystemProperty( + USB_PERSISTENT_CONFIG_PROPERTY, "")) & UsbManager.FUNCTION_ADB) != 0; - /* - * Previous versions can set persist config to mtp/ptp but it does not - * get reset on OTA. Reset the property here instead. - */ - String persisted = SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY); - if (UsbManager.containsFunction(persisted, UsbManager.USB_FUNCTION_MTP) - || UsbManager.containsFunction(persisted, UsbManager.USB_FUNCTION_PTP)) { - SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY, - UsbManager.removeFunction(UsbManager.removeFunction(persisted, - UsbManager.USB_FUNCTION_MTP), UsbManager.USB_FUNCTION_PTP)); - } + // We do not show the USB notification if the primary volume supports mass storage. + // The legacy mass storage UI will be used instead. + final StorageManager storageManager = StorageManager.from(mContext); + final StorageVolume primary = storageManager.getPrimaryVolume(); + + boolean massStorageSupported = primary != null && primary.allowMassStorage(); + mUseUsbNotification = !massStorageSupported && mContext.getResources().getBoolean( + com.android.internal.R.bool.config_usbChargingMessage); } public void sendMessage(int what, boolean arg) { @@ -602,20 +595,14 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable); if (enable != mAdbEnabled) { mAdbEnabled = enable; - String oldFunctions = mCurrentFunctions; - - // Persist the adb setting - String newFunction = applyAdbFunction(SystemProperties.get( - USB_PERSISTENT_CONFIG_PROPERTY, UsbManager.USB_FUNCTION_NONE)); - SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY, newFunction); - // Remove mtp from the config if file transfer is not enabled - if (oldFunctions.equals(UsbManager.USB_FUNCTION_MTP) && - !mUsbDataUnlocked && enable) { - oldFunctions = UsbManager.USB_FUNCTION_NONE; + if (enable) { + setSystemProperty(USB_PERSISTENT_CONFIG_PROPERTY, UsbManager.USB_FUNCTION_ADB); + } else { + setSystemProperty(USB_PERSISTENT_CONFIG_PROPERTY, ""); } - setEnabledFunctions(oldFunctions, true, mUsbDataUnlocked); + setEnabledFunctions(mCurrentFunctions, true); updateAdbNotification(false); } @@ -624,21 +611,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver } } - protected String applyAdbFunction(String functions) { - // Do not pass null pointer to the UsbManager. - // There isnt a check there. - if (functions == null) { - functions = ""; - } - if (mAdbEnabled) { - functions = UsbManager.addFunction(functions, UsbManager.USB_FUNCTION_ADB); - } else { - functions = UsbManager.removeFunction(functions, UsbManager.USB_FUNCTION_ADB); - } - return functions; - } - - private boolean isUsbTransferAllowed() { + protected boolean isUsbTransferAllowed() { UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); return !userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER); } @@ -650,12 +623,13 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver if (mConfigured && enteringAccessoryMode) { // successfully entered accessory mode - if (mAccessoryStrings != null) { - mCurrentAccessory = new UsbAccessory(mAccessoryStrings); + String[] accessoryStrings = mUsbDeviceManager.getAccessoryStrings(); + if (accessoryStrings != null) { + mCurrentAccessory = new UsbAccessory(accessoryStrings); Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory); // defer accessoryAttached if system is not ready if (mBootCompleted) { - getCurrentSettings().accessoryAttached(mCurrentAccessory); + mUsbDeviceManager.getCurrentSettings().accessoryAttached(mCurrentAccessory); } // else handle in boot completed } else { Slog.e(TAG, "nativeGetAccessoryStrings failed"); @@ -673,17 +647,24 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver // make sure accessory mode is off // and restore default functions Slog.d(TAG, "exited USB accessory mode"); - setEnabledFunctions(null, false, false); + setEnabledFunctions(UsbManager.FUNCTION_NONE, false); if (mCurrentAccessory != null) { if (mBootCompleted) { mSettingsManager.usbAccessoryRemoved(mCurrentAccessory); } mCurrentAccessory = null; - mAccessoryStrings = null; } } + protected SharedPreferences getPinnedSharedPrefs(Context context) { + final File prefsFile = new File(new File( + Environment.getDataUserCePackageDirectory(StorageManager.UUID_PRIVATE_INTERNAL, + context.getUserId(), context.getPackageName()), "shared_prefs"), + UsbDeviceManager.class.getSimpleName() + ".xml"); + return context.getSharedPreferences(prefsFile, Context.MODE_PRIVATE); + } + private boolean isUsbStateChanged(Intent intent) { final Set<String> keySet = intent.getExtras().keySet(); if (mBroadcastedIntent == null) { @@ -706,7 +687,8 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver return false; } - protected void updateUsbStateBroadcastIfNeeded(boolean configChanged) { + protected void updateUsbStateBroadcastIfNeeded(long functions, + boolean configChanged) { // send a sticky broadcast containing current USB state Intent intent = new Intent(UsbManager.ACTION_USB_STATE); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING @@ -716,18 +698,14 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver intent.putExtra(UsbManager.USB_HOST_CONNECTED, mHostConnected); intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured); intent.putExtra(UsbManager.USB_DATA_UNLOCKED, - isUsbTransferAllowed() && mUsbDataUnlocked); + isUsbTransferAllowed() && isUsbDataTransferActive(mCurrentFunctions)); intent.putExtra(UsbManager.USB_CONFIG_CHANGED, configChanged); - if (mCurrentFunctions != null) { - String[] functions = mCurrentFunctions.split(","); - for (int i = 0; i < functions.length; i++) { - final String function = functions[i]; - if (UsbManager.USB_FUNCTION_NONE.equals(function)) { - continue; - } - intent.putExtra(function, true); - } + long remainingFunctions = functions; + while (remainingFunctions != 0) { + intent.putExtra(UsbManager.usbFunctionsToString( + Long.highestOneBit(remainingFunctions)), true); + remainingFunctions -= Long.highestOneBit(remainingFunctions); } // send broadcast intent only if the USB state has changed @@ -739,18 +717,21 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver } if (DEBUG) Slog.d(TAG, "broadcasting " + intent + " extras: " + intent.getExtras()); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + sendStickyBroadcast(intent); mBroadcastedIntent = intent; } + protected void sendStickyBroadcast(Intent intent) { + mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + } + private void updateUsbFunctions() { updateAudioSourceFunction(); updateMidiFunction(); } private void updateAudioSourceFunction() { - boolean enabled = UsbManager.containsFunction(mCurrentFunctions, - UsbManager.USB_FUNCTION_AUDIO_SOURCE); + boolean enabled = (mCurrentFunctions & UsbManager.FUNCTION_AUDIO_SOURCE) != 0; if (enabled != mAudioSourceEnabled) { int card = -1; int device = -1; @@ -775,8 +756,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver } private void updateMidiFunction() { - boolean enabled = UsbManager.containsFunction(mCurrentFunctions, - UsbManager.USB_FUNCTION_MIDI); + boolean enabled = (mCurrentFunctions & UsbManager.FUNCTION_MIDI) != 0; if (enabled != mMidiEnabled) { if (enabled) { Scanner scanner = null; @@ -800,11 +780,21 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver } private void setScreenUnlockedFunctions() { - setEnabledFunctions(mScreenUnlockedFunctions, false, - UsbManager.containsFunction(mScreenUnlockedFunctions, - UsbManager.USB_FUNCTION_MTP) - || UsbManager.containsFunction(mScreenUnlockedFunctions, - UsbManager.USB_FUNCTION_PTP)); + setEnabledFunctions(mScreenUnlockedFunctions, false); + } + + /** + * Returns the functions that are passed down to the low level driver once adb and + * charging are accounted for. + */ + long getAppliedFunctions(long functions) { + if (functions == UsbManager.FUNCTION_NONE) { + return getChargingFunctions(); + } + if (mAdbEnabled) { + return functions | UsbManager.FUNCTION_ADB; + } + return functions; } @Override @@ -817,10 +807,10 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver updateUsbNotification(false); updateAdbNotification(false); if (mBootCompleted) { - updateUsbStateBroadcastIfNeeded(false); + updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions), + false); } - if (UsbManager.containsFunction(mCurrentFunctions, - UsbManager.USB_FUNCTION_ACCESSORY)) { + if ((mCurrentFunctions & UsbManager.FUNCTION_ACCESSORY) != 0) { updateCurrentAccessory(); } if (mBootCompleted) { @@ -828,11 +818,10 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver && !hasMessages(MSG_FUNCTION_SWITCH_TIMEOUT)) { // restore defaults when USB is disconnected if (!mScreenLocked - && !UsbManager.USB_FUNCTION_NONE.equals( - mScreenUnlockedFunctions)) { + && mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) { setScreenUnlockedFunctions(); } else { - setEnabledFunctions(null, !mAdbEnabled, false); + setEnabledFunctions(UsbManager.FUNCTION_NONE, !mAdbEnabled); } } updateUsbFunctions(); @@ -867,7 +856,8 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver updateUsbNotification(false); if (mBootCompleted) { if (mHostConnected || prevHostConnected) { - updateUsbStateBroadcastIfNeeded(false); + updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions), + false); } } else { mPendingBootBroadcast = true; @@ -913,17 +903,17 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver setAdbEnabled(msg.arg1 == 1); break; case MSG_SET_CURRENT_FUNCTIONS: - String functions = (String) msg.obj; - setEnabledFunctions(functions, false, msg.arg1 == 1); + long functions = (Long) msg.obj; + setEnabledFunctions(functions, false); break; case MSG_SET_SCREEN_UNLOCKED_FUNCTIONS: - mScreenUnlockedFunctions = (String) msg.obj; + mScreenUnlockedFunctions = (Long) msg.obj; SharedPreferences.Editor editor = mSettings.edit(); editor.putString(String.format(Locale.ENGLISH, UNLOCKED_CONFIG_PREF, - mCurrentUser), mScreenUnlockedFunctions); + mCurrentUser), + UsbManager.usbFunctionsToString(mScreenUnlockedFunctions)); editor.commit(); - if (!mScreenLocked && !UsbManager.USB_FUNCTION_NONE.equals( - mScreenUnlockedFunctions)) { + if (!mScreenLocked && mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) { // If the screen is unlocked, also set current functions. setScreenUnlockedFunctions(); } @@ -936,22 +926,21 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver if (mSettings == null && !mScreenLocked) { // Shared preferences aren't accessible until the user has been unlocked. mSettings = getPinnedSharedPrefs(mContext); - mScreenUnlockedFunctions = mSettings.getString( + mScreenUnlockedFunctions = UsbManager.usbFunctionsFromString( + mSettings.getString( String.format(Locale.ENGLISH, UNLOCKED_CONFIG_PREF, mCurrentUser), - UsbManager.USB_FUNCTION_NONE); + "")); } if (!mBootCompleted) { break; } if (mScreenLocked) { if (!mConnected) { - setEnabledFunctions(null, false, false); + setEnabledFunctions(UsbManager.FUNCTION_NONE, false); } } else { - if (!UsbManager.USB_FUNCTION_NONE.equals(mScreenUnlockedFunctions) - && (UsbManager.USB_FUNCTION_ADB.equals(mCurrentFunctions) - || (UsbManager.USB_FUNCTION_MTP.equals(mCurrentFunctions) - && !mUsbDataUnlocked))) { + if (mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE + && mCurrentFunctions == UsbManager.FUNCTION_NONE) { // Set the screen unlocked functions if current function is charging. setScreenUnlockedFunctions(); } @@ -959,13 +948,24 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver break; case MSG_UPDATE_USER_RESTRICTIONS: // Restart the USB stack if USB transfer is enabled but no longer allowed. - final boolean forceRestart = mUsbDataUnlocked - && isUsbDataTransferActive() - && !isUsbTransferAllowed(); - setEnabledFunctions( - mCurrentFunctions, forceRestart, mUsbDataUnlocked && !forceRestart); + if (isUsbDataTransferActive(mCurrentFunctions) && !isUsbTransferAllowed()) { + setEnabledFunctions(UsbManager.FUNCTION_NONE, true); + } break; case MSG_SYSTEM_READY: + mNotificationManager = (NotificationManager) + mContext.getSystemService(Context.NOTIFICATION_SERVICE); + + // Ensure that the notification channels are set up + if (isTv()) { + // TV-specific notification channel + mNotificationManager.createNotificationChannel( + new NotificationChannel(ADB_NOTIFICATION_CHANNEL_ID_TV, + mContext.getString( + com.android.internal.R.string + .adb_debugging_notification_channel_tv), + NotificationManager.IMPORTANCE_HIGH)); + } mSystemReady = true; finishBoot(); break; @@ -984,10 +984,14 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver } mCurrentUser = msg.arg1; mScreenLocked = true; - mScreenUnlockedFunctions = mSettings.getString( - String.format(Locale.ENGLISH, UNLOCKED_CONFIG_PREF, mCurrentUser), - UsbManager.USB_FUNCTION_NONE); - setEnabledFunctions(null, false, false); + if (mSettings != null) { + mScreenUnlockedFunctions = UsbManager.usbFunctionsFromString( + mSettings.getString( + String.format(Locale.ENGLISH, UNLOCKED_CONFIG_PREF, + mCurrentUser), + "")); + } + setEnabledFunctions(UsbManager.FUNCTION_NONE, false); } break; } @@ -995,9 +999,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver if (DEBUG) { Slog.v(TAG, "Accessory mode enter timeout: " + mConnected); } - if (!mConnected || !UsbManager.containsFunction( - mCurrentFunctions, - UsbManager.USB_FUNCTION_ACCESSORY)) { + if (!mConnected || (mCurrentFunctions & UsbManager.FUNCTION_ACCESSORY) == 0) { notifyAccessoryModeExit(); } break; @@ -1008,17 +1010,17 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver protected void finishBoot() { if (mBootCompleted && mCurrentUsbFunctionsReceived && mSystemReady) { if (mPendingBootBroadcast) { - updateUsbStateBroadcastIfNeeded(false); + updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions), false); mPendingBootBroadcast = false; } if (!mScreenLocked - && !UsbManager.USB_FUNCTION_NONE.equals(mScreenUnlockedFunctions)) { + && mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) { setScreenUnlockedFunctions(); } else { - setEnabledFunctions(null, false, false); + setEnabledFunctions(UsbManager.FUNCTION_NONE, false); } if (mCurrentAccessory != null) { - getCurrentSettings().accessoryAttached(mCurrentAccessory); + mUsbDeviceManager.getCurrentSettings().accessoryAttached(mCurrentAccessory); } if (mDebuggingManager != null) { mDebuggingManager.setAdbEnabled(mAdbEnabled); @@ -1026,8 +1028,8 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver // make sure the ADB_ENABLED setting value matches the current state try { - Settings.Global.putInt(mContentResolver, - Settings.Global.ADB_ENABLED, mAdbEnabled ? 1 : 0); + putGlobalSettings(mContentResolver, Settings.Global.ADB_ENABLED, + mAdbEnabled ? 1 : 0); } catch (SecurityException e) { // If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't // be changed. @@ -1040,9 +1042,9 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver } } - private boolean isUsbDataTransferActive() { - return UsbManager.containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP) - || UsbManager.containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP); + protected boolean isUsbDataTransferActive(long functions) { + return (functions & UsbManager.FUNCTION_MTP) != 0 + || (functions & UsbManager.FUNCTION_PTP) != 0; } public UsbAccessory getCurrentAccessory() { @@ -1051,7 +1053,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver protected void updateUsbNotification(boolean force) { if (mNotificationManager == null || !mUseUsbNotification - || ("0".equals(SystemProperties.get("persist.charging.notify")))) { + || ("0".equals(getSystemProperty("persist.charging.notify", "")))) { return; } @@ -1074,20 +1076,16 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver titleRes = com.android.internal.R.string.usb_unsupported_audio_accessory_title; id = SystemMessage.NOTE_USB_AUDIO_ACCESSORY_NOT_SUPPORTED; } else if (mConnected) { - if (UsbManager.containsFunction(mCurrentFunctions, - UsbManager.USB_FUNCTION_MTP) && mUsbDataUnlocked) { + if (mCurrentFunctions == UsbManager.FUNCTION_MTP) { titleRes = com.android.internal.R.string.usb_mtp_notification_title; id = SystemMessage.NOTE_USB_MTP; - } else if (UsbManager.containsFunction(mCurrentFunctions, - UsbManager.USB_FUNCTION_PTP) && mUsbDataUnlocked) { + } else if (mCurrentFunctions == UsbManager.FUNCTION_PTP) { titleRes = com.android.internal.R.string.usb_ptp_notification_title; id = SystemMessage.NOTE_USB_PTP; - } else if (UsbManager.containsFunction(mCurrentFunctions, - UsbManager.USB_FUNCTION_MIDI)) { + } else if (mCurrentFunctions == UsbManager.FUNCTION_MIDI) { titleRes = com.android.internal.R.string.usb_midi_notification_title; id = SystemMessage.NOTE_USB_MIDI; - } else if (UsbManager.containsFunction(mCurrentFunctions, - UsbManager.USB_FUNCTION_ACCESSORY)) { + } else if (mCurrentFunctions == UsbManager.FUNCTION_ACCESSORY) { titleRes = com.android.internal.R.string.usb_accessory_notification_title; id = SystemMessage.NOTE_USB_ACCESSORY; } else if (mSourcePower) { @@ -1184,7 +1182,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver final int titleRes = com.android.internal.R.string.adb_active_notification_title; if (mAdbEnabled && mConnected) { - if ("0".equals(SystemProperties.get("persist.adb.notify"))) return; + if ("0".equals(getSystemProperty("persist.adb.notify", ""))) return; if (force && mAdbNotificationShown) { mAdbNotificationShown = false; @@ -1230,20 +1228,41 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver } } - protected String getChargingFunctions() { + private boolean isTv() { + return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK); + } + + protected long getChargingFunctions() { // if ADB is enabled, reset functions to ADB // else enable MTP as usual. if (mAdbEnabled) { - return UsbManager.USB_FUNCTION_ADB; + return UsbManager.FUNCTION_ADB; } else { - return UsbManager.USB_FUNCTION_MTP; + return UsbManager.FUNCTION_MTP; } } - public boolean isFunctionEnabled(String function) { - return UsbManager.containsFunction(mCurrentFunctions, function); + protected void setSystemProperty(String prop, String val) { + SystemProperties.set(prop, val); + } + + protected String getSystemProperty(String prop, String def) { + return SystemProperties.get(prop, def); + } + + protected void putGlobalSettings(ContentResolver contentResolver, String setting, int val) { + Settings.Global.putInt(contentResolver, setting, val); + } + + public long getEnabledFunctions() { + return mCurrentFunctions; } + public long getScreenUnlockedFunctions() { + return mScreenUnlockedFunctions; + } + + public void dump(IndentingPrintWriter pw) { pw.println("USB Device State:"); pw.println(" mCurrentFunctions: " + mCurrentFunctions); @@ -1252,7 +1271,6 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver pw.println(" mScreenLocked: " + mScreenLocked); pw.println(" mConnected: " + mConnected); pw.println(" mConfigured: " + mConfigured); - pw.println(" mUsbDataUnlocked: " + mUsbDataUnlocked); pw.println(" mCurrentAccessory: " + mCurrentAccessory); pw.println(" mHostConnected: " + mHostConnected); pw.println(" mSourcePower: " + mSourcePower); @@ -1275,12 +1293,10 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver /** * Evaluates USB function policies and applies the change accordingly. */ - protected abstract void setEnabledFunctions(String functions, boolean forceRestart, - boolean usbDataUnlocked); - + protected abstract void setEnabledFunctions(long functions, boolean forceRestart); } - private final class UsbHandlerLegacy extends UsbHandler { + private static final class UsbHandlerLegacy extends UsbHandler { /** * The non-persistent property which stores the current USB settings. */ @@ -1293,46 +1309,44 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver private HashMap<String, HashMap<String, Pair<String, String>>> mOemModeMap; private String mCurrentOemFunctions; + private String mCurrentFunctionsStr; + private boolean mUsbDataUnlocked; - UsbHandlerLegacy(Looper looper, Context context) { - super(looper); + UsbHandlerLegacy(Looper looper, Context context, UsbDeviceManager deviceManager, + UsbDebuggingManager debuggingManager, UsbAlsaManager alsaManager, + UsbSettingsManager settingsManager) { + super(looper, context, deviceManager, debuggingManager, alsaManager, settingsManager); try { readOemUsbOverrideConfig(context); // Restore default functions. - mCurrentOemFunctions = SystemProperties.get(getPersistProp(false), + mCurrentOemFunctions = getSystemProperty(getPersistProp(false), UsbManager.USB_FUNCTION_NONE); if (isNormalBoot()) { - mCurrentFunctions = SystemProperties.get(USB_CONFIG_PROPERTY, + mCurrentFunctionsStr = getSystemProperty(USB_CONFIG_PROPERTY, UsbManager.USB_FUNCTION_NONE); - mCurrentFunctionsApplied = mCurrentFunctions.equals( - SystemProperties.get(USB_STATE_PROPERTY)); + mCurrentFunctionsApplied = mCurrentFunctionsStr.equals( + getSystemProperty(USB_STATE_PROPERTY, UsbManager.USB_FUNCTION_NONE)); } else { - mCurrentFunctions = SystemProperties.get(getPersistProp(true), + mCurrentFunctionsStr = getSystemProperty(getPersistProp(true), UsbManager.USB_FUNCTION_NONE); - mCurrentFunctionsApplied = SystemProperties.get(USB_CONFIG_PROPERTY, + mCurrentFunctionsApplied = getSystemProperty(USB_CONFIG_PROPERTY, UsbManager.USB_FUNCTION_NONE).equals( - SystemProperties.get(USB_STATE_PROPERTY)); + getSystemProperty(USB_STATE_PROPERTY, UsbManager.USB_FUNCTION_NONE)); } + // Mask out adb, since it is stored in mAdbEnabled + mCurrentFunctions = UsbManager.usbFunctionsFromString(mCurrentFunctionsStr) + & ~UsbManager.FUNCTION_ADB; mCurrentUsbFunctionsReceived = true; String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim(); updateState(state); - - // register observer to listen for settings changes - mContentResolver.registerContentObserver( - Settings.Global.getUriFor(Settings.Global.ADB_ENABLED), - false, new AdbSettingsObserver()); - - // Watch for USB configuration changes - mUEventObserver.startObserving(USB_STATE_MATCH); - mUEventObserver.startObserving(ACCESSORY_START_MATCH); } catch (Exception e) { Slog.e(TAG, "Error initializing UsbHandler", e); } } private void readOemUsbOverrideConfig(Context context) { - String[] configList = mContext.getResources().getStringArray( + String[] configList = context.getResources().getStringArray( com.android.internal.R.array.config_oemUsbModeOverride); if (configList != null) { @@ -1367,7 +1381,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver return usbFunctions; } - String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown"); + String bootMode = getSystemProperty(BOOT_MODE_PROPERTY, "unknown"); Slog.d(TAG, "applyOemOverride usbfunctions=" + usbFunctions + " bootmode=" + bootMode); Map<String, Pair<String, String>> overridesMap = @@ -1386,25 +1400,22 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver if (!overrideFunctions.second.equals("")) { String newFunction; if (mAdbEnabled) { - newFunction = UsbManager.addFunction(overrideFunctions.second, + newFunction = addFunction(overrideFunctions.second, UsbManager.USB_FUNCTION_ADB); } else { newFunction = overrideFunctions.second; } Slog.d(TAG, "OEM USB override persisting: " + newFunction + "in prop: " + getPersistProp(false)); - SystemProperties.set(getPersistProp(false), - newFunction); + setSystemProperty(getPersistProp(false), newFunction); } return overrideFunctions.first; } else if (mAdbEnabled) { - String newFunction = UsbManager.addFunction(UsbManager.USB_FUNCTION_NONE, + String newFunction = addFunction(UsbManager.USB_FUNCTION_NONE, UsbManager.USB_FUNCTION_ADB); - SystemProperties.set(getPersistProp(false), - newFunction); + setSystemProperty(getPersistProp(false), newFunction); } else { - SystemProperties.set(getPersistProp(false), - UsbManager.USB_FUNCTION_NONE); + setSystemProperty(getPersistProp(false), UsbManager.USB_FUNCTION_NONE); } } // return passed in functions as is. @@ -1417,7 +1428,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver String value = null; for (int i = 0; i < 20; i++) { // State transition is done when sys.usb.state is set to the new configuration - value = SystemProperties.get(USB_STATE_PROPERTY); + value = getSystemProperty(USB_STATE_PROPERTY, ""); if (state.equals(value)) return true; SystemClock.sleep(50); } @@ -1432,14 +1443,14 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver * we always set it due to b/23631400, where adbd was getting killed * and not restarted due to property timeouts on some devices */ - SystemProperties.set(USB_CONFIG_PROPERTY, config); + setSystemProperty(USB_CONFIG_PROPERTY, config); } @Override - protected void setEnabledFunctions(String functions, boolean forceRestart, - boolean usbDataUnlocked) { + protected void setEnabledFunctions(long usbFunctions, boolean forceRestart) { + boolean usbDataUnlocked = isUsbDataTransferActive(usbFunctions); if (DEBUG) { - Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", " + Slog.d(TAG, "setEnabledFunctions functions=" + usbFunctions + ", " + "forceRestart=" + forceRestart + ", usbDataUnlocked=" + usbDataUnlocked); } @@ -1452,9 +1463,9 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver /** * Try to set the enabled functions. */ - final String oldFunctions = mCurrentFunctions; + final long oldFunctions = mCurrentFunctions; final boolean oldFunctionsApplied = mCurrentFunctionsApplied; - if (trySetEnabledFunctions(functions, forceRestart)) { + if (trySetEnabledFunctions(usbFunctions, forceRestart)) { return; } @@ -1464,7 +1475,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver * user restrictions independently of any other new functions we were * trying to activate. */ - if (oldFunctionsApplied && !oldFunctions.equals(functions)) { + if (oldFunctionsApplied && oldFunctions != usbFunctions) { Slog.e(TAG, "Failsafe 1: Restoring previous USB functions."); if (trySetEnabledFunctions(oldFunctions, false)) { return; @@ -1475,7 +1486,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver * Still didn't work. Try to restore the default functions. */ Slog.e(TAG, "Failsafe 2: Restoring default USB functions."); - if (trySetEnabledFunctions(null, false)) { + if (trySetEnabledFunctions(UsbManager.FUNCTION_NONE, false)) { return; } @@ -1484,7 +1495,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver * Try to get ADB working if enabled. */ Slog.e(TAG, "Failsafe 3: Restoring empty function list (with ADB if enabled)."); - if (trySetEnabledFunctions(UsbManager.USB_FUNCTION_NONE, false)) { + if (trySetEnabledFunctions(UsbManager.FUNCTION_NONE, false)) { return; } @@ -1495,30 +1506,49 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver } private boolean isNormalBoot() { - String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown"); + String bootMode = getSystemProperty(BOOT_MODE_PROPERTY, "unknown"); return bootMode.equals(NORMAL_BOOT) || bootMode.equals("unknown"); } - private boolean trySetEnabledFunctions(String functions, boolean forceRestart) { + protected String applyAdbFunction(String functions) { + // Do not pass null pointer to the UsbManager. + // There isn't a check there. + if (functions == null) { + functions = ""; + } + if (mAdbEnabled) { + functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB); + } else { + functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB); + } + return functions; + } + + private boolean trySetEnabledFunctions(long usbFunctions, boolean forceRestart) { + String functions = null; + if (usbFunctions != UsbManager.FUNCTION_NONE) { + functions = UsbManager.usbFunctionsToString(usbFunctions); + } + mCurrentFunctions = usbFunctions; if (functions == null || applyAdbFunction(functions) .equals(UsbManager.USB_FUNCTION_NONE)) { - functions = getChargingFunctions(); + functions = UsbManager.usbFunctionsToString(getChargingFunctions()); } functions = applyAdbFunction(functions); String oemFunctions = applyOemOverrideFunction(functions); - if (!isNormalBoot() && !mCurrentFunctions.equals(functions)) { - SystemProperties.set(getPersistProp(true), functions); + if (!isNormalBoot() && !mCurrentFunctionsStr.equals(functions)) { + setSystemProperty(getPersistProp(true), functions); } if ((!functions.equals(oemFunctions) && !mCurrentOemFunctions.equals(oemFunctions)) - || !mCurrentFunctions.equals(functions) + || !mCurrentFunctionsStr.equals(functions) || !mCurrentFunctionsApplied || forceRestart) { Slog.i(TAG, "Setting USB config to " + functions); - mCurrentFunctions = functions; + mCurrentFunctionsStr = functions; mCurrentOemFunctions = oemFunctions; mCurrentFunctionsApplied = false; @@ -1538,12 +1568,12 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver setUsbConfig(oemFunctions); if (mBootCompleted - && (UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_MTP) - || UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) { + && (containsFunction(functions, UsbManager.USB_FUNCTION_MTP) + || containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) { /** * Start up dependent services. */ - updateUsbStateBroadcastIfNeeded(true); + updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions), true); } if (!waitForState(oemFunctions)) { @@ -1557,7 +1587,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver } private String getPersistProp(boolean functions) { - String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown"); + String bootMode = getSystemProperty(BOOT_MODE_PROPERTY, "unknown"); String persistProp = USB_PERSISTENT_CONFIG_PROPERTY; if (!(bootMode.equals(NORMAL_BOOT) || bootMode.equals("unknown"))) { if (functions) { @@ -1568,9 +1598,54 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver } return persistProp; } + + private String addFunction(String functions, String function) { + if (UsbManager.USB_FUNCTION_NONE.equals(functions)) { + return function; + } + if (!containsFunction(functions, function)) { + if (functions.length() > 0) { + functions += ","; + } + functions += function; + } + return functions; + } + + private String removeFunction(String functions, String function) { + String[] split = functions.split(","); + for (int i = 0; i < split.length; i++) { + if (function.equals(split[i])) { + split[i] = null; + } + } + if (split.length == 1 && split[0] == null) { + return UsbManager.USB_FUNCTION_NONE; + } + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < split.length; i++) { + String s = split[i]; + if (s != null) { + if (builder.length() > 0) { + builder.append(","); + } + builder.append(s); + } + } + return builder.toString(); + } + + private boolean containsFunction(String functions, String function) { + int index = functions.indexOf(function); + if (index < 0) return false; + if (index > 0 && functions.charAt(index - 1) != ',') return false; + int charAfter = index + function.length(); + if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false; + return true; + } } - private final class UsbHandlerHal extends UsbHandler { + private static final class UsbHandlerHal extends UsbHandler { /** * Proxy object for the usb gadget hal daemon. @@ -1627,9 +1702,12 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver */ protected static final String ADBD = "adbd"; + protected boolean mCurrentUsbFunctionsRequested; - UsbHandlerHal(Looper looper) { - super(looper); + UsbHandlerHal(Looper looper, Context context, UsbDeviceManager deviceManager, + UsbDebuggingManager debuggingManager, UsbAlsaManager alsaManager, + UsbSettingsManager settingsManager) { + super(looper, context, deviceManager, debuggingManager, alsaManager, settingsManager); try { ServiceNotification serviceNotification = new ServiceNotification(); @@ -1645,25 +1723,12 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver mGadgetProxy = IUsbGadget.getService(true); mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(), USB_GADGET_HAL_DEATH_COOKIE); - mCurrentFunctions = UsbManager.USB_FUNCTION_NONE; + mCurrentFunctions = UsbManager.FUNCTION_NONE; mGadgetProxy.getCurrentUsbFunctions(new UsbGadgetCallback()); mCurrentUsbFunctionsRequested = true; } String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim(); updateState(state); - - /** - * Register observer to listen for settings changes. - */ - mContentResolver.registerContentObserver( - Settings.Global.getUriFor(Settings.Global.ADB_ENABLED), - false, new AdbSettingsObserver()); - - /** - * Watch for USB configuration changes. - */ - mUEventObserver.startObserving(USB_STATE_MATCH); - mUEventObserver.startObserving(ACCESSORY_START_MATCH); } catch (NoSuchElementException e) { Slog.e(TAG, "Usb gadget hal not found", e); } catch (RemoteException e) { @@ -1696,7 +1761,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(), USB_GADGET_HAL_DEATH_COOKIE); if (!mCurrentFunctionsApplied) { - setCurrentFunctions(mCurrentFunctions, mUsbDataUnlocked); + setEnabledFunctions(mCurrentFunctions, false); } } catch (NoSuchElementException e) { Slog.e(TAG, "Usb gadget hal not found", e); @@ -1711,12 +1776,12 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver public void handleMessage(Message msg) { switch (msg.what) { case MSG_SET_CHARGING_FUNCTIONS: - setEnabledFunctions(null, false, mUsbDataUnlocked); + setEnabledFunctions(UsbManager.FUNCTION_NONE, false); break; case MSG_SET_FUNCTIONS_TIMEOUT: Slog.e(TAG, "Set functions timed out! no reply from usb hal"); if (msg.arg1 != 1) { - setEnabledFunctions(null, false, mUsbDataUnlocked); + setEnabledFunctions(UsbManager.FUNCTION_NONE, false); } break; case MSG_GET_CURRENT_USB_FUNCTIONS: @@ -1725,7 +1790,8 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver if (mCurrentUsbFunctionsRequested) { Slog.e(TAG, "updating mCurrentFunctions"); - mCurrentFunctions = functionListToString((Long) msg.obj); + // Mask out adb, since it is stored in mAdbEnabled + mCurrentFunctions = ((Long) msg.obj) & ~UsbManager.FUNCTION_ADB; Slog.e(TAG, "mCurrentFunctions:" + mCurrentFunctions + "applied:" + msg.arg1); mCurrentFunctionsApplied = msg.arg1 == 1; @@ -1737,7 +1803,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver * Dont force to default when the configuration is already set to default. */ if (msg.arg1 != 1) { - setEnabledFunctions(null, !mAdbEnabled, false); + setEnabledFunctions(UsbManager.FUNCTION_NONE, !mAdbEnabled); } break; default: @@ -1789,70 +1855,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver } } - private long stringToFunctionList(String config) { - long functionsMask = 0; - String[] functions = config.split(","); - for (int i = 0; i < functions.length; i++) { - switch (functions[i]) { - case "none": - functionsMask |= GadgetFunction.NONE; - break; - case "adb": - functionsMask |= GadgetFunction.ADB; - break; - case "mtp": - functionsMask |= GadgetFunction.MTP; - break; - case "ptp": - functionsMask |= GadgetFunction.PTP; - break; - case "midi": - functionsMask |= GadgetFunction.MIDI; - break; - case "accessory": - functionsMask |= GadgetFunction.ACCESSORY; - break; - case "rndis": - functionsMask |= GadgetFunction.RNDIS; - break; - } - } - return functionsMask; - } - - private String functionListToString(Long functionList) { - StringJoiner functions = new StringJoiner(","); - if (functionList == GadgetFunction.NONE) { - functions.add("none"); - return functions.toString(); - } - if ((functionList & GadgetFunction.ADB) != 0) { - functions.add("adb"); - } - if ((functionList & GadgetFunction.MTP) != 0) { - functions.add("mtp"); - } - if ((functionList & GadgetFunction.PTP) != 0) { - functions.add("ptp"); - } - if ((functionList & GadgetFunction.MIDI) != 0) { - functions.add("midi"); - } - if ((functionList & GadgetFunction.ACCESSORY) != 0) { - functions.add("accessory"); - } - if ((functionList & GadgetFunction.RNDIS) != 0) { - functions.add("rndis"); - } - /** - * Remove the trailing comma. - */ - return functions.toString(); - } - - - private void setUsbConfig(String config, boolean chargingFunctions) { - Long functions = stringToFunctionList(config); + private void setUsbConfig(long config, boolean chargingFunctions) { if (true) Slog.d(TAG, "setUsbConfig(" + config + ") request:" + ++mCurrentRequest); /** * Cancel any ongoing requests, if present. @@ -1867,20 +1870,20 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver return; } try { - if ((functions & GadgetFunction.ADB) != 0) { + if ((config & UsbManager.FUNCTION_ADB) != 0) { /** * Start adbd if ADB function is included in the configuration. */ - SystemProperties.set(CTL_START, ADBD); + setSystemProperty(CTL_START, ADBD); } else { /** * Stop adbd otherwise. */ - SystemProperties.set(CTL_STOP, ADBD); + setSystemProperty(CTL_STOP, ADBD); } UsbGadgetCallback usbGadgetCallback = new UsbGadgetCallback(mCurrentRequest, - functions, chargingFunctions); - mGadgetProxy.setCurrentUsbFunctions(functions, usbGadgetCallback, + config, chargingFunctions); + mGadgetProxy.setCurrentUsbFunctions(config, usbGadgetCallback, SET_FUNCTIONS_TIMEOUT_MS - SET_FUNCTIONS_LEEWAY_MS); sendMessageDelayed(MSG_SET_FUNCTIONS_TIMEOUT, chargingFunctions, SET_FUNCTIONS_TIMEOUT_MS); @@ -1894,49 +1897,29 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver } @Override - protected void setEnabledFunctions(String functions, boolean forceRestart, - boolean usbDataUnlocked) { + protected void setEnabledFunctions(long functions, boolean forceRestart) { if (DEBUG) { Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", " - + "forceRestart=" + forceRestart + ", usbDataUnlocked=" + usbDataUnlocked); - } - - if (usbDataUnlocked != mUsbDataUnlocked) { - mUsbDataUnlocked = usbDataUnlocked; - updateUsbNotification(false); - forceRestart = true; + + "forceRestart=" + forceRestart); } - - trySetEnabledFunctions(functions, forceRestart); - } - - private void trySetEnabledFunctions(String functions, boolean forceRestart) { - boolean chargingFunctions = false; - - if (functions == null || applyAdbFunction(functions) - .equals(UsbManager.USB_FUNCTION_NONE)) { - functions = getChargingFunctions(); - chargingFunctions = true; - } - functions = applyAdbFunction(functions); - - if (!mCurrentFunctions.equals(functions) + if (mCurrentFunctions != functions || !mCurrentFunctionsApplied || forceRestart) { - Slog.i(TAG, "Setting USB config to " + functions); + Slog.i(TAG, "Setting USB config to " + UsbManager.usbFunctionsToString(functions)); mCurrentFunctions = functions; mCurrentFunctionsApplied = false; // set the flag to false as that would be stale value mCurrentUsbFunctionsRequested = false; + boolean chargingFunctions = functions == UsbManager.FUNCTION_NONE; + functions = getAppliedFunctions(functions); + // Set the new USB configuration. - setUsbConfig(mCurrentFunctions, chargingFunctions); + setUsbConfig(functions, chargingFunctions); - if (mBootCompleted - && (UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_MTP) - || UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) { + if (mBootCompleted && isUsbDataTransferActive(functions)) { // Start up dependent services. - updateUsbStateBroadcastIfNeeded(true); + updateUsbStateBroadcastIfNeeded(functions, true); } } } @@ -1968,27 +1951,37 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver return nativeOpenAccessory(); } - /** - * Checks whether the function is present in the USB configuration. - * - * @param function function to be checked. - */ - public boolean isFunctionEnabled(String function) { - return mHandler.isFunctionEnabled(function); + public long getCurrentFunctions() { + return mHandler.getEnabledFunctions(); + } + + public long getScreenUnlockedFunctions() { + return mHandler.getScreenUnlockedFunctions(); } /** * Adds function to the current USB configuration. * - * @param functions name of the USB function, or null to restore the default function. - * @param usbDataUnlocked whether user data is accessible. + * @param functions The functions to set, or empty to set the charging function. */ - public void setCurrentFunctions(String functions, boolean usbDataUnlocked) { + public void setCurrentFunctions(long functions) { if (DEBUG) { - Slog.d(TAG, "setCurrentFunctions(" + functions + ", " - + usbDataUnlocked + ")"); - } - mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, usbDataUnlocked); + Slog.d(TAG, "setCurrentFunctions(" + UsbManager.usbFunctionsToString(functions) + ")"); + } + if (functions == UsbManager.FUNCTION_NONE) { + MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_CHARGING); + } else if (functions == UsbManager.FUNCTION_MTP) { + MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_MTP); + } else if (functions == UsbManager.FUNCTION_PTP) { + MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_PTP); + } else if (functions == UsbManager.FUNCTION_MIDI) { + MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_MIDI); + } else if (functions == UsbManager.FUNCTION_RNDIS) { + MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_RNDIS); + } else if (functions == UsbManager.FUNCTION_ACCESSORY) { + MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_ACCESSORY); + } + mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions); } /** @@ -1996,9 +1989,10 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver * * @param functions Functions to set. */ - public void setScreenUnlockedFunctions(String functions) { + public void setScreenUnlockedFunctions(long functions) { if (DEBUG) { - Slog.d(TAG, "setScreenUnlockedFunctions(" + functions + ")"); + Slog.d(TAG, "setScreenUnlockedFunctions(" + + UsbManager.usbFunctionsToString(functions) + ")"); } mHandler.sendMessage(MSG_SET_SCREEN_UNLOCKED_FUNCTIONS, functions); } diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java index 1a20819b9a80..2f6e53143312 100644 --- a/services/usb/java/com/android/server/usb/UsbService.java +++ b/services/usb/java/com/android/server/usb/UsbService.java @@ -382,59 +382,44 @@ public class UsbService extends IUsbManager.Stub { } @Override - public boolean isFunctionEnabled(String function) { + public void setCurrentFunctions(long functions) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); - return mDeviceManager != null && mDeviceManager.isFunctionEnabled(function); + Preconditions.checkArgument(UsbManager.areSettableFunctions(functions)); + Preconditions.checkState(mDeviceManager != null); + mDeviceManager.setCurrentFunctions(functions); } @Override - public void setCurrentFunction(String function, boolean usbDataUnlocked) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); - - if (!isSupportedCurrentFunction(function)) { - Slog.w(TAG, "Caller of setCurrentFunction() requested unsupported USB function: " - + function); - function = UsbManager.USB_FUNCTION_NONE; - } + public void setCurrentFunction(String functions, boolean usbDataUnlocked) { + setCurrentFunctions(UsbManager.usbFunctionsFromString(functions)); + } - if (mDeviceManager != null) { - mDeviceManager.setCurrentFunctions(function, usbDataUnlocked); - } else { - throw new IllegalStateException("USB device mode not supported"); - } + @Override + public boolean isFunctionEnabled(String function) { + return (getCurrentFunctions() & UsbManager.usbFunctionsFromString(function)) != 0; } @Override - public void setScreenUnlockedFunctions(String function) { + public long getCurrentFunctions() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); - - if (!isSupportedCurrentFunction(function)) { - Slog.w(TAG, "Caller of setScreenUnlockedFunctions() requested unsupported USB function:" - + function); - function = UsbManager.USB_FUNCTION_NONE; - } - - if (mDeviceManager != null) { - mDeviceManager.setScreenUnlockedFunctions(function); - } else { - throw new IllegalStateException("USB device mode not supported"); - } + Preconditions.checkState(mDeviceManager != null); + return mDeviceManager.getCurrentFunctions(); } - private static boolean isSupportedCurrentFunction(String function) { - if (function == null) return true; + @Override + public void setScreenUnlockedFunctions(long functions) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); + Preconditions.checkArgument(UsbManager.areSettableFunctions(functions)); + Preconditions.checkState(mDeviceManager != null); - switch (function) { - case UsbManager.USB_FUNCTION_NONE: - case UsbManager.USB_FUNCTION_AUDIO_SOURCE: - case UsbManager.USB_FUNCTION_MIDI: - case UsbManager.USB_FUNCTION_MTP: - case UsbManager.USB_FUNCTION_PTP: - case UsbManager.USB_FUNCTION_RNDIS: - return true; - } + mDeviceManager.setScreenUnlockedFunctions(functions); + } - return false; + @Override + public long getScreenUnlockedFunctions() { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); + Preconditions.checkState(mDeviceManager != null); + return mDeviceManager.getScreenUnlockedFunctions(); } @Override diff --git a/tests/UsbTests/Android.mk b/tests/UsbTests/Android.mk new file mode 100644 index 000000000000..a04f32a6d714 --- /dev/null +++ b/tests/UsbTests/Android.mk @@ -0,0 +1,44 @@ +# +# Copyright (C) 2018 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + frameworks-base-testutils \ + android-support-test \ + mockito-target-inline-minus-junit4 \ + platform-test-annotations \ + services.core \ + services.net \ + services.usb \ + truth-prebuilt \ + +LOCAL_JNI_SHARED_LIBRARIES := \ + libdexmakerjvmtiagent \ + +LOCAL_CERTIFICATE := platform + +LOCAL_PACKAGE_NAME := UsbTests + +LOCAL_COMPATIBILITY_SUITE := device-tests + +include $(BUILD_PACKAGE) diff --git a/tests/UsbTests/AndroidManifest.xml b/tests/UsbTests/AndroidManifest.xml new file mode 100644 index 000000000000..5d606951bb5e --- /dev/null +++ b/tests/UsbTests/AndroidManifest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.server.usb" > + + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> + <uses-permission android:name="android.permission.MANAGE_USERS" /> + + <application android:debuggable="true"> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.server.usb" + android:label="UsbTests"/> +</manifest> diff --git a/tests/UsbTests/AndroidTest.xml b/tests/UsbTests/AndroidTest.xml new file mode 100644 index 000000000000..0b623fbf2015 --- /dev/null +++ b/tests/UsbTests/AndroidTest.xml @@ -0,0 +1,29 @@ +<!-- Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<configuration description="Runs sample instrumentation test."> + <target_preparer class="com.android.tradefed.targetprep.TestFilePushSetup"/> + <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="test-file-name" value="UsbTests.apk"/> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"/> + <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"/> + <option name="test-suite-tag" value="apct"/> + <option name="test-tag" value="UsbTests"/> + + <test class="com.android.tradefed.testtype.AndroidJUnitTest"> + <option name="package" value="com.android.server.usb"/> + <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/> + </test> +</configuration>
\ No newline at end of file diff --git a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java new file mode 100644 index 000000000000..c491b4658999 --- /dev/null +++ b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.usb; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.hardware.usb.UsbManager; +import android.os.Handler; +import android.os.Looper; +import android.os.UserHandle; +import android.provider.Settings; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import com.android.server.FgThread; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +/** + * Tests for UsbHandler state changes. + */ +@RunWith(AndroidJUnit4.class) +public class UsbHandlerTest { + private static final String TAG = UsbHandlerTest.class.getSimpleName(); + + @Mock + private UsbDeviceManager mUsbDeviceManager; + @Mock + private UsbDebuggingManager mUsbDebuggingManager; + @Mock + private UsbAlsaManager mUsbAlsaManager; + @Mock + private UsbSettingsManager mUsbSettingsManager; + @Mock + private SharedPreferences mSharedPreferences; + @Mock + private SharedPreferences.Editor mEditor; + + private MockUsbHandler mUsbHandler; + + private static final int MSG_UPDATE_STATE = 0; + private static final int MSG_ENABLE_ADB = 1; + private static final int MSG_SET_CURRENT_FUNCTIONS = 2; + private static final int MSG_SYSTEM_READY = 3; + private static final int MSG_BOOT_COMPLETED = 4; + private static final int MSG_USER_SWITCHED = 5; + private static final int MSG_UPDATE_USER_RESTRICTIONS = 6; + private static final int MSG_SET_SCREEN_UNLOCKED_FUNCTIONS = 12; + private static final int MSG_UPDATE_SCREEN_LOCK = 13; + + private Map<String, String> mMockProperties; + private Map<String, Integer> mMockGlobalSettings; + + private class MockUsbHandler extends UsbDeviceManager.UsbHandler { + boolean mIsUsbTransferAllowed; + Intent mBroadcastedIntent; + + MockUsbHandler(Looper looper, Context context, UsbDeviceManager deviceManager, + UsbDebuggingManager debuggingManager, UsbAlsaManager alsaManager, + UsbSettingsManager settingsManager) { + super(looper, context, deviceManager, debuggingManager, alsaManager, settingsManager); + mUseUsbNotification = false; + mIsUsbTransferAllowed = true; + mCurrentUsbFunctionsReceived = true; + } + + @Override + protected void setEnabledFunctions(long functions, boolean force) { + mCurrentFunctions = functions; + } + + @Override + protected void setSystemProperty(String property, String value) { + mMockProperties.put(property, value); + } + + @Override + protected void putGlobalSettings(ContentResolver resolver, String setting, int val) { + mMockGlobalSettings.put(setting, val); + } + + @Override + protected String getSystemProperty(String property, String def) { + if (mMockProperties.containsKey(property)) { + return mMockProperties.get(property); + } + return def; + } + + @Override + protected boolean isUsbTransferAllowed() { + return mIsUsbTransferAllowed; + } + + @Override + protected SharedPreferences getPinnedSharedPrefs(Context context) { + return mSharedPreferences; + } + + @Override + protected void sendStickyBroadcast(Intent intent) { + mBroadcastedIntent = intent; + } + } + + @Before + public void before() { + MockitoAnnotations.initMocks(this); + mMockProperties = new HashMap<>(); + mMockGlobalSettings = new HashMap<>(); + when(mSharedPreferences.edit()).thenReturn(mEditor); + + mUsbHandler = new MockUsbHandler(FgThread.get().getLooper(), + InstrumentationRegistry.getContext(), mUsbDeviceManager, mUsbDebuggingManager, + mUsbAlsaManager, mUsbSettingsManager); + } + + @SmallTest + public void setFunctionsMtp() { + mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS, + UsbManager.FUNCTION_MTP)); + assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_MTP, 0); + } + + @SmallTest + public void setFunctionsPtp() { + mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS, + UsbManager.FUNCTION_PTP)); + assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_PTP, 0); + } + + @SmallTest + public void setFunctionsMidi() { + mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS, + UsbManager.FUNCTION_MIDI)); + assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_MIDI, 0); + } + + @SmallTest + public void setFunctionsRndis() { + mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS, + UsbManager.FUNCTION_RNDIS)); + assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_RNDIS, 0); + } + + @SmallTest + public void enableAdb() { + sendBootCompleteMessages(mUsbHandler); + mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_ENABLE_ADB, 1)); + assertEquals(mUsbHandler.getEnabledFunctions(), UsbManager.FUNCTION_NONE); + assertTrue(mUsbHandler.mAdbEnabled); + assertEquals(mMockProperties.get(UsbDeviceManager.UsbHandler + .USB_PERSISTENT_CONFIG_PROPERTY), UsbManager.USB_FUNCTION_ADB); + verify(mUsbDebuggingManager).setAdbEnabled(true); + + mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_UPDATE_STATE, 1, 1)); + + assertTrue(mUsbHandler.mBroadcastedIntent.getBooleanExtra(UsbManager.USB_CONNECTED, false)); + assertTrue(mUsbHandler.mBroadcastedIntent + .getBooleanExtra(UsbManager.USB_CONFIGURED, false)); + assertTrue(mUsbHandler.mBroadcastedIntent + .getBooleanExtra(UsbManager.USB_FUNCTION_ADB, false)); + } + + @SmallTest + public void disableAdb() { + mMockProperties.put(UsbDeviceManager.UsbHandler.USB_PERSISTENT_CONFIG_PROPERTY, + UsbManager.USB_FUNCTION_ADB); + mUsbHandler = new MockUsbHandler(FgThread.get().getLooper(), + InstrumentationRegistry.getContext(), mUsbDeviceManager, mUsbDebuggingManager, + mUsbAlsaManager, mUsbSettingsManager); + + sendBootCompleteMessages(mUsbHandler); + mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_ENABLE_ADB, 0)); + assertEquals(mUsbHandler.getEnabledFunctions(), UsbManager.FUNCTION_NONE); + assertFalse(mUsbHandler.mAdbEnabled); + assertEquals(mMockProperties.get(UsbDeviceManager.UsbHandler + .USB_PERSISTENT_CONFIG_PROPERTY), ""); + verify(mUsbDebuggingManager).setAdbEnabled(false); + } + + @SmallTest + public void bootCompletedCharging() { + sendBootCompleteMessages(mUsbHandler); + assertEquals(mUsbHandler.getEnabledFunctions(), UsbManager.FUNCTION_NONE); + } + + @Test + @SmallTest + public void bootCompletedAdbEnabled() { + mMockProperties.put(UsbDeviceManager.UsbHandler.USB_PERSISTENT_CONFIG_PROPERTY, "adb"); + mUsbHandler = new MockUsbHandler(FgThread.get().getLooper(), + InstrumentationRegistry.getContext(), mUsbDeviceManager, mUsbDebuggingManager, + mUsbAlsaManager, mUsbSettingsManager); + + sendBootCompleteMessages(mUsbHandler); + assertEquals(mUsbHandler.getEnabledFunctions(), UsbManager.FUNCTION_NONE); + assertEquals(mMockGlobalSettings.get(Settings.Global.ADB_ENABLED).intValue(), 1); + assertTrue(mUsbHandler.mAdbEnabled); + verify(mUsbDebuggingManager).setAdbEnabled(true); + } + + @SmallTest + public void userSwitchedDisablesMtp() { + mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS, + UsbManager.FUNCTION_MTP)); + assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_MTP, 0); + + mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_USER_SWITCHED, + UserHandle.getCallingUserId() + 1)); + assertEquals(mUsbHandler.getEnabledFunctions(), UsbManager.FUNCTION_NONE); + } + + @SmallTest + public void changedRestrictionsDisablesMtp() { + mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS, + UsbManager.FUNCTION_MTP)); + assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_MTP, 0); + + mUsbHandler.mIsUsbTransferAllowed = false; + mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_UPDATE_USER_RESTRICTIONS)); + assertEquals(mUsbHandler.getEnabledFunctions(), UsbManager.FUNCTION_NONE); + } + + @SmallTest + public void disconnectResetsCharging() { + sendBootCompleteMessages(mUsbHandler); + + mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS, + UsbManager.FUNCTION_MTP)); + assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_MTP, 0); + + mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_UPDATE_STATE, 0, 0)); + + assertEquals(mUsbHandler.getEnabledFunctions(), UsbManager.FUNCTION_NONE); + } + + @SmallTest + public void configuredSendsBroadcast() { + sendBootCompleteMessages(mUsbHandler); + mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS, + UsbManager.FUNCTION_MTP)); + assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_MTP, 0); + + mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_UPDATE_STATE, 1, 1)); + + assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_MTP, 0); + assertTrue(mUsbHandler.mBroadcastedIntent.getBooleanExtra(UsbManager.USB_CONNECTED, false)); + assertTrue(mUsbHandler.mBroadcastedIntent + .getBooleanExtra(UsbManager.USB_CONFIGURED, false)); + assertTrue(mUsbHandler.mBroadcastedIntent + .getBooleanExtra(UsbManager.USB_FUNCTION_MTP, false)); + } + + @SmallTest + public void setScreenUnlockedFunctions() { + sendBootCompleteMessages(mUsbHandler); + mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_UPDATE_SCREEN_LOCK, 0)); + + mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_SCREEN_UNLOCKED_FUNCTIONS, + UsbManager.FUNCTION_MTP)); + assertNotEquals(mUsbHandler.getScreenUnlockedFunctions() & UsbManager.FUNCTION_MTP, 0); + assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_MTP, 0); + verify(mEditor).putString(String.format(Locale.ENGLISH, + UsbDeviceManager.UNLOCKED_CONFIG_PREF, mUsbHandler.mCurrentUser), + UsbManager.USB_FUNCTION_MTP); + } + + @SmallTest + public void unlockScreen() { + when(mSharedPreferences.getString(String.format(Locale.ENGLISH, + UsbDeviceManager.UNLOCKED_CONFIG_PREF, mUsbHandler.mCurrentUser), "")) + .thenReturn(UsbManager.USB_FUNCTION_MTP); + sendBootCompleteMessages(mUsbHandler); + mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_UPDATE_SCREEN_LOCK, 0)); + + assertNotEquals(mUsbHandler.getScreenUnlockedFunctions() & UsbManager.FUNCTION_MTP, 0); + assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_MTP, 0); + } + + private static void sendBootCompleteMessages(Handler handler) { + handler.handleMessage(handler.obtainMessage(MSG_BOOT_COMPLETED)); + handler.handleMessage(handler.obtainMessage(MSG_SYSTEM_READY)); + } +}
\ No newline at end of file diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java index 099cfd457160..e692652c7ea4 100644 --- a/tests/net/java/com/android/server/connectivity/TetheringTest.java +++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java @@ -311,7 +311,7 @@ public class TetheringTest { // Emulate pressing the USB tethering button in Settings UI. mTethering.startTethering(TETHERING_USB, null, false); mLooper.dispatchAll(); - verify(mUsbManager, times(1)).setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false); + verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS); // Pretend we receive a USB connected broadcast. Here we also pretend // that the RNDIS function is somehow enabled, so that we see if we |