diff options
-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 |