diff options
7 files changed, 321 insertions, 247 deletions
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl index 31a6a962e2b9..0fe112c33e27 100644 --- a/core/java/android/hardware/usb/IUsbManager.aidl +++ b/core/java/android/hardware/usb/IUsbManager.aidl @@ -82,6 +82,9 @@ interface IUsbManager      /* Clears default preferences and permissions for the package */      void clearDefaults(String packageName, int userId); +    /* Returns true if the specified USB function is enabled. */ +    boolean isFunctionEnabled(String function); +      /* Sets the current USB function. */      void setCurrentFunction(String function); diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java index c83f4668b81a..f58b9d6dd14e 100644 --- a/core/java/android/hardware/usb/UsbManager.java +++ b/core/java/android/hardware/usb/UsbManager.java @@ -22,7 +22,6 @@ import android.content.Context;  import android.os.Bundle;  import android.os.ParcelFileDescriptor;  import android.os.RemoteException; -import android.os.SystemProperties;  import android.util.Log;  import java.util.HashMap; @@ -54,8 +53,6 @@ public class UsbManager {       * <li> {@link #USB_CONNECTED} boolean indicating whether USB is connected or disconnected.       * <li> {@link #USB_CONFIGURED} boolean indicating whether USB is configured.       * currently zero if not configured, one for configured. -     * <li> {@link #USB_FUNCTION_MASS_STORAGE} boolean extra indicating whether the -     * mass storage function is enabled       * <li> {@link #USB_FUNCTION_ADB} boolean extra indicating whether the       * adb function is enabled       * <li> {@link #USB_FUNCTION_RNDIS} boolean extra indicating whether the @@ -152,12 +149,13 @@ public class UsbManager {      public static final String USB_DATA_UNLOCKED = "unlocked";      /** -     * Name of the USB mass storage USB function. -     * Used in extras for the {@link #ACTION_USB_STATE} broadcast +     * 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)}.       *       * {@hide}       */ -    public static final String USB_FUNCTION_MASS_STORAGE = "mass_storage"; +    public static final String USB_FUNCTION_NONE = "none";      /**       * Name of the adb USB function. @@ -218,15 +216,14 @@ public class UsbManager {      /**       * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} and       * {@link #ACTION_USB_DEVICE_DETACHED} broadcasts -     * containing the UsbDevice object for the device. +     * containing the {@link UsbDevice} object for the device.       */ -      public static final String EXTRA_DEVICE = "device";      /**       * Name of extra for {@link #ACTION_USB_ACCESSORY_ATTACHED} and       * {@link #ACTION_USB_ACCESSORY_DETACHED} broadcasts -     * containing the UsbAccessory object for the accessory. +     * containing the {@link UsbAccessory} object for the accessory.       */      public static final String EXTRA_ACCESSORY = "accessory"; @@ -238,23 +235,6 @@ public class UsbManager {       */      public static final String EXTRA_PERMISSION_GRANTED = "permission"; -    /** -     * The persistent property which stores whether adb is enabled or not. Other values are ignored. -     * Previously this value stored non-adb settings, but not anymore. -     * TODO: rename this to something adb specific, rather than using usb. -     * -     * {@hide} -     */ -    public static final String ADB_PERSISTENT_PROPERTY = "persist.sys.usb.config"; - -    /** -     * The non-persistent property which stores the current USB settings. -     * -     * {@hide} -     */ -    public static final String USB_SETTINGS_PROPERTY = "sys.usb.config"; - -      private final Context mContext;      private final IUsbManager mService; @@ -437,31 +417,44 @@ public class UsbManager {          }      } -    private static boolean propertyContainsFunction(String property, String function) { -        String functions = SystemProperties.get(property, ""); -        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; -    } -      /** -     * Returns true if the specified USB function is currently enabled. +     * Returns true if the specified USB function is currently enabled when in device mode. +     * <p> +     * USB functions represent interfaces which are published to the host to access +     * services offered by the device. +     * </p>       *       * @param function name of the USB function -     * @return true if the USB function is enabled. +     * @return true if the USB function is enabled       *       * {@hide}       */      public boolean isFunctionEnabled(String function) { -        return propertyContainsFunction(USB_SETTINGS_PROPERTY, function); +        try { +            return mService.isFunctionEnabled(function); +        } catch (RemoteException e) { +            Log.e(TAG, "RemoteException in setCurrentFunction", e); +            return false; +        }      }      /** -     * Sets the current USB function. -     * If function is null, then the current function is set to the default function. +     * Sets the current USB function when in device mode. +     * <p> +     * USB functions represent interfaces which are published to the host to access +     * services offered by the device. +     * </p><p> +     * This method is intended to select among primary USB functions.  The system may +     * 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> +     * 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       * @@ -477,8 +470,9 @@ public class UsbManager {      /**       * Sets whether USB data (for example, MTP exposed pictures) should be made available -     * on the USB connection. Unlocking usb data should only be done with user involvement, -     * since exposing pictures or other data could leak sensitive user information. +     * 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.       *       * {@hide}       */ @@ -491,7 +485,8 @@ public class UsbManager {      }      /** -     * Returns {@code true} iff access to sensitive USB data is currently allowed. +     * Returns {@code true} iff access to sensitive USB data is currently allowed when +     * in device mode.       *       * {@hide}       */ @@ -504,4 +499,51 @@ public class UsbManager {          return false;      } +    /** @hide */ +    public static String addFunction(String functions, String function) { +        if ("none".equals(functions)) { +            return function; +        } +        if (!containsFunction(functions, function)) { +            if (functions.length() > 0) { +                functions += ","; +            } +            functions += function; +        } +        return functions; +    } + +    /** @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; +            } +        } +        if (split.length == 1 && split[0] == null) { +            return "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(); +    } + +    /** @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; +    }  } diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 680a1ab7d564..f6cdb3131cfb 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -2879,8 +2879,6 @@      <string name="usb_ptp_notification_title">USB for photo transfer</string>      <!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in MIDI mode.  This is the title -->      <string name="usb_midi_notification_title">USB for MIDI</string> -    <!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in mass storage mode (for installer CD image).  This is the title --> -    <string name="usb_cd_installer_notification_title">Connected as an installer</string>      <!-- USB_PREFERENCES: Notification for when a USB accessory is attached.  This is the title -->      <string name="usb_accessory_notification_title">Connected to a USB accessory</string>      <!-- See USB_PREFERENCES. This is the message. --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 5de010d222cc..fcdaba29c02f 100755 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1799,7 +1799,6 @@    <java-symbol type="string" name="tethered_notification_message" />    <java-symbol type="string" name="tethered_notification_title" />    <java-symbol type="string" name="usb_accessory_notification_title" /> -  <java-symbol type="string" name="usb_cd_installer_notification_title" />    <java-symbol type="string" name="usb_mtp_notification_title" />    <java-symbol type="string" name="usb_charging_notification_title" />    <java-symbol type="string" name="usb_notification_message" /> diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 5040bd036a18..c3174a398f83 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -60,7 +60,6 @@ import android.content.pm.ServiceInfo;  import android.content.pm.UserInfo;  import android.database.ContentObserver;  import android.graphics.Bitmap; -import android.hardware.usb.UsbManager;  import android.media.AudioManager;  import android.media.IAudioService;  import android.net.ConnectivityManager; @@ -5434,10 +5433,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {                          Settings.Secure.putIntForUser(mContext.getContentResolver(),                                  Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0,                                  userHandle); -                    } else if (UserManager.DISALLOW_USB_FILE_TRANSFER.equals(key)) { -                        UsbManager manager = -                                (UsbManager) mContext.getSystemService(Context.USB_SERVICE); -                        manager.setCurrentFunction("none");                      } else if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) {                          Settings.Secure.putIntForUser(mContext.getContentResolver(),                                  Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF, diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index e7716c234d40..81b4857351c0 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -19,12 +19,10 @@ package com.android.server.usb;  import android.app.Notification;  import android.app.NotificationManager;  import android.app.PendingIntent; -import android.content.BroadcastReceiver;  import android.content.ComponentName;  import android.content.ContentResolver;  import android.content.Context;  import android.content.Intent; -import android.content.IntentFilter;  import android.content.pm.PackageManager;  import android.content.res.Resources;  import android.database.ContentObserver; @@ -54,7 +52,6 @@ import java.io.FileDescriptor;  import java.io.FileNotFoundException;  import java.io.IOException;  import java.io.PrintWriter; -import java.util.Arrays;  import java.util.HashMap;  import java.util.LinkedList;  import java.util.List; @@ -67,9 +64,25 @@ import java.util.Scanner;   */  public class UsbDeviceManager { -    private static final String TAG = UsbDeviceManager.class.getSimpleName(); +    private static final String TAG = "UsbDeviceManager";      private static final boolean DEBUG = false; +    /** +     * The persistent property which stores whether adb is enabled or not. +     * May also contain vendor-specific default functions for testing purposes. +     */ +    private static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config"; + +    /** +     * The non-persistent property which stores the current USB settings. +     */ +    private static final String USB_CONFIG_PROPERTY = "sys.usb.config"; + +    /** +     * The non-persistent property which stores the current USB actual state. +     */ +    private static final String USB_STATE_PROPERTY = "sys.usb.state"; +      private static final String USB_STATE_MATCH =              "DEVPATH=/devices/virtual/android_usb/android0";      private static final String ACCESSORY_START_MATCH = @@ -92,6 +105,7 @@ public class UsbDeviceManager {      private static final int MSG_BOOT_COMPLETED = 4;      private static final int MSG_USER_SWITCHED = 5;      private static final int MSG_SET_USB_DATA_UNLOCKED = 6; +    private static final int MSG_UPDATE_USER_RESTRICTIONS = 7;      private static final int AUDIO_MODE_SOURCE = 1; @@ -184,12 +198,6 @@ public class UsbDeviceManager {          }      } -    public void setCurrentSettings(UsbSettingsManager settings) { -        synchronized (mLock) { -            mCurrentSettings = settings; -        } -    } -      private UsbSettingsManager getCurrentSettings() {          synchronized (mLock) {              return mCurrentSettings; @@ -221,6 +229,22 @@ public class UsbDeviceManager {          mHandler.sendEmptyMessage(MSG_SYSTEM_READY);      } +    public void bootCompleted() { +        if (DEBUG) Slog.d(TAG, "boot completed"); +        mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED); +    } + +    public void setCurrentUser(int userId, UsbSettingsManager settings) { +        synchronized (mLock) { +            mCurrentSettings = settings; +            mHandler.obtainMessage(MSG_USER_SWITCHED, userId, 0).sendToTarget(); +        } +    } + +    public void updateUserRestrictions() { +        mHandler.sendEmptyMessage(MSG_UPDATE_USER_RESTRICTIONS); +    } +      private void startAccessoryMode() {          if (!mHasUsbAccessory) return; @@ -270,46 +294,6 @@ public class UsbDeviceManager {          }      } -     private static String addFunction(String functions, String function) { -         if ("none".equals(functions)) { -             return function; -         } -        if (!containsFunction(functions, function)) { -            if (functions.length() > 0) { -                functions += ","; -            } -            functions += function; -        } -        return functions; -    } - -    private 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; -            } -        } -        if (split.length == 1 && split[0] == null) { -            return "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 static boolean containsFunction(String functions, String function) { -        return Arrays.asList(functions.split(",")).contains(function); -    } -      private final class UsbHandler extends Handler {          // current USB state @@ -317,49 +301,24 @@ public class UsbDeviceManager {          private boolean mConfigured;          private boolean mUsbDataUnlocked;          private String mCurrentFunctions; +        private boolean mCurrentFunctionsApplied;          private UsbAccessory mCurrentAccessory;          private int mUsbNotificationId; -        private String mDefaultFunctions;          private boolean mAdbNotificationShown;          private int mCurrentUser = UserHandle.USER_NULL; -        private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() { -            @Override -            public void onReceive(Context context, Intent intent) { -                if (DEBUG) Slog.d(TAG, "boot completed"); -                mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED); -            } -        }; - -        private final BroadcastReceiver mUserSwitchedReceiver = new BroadcastReceiver() { -            @Override -            public void onReceive(Context context, Intent intent) { -                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); -                mHandler.obtainMessage(MSG_USER_SWITCHED, userId, 0).sendToTarget(); -            } -        }; -          public UsbHandler(Looper looper) {              super(looper);              try { -                // TODO: rename persist.sys.usb.config to something more descriptive. -                // persist.sys.usb.config should never be unset.  But if it is, set it to "adb" -                // so we have a chance of debugging what happened. -                mDefaultFunctions = SystemProperties.get("persist.sys.usb.config", "adb"); - -                // sanity check the sys.usb.config system property -                // this may be necessary if we crashed while switching USB configurations -                String config = SystemProperties.get("sys.usb.config", "none"); -                if (!config.equals(mDefaultFunctions)) { -                    Slog.w(TAG, "resetting config to persistent property: " + mDefaultFunctions); -                    SystemProperties.set("sys.usb.config", mDefaultFunctions); -                } - -                mAdbEnabled = containsFunction( -                        SystemProperties.get(UsbManager.ADB_PERSISTENT_PROPERTY, "adb"), +                // Restore default functions. +                mCurrentFunctions = SystemProperties.get(USB_CONFIG_PROPERTY, +                        UsbManager.USB_FUNCTION_NONE); +                mCurrentFunctionsApplied = mCurrentFunctions.equals( +                        SystemProperties.get(USB_STATE_PROPERTY)); +                mAdbEnabled = UsbManager.containsFunction(getDefaultFunctions(),                          UsbManager.USB_FUNCTION_ADB); +                setEnabledFunctions(null, false); -                mCurrentFunctions = getDefaultFunctions();                  String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();                  updateState(state); @@ -371,12 +330,6 @@ public class UsbDeviceManager {                  // Watch for USB configuration changes                  mUEventObserver.startObserving(USB_STATE_MATCH);                  mUEventObserver.startObserving(ACCESSORY_START_MATCH); - -                IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED); -                filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); -                mContext.registerReceiver(mBootCompletedReceiver, filter); -                mContext.registerReceiver( -                        mUserSwitchedReceiver, new IntentFilter(Intent.ACTION_USER_SWITCHED));              } catch (Exception e) {                  Slog.e(TAG, "Error initializing UsbHandler", e);              } @@ -420,34 +373,26 @@ public class UsbDeviceManager {              sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);          } -        private void updatePersistentProperty() { -            String newValue = getDefaultFunctions(); -            String value = SystemProperties.get(UsbManager.ADB_PERSISTENT_PROPERTY); -            if (DEBUG) { Slog.d(TAG, "updatePersistentProperty newValue=" + newValue + " value=" + value); } -            if (!newValue.equals(value)) { -                SystemProperties.set(UsbManager.ADB_PERSISTENT_PROPERTY, getDefaultFunctions()); -            } -            waitForState(newValue); -        } -          private boolean waitForState(String state) {              // wait for the transition to complete.              // give up after 1 second. +            String value = null;              for (int i = 0; i < 20; i++) {                  // State transition is done when sys.usb.state is set to the new configuration -                if (state.equals(SystemProperties.get("sys.usb.state"))) return true; +                value = SystemProperties.get(USB_STATE_PROPERTY); +                if (state.equals(value)) return true;                  SystemClock.sleep(50);              } -            Slog.e(TAG, "waitForState(" + state + ") FAILED"); +            Slog.e(TAG, "waitForState(" + state + ") FAILED: got " + value);              return false;          }          private boolean setUsbConfig(String config) {              if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");              // set the new configuration -            String oldConfig = SystemProperties.get(UsbManager.USB_SETTINGS_PROPERTY); +            String oldConfig = SystemProperties.get(USB_CONFIG_PROPERTY);              if (!config.equals(oldConfig)) { -                SystemProperties.set(UsbManager.USB_SETTINGS_PROPERTY, config); +                SystemProperties.set(USB_CONFIG_PROPERTY, config);              }              return waitForState(config);          } @@ -456,54 +401,110 @@ public class UsbDeviceManager {              if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable);              if (enable != mAdbEnabled) {                  mAdbEnabled = enable; +                  // Due to the persist.sys.usb.config property trigger, changing adb state requires                  // persisting default function -                updatePersistentProperty(); +                String oldFunctions = getDefaultFunctions(); +                String newFunctions = applyAdbFunction(oldFunctions); +                if (!oldFunctions.equals(newFunctions)) { +                    SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY, newFunctions); +                } +                  // After persisting them use the lock-down aware function set -                setEnabledFunctions(getDefaultFunctions()); +                setEnabledFunctions(mCurrentFunctions, false);                  updateAdbNotification();              } +              if (mDebuggingManager != null) {                  mDebuggingManager.setAdbEnabled(mAdbEnabled);              }          }          /** -         * Stop and start the USB driver. This is needed to close all outstanding -         * USB connections. +         * Evaluates USB function policies and applies the change accordingly.           */ -        private void restartCurrentFunction() { -            setUsbConfig("none"); -            setUsbConfig(mCurrentFunctions); -        } +        private void setEnabledFunctions(String functions, boolean forceRestart) { +            if (DEBUG) Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", " +                    + "forceRestart=" + forceRestart); + +            // Try to set the enabled functions. +            final String oldFunctions = mCurrentFunctions; +            final boolean oldFunctionsApplied = mCurrentFunctionsApplied; +            if (trySetEnabledFunctions(functions, forceRestart)) { +                return; +            } -        private void setEnabledFunctions(String functions) { -            if (DEBUG) Slog.d(TAG, "setEnabledFunctions " + functions); +            // Didn't work.  Try to revert changes. +            // We always reapply the policy in case certain constraints changed such as +            // user restrictions independently of any other new functions we were +            // trying to activate. +            if (oldFunctionsApplied && !oldFunctions.equals(functions)) { +                Slog.e(TAG, "Failsafe 1: Restoring previous USB functions."); +                if (trySetEnabledFunctions(oldFunctions, false)) { +                    return; +                } +            } +            // Still didn't work.  Try to restore the default functions. +            Slog.e(TAG, "Failsafe 2: Restoring default USB functions."); +            if (trySetEnabledFunctions(null, false)) { +                return; +            } + +            // Now we're desperate.  Ignore the default functions. +            // 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)) { +                return; +            } + +            // Ouch. +            Slog.e(TAG, "Unable to set any USB functions!"); +        } + +        private boolean trySetEnabledFunctions(String functions, boolean forceRestart) {              if (functions == null) {                  functions = getDefaultFunctions();              } +            functions = applyAdbFunction(functions); +            functions = applyUserRestrictions(functions); + +            if (!mCurrentFunctions.equals(functions) || !mCurrentFunctionsApplied +                    || forceRestart) { +                Slog.i(TAG, "Setting USB config to " + functions); +                mCurrentFunctions = functions; +                mCurrentFunctionsApplied = false; + +                // Kick the USB stack to close existing connections. +                setUsbConfig(UsbManager.USB_FUNCTION_NONE); + +                // Set the new USB configuration. +                if (!setUsbConfig(functions)) { +                    Slog.e(TAG, "Failed to switch USB config to " + functions); +                    return false; +                } + +                mCurrentFunctionsApplied = true; +            } +            return true; +        } +        private String applyAdbFunction(String functions) {              if (mAdbEnabled) { -                functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB); +                functions = UsbManager.addFunction(functions, UsbManager.USB_FUNCTION_ADB);              } else { -                functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB); +                functions = UsbManager.removeFunction(functions, UsbManager.USB_FUNCTION_ADB);              } -            if (!mCurrentFunctions.equals(functions)) { -                if (!setUsbConfig("none")) { -                    Slog.e(TAG, "Failed to disable USB"); -                    // revert to previous configuration if we fail -                    setUsbConfig(mCurrentFunctions); -                    return; -                } -                if (setUsbConfig(functions)) { -                    mCurrentFunctions = functions; -                } else { -                    Slog.e(TAG, "Failed to switch USB config to " + functions); -                    // revert to previous configuration if we fail -                    setUsbConfig(mCurrentFunctions); -                } +            return functions; +        } + +        private String applyUserRestrictions(String functions) { +            UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); +            if (userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER)) { +                functions = UsbManager.removeFunction(functions, UsbManager.USB_FUNCTION_MTP); +                functions = UsbManager.removeFunction(functions, UsbManager.USB_FUNCTION_PTP);              } +           return functions;          }          private void updateCurrentAccessory() { @@ -523,7 +524,7 @@ public class UsbDeviceManager {                      // defer accessoryAttached if system is not ready                      if (mBootCompleted) {                          getCurrentSettings().accessoryAttached(mCurrentAccessory); -                    } // else handle in mBootCompletedReceiver +                    } // else handle in boot completed                  } else {                      Slog.e(TAG, "nativeGetAccessoryStrings failed");                  } @@ -531,7 +532,7 @@ public class UsbDeviceManager {                  // make sure accessory mode is off                  // and restore default functions                  Slog.d(TAG, "exited USB accessory mode"); -                setEnabledFunctions(getDefaultFunctions()); +                setEnabledFunctions(null, false);                  if (mCurrentAccessory != null) {                      if (mBootCompleted) { @@ -543,10 +544,11 @@ public class UsbDeviceManager {              }          } -        private void updateUsbState() { +        private void updateUsbStateBroadcast() {              // send a sticky broadcast containing current USB state              Intent intent = new Intent(UsbManager.ACTION_USB_STATE); -            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); +            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING +                    | Intent.FLAG_RECEIVER_FOREGROUND);              intent.putExtra(UsbManager.USB_CONNECTED, mConnected);              intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);              intent.putExtra(UsbManager.USB_DATA_UNLOCKED, mUsbDataUnlocked); @@ -563,8 +565,13 @@ public class UsbDeviceManager {              mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);          } +        private void updateUsbFunctions() { +            updateAudioSourceFunction(); +            updateMidiFunction(); +        } +          private void updateAudioSourceFunction() { -            boolean enabled = containsFunction(mCurrentFunctions, +            boolean enabled = UsbManager.containsFunction(mCurrentFunctions,                      UsbManager.USB_FUNCTION_AUDIO_SOURCE);              if (enabled != mAudioSourceEnabled) {                  int card = -1; @@ -590,7 +597,8 @@ public class UsbDeviceManager {          }          private void updateMidiFunction() { -            boolean enabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MIDI); +            boolean enabled = UsbManager.containsFunction(mCurrentFunctions, +                    UsbManager.USB_FUNCTION_MIDI);              if (enabled != mMidiEnabled) {                  if (enabled) {                      Scanner scanner = null; @@ -624,17 +632,16 @@ public class UsbDeviceManager {                      }                      updateUsbNotification();                      updateAdbNotification(); -                    if (containsFunction(mCurrentFunctions, +                    if (UsbManager.containsFunction(mCurrentFunctions,                              UsbManager.USB_FUNCTION_ACCESSORY)) {                          updateCurrentAccessory();                      } else if (!mConnected) {                          // restore defaults when USB is disconnected -                        setEnabledFunctions(getDefaultFunctions()); +                        setEnabledFunctions(null, false);                      }                      if (mBootCompleted) { -                        updateUsbState(); -                        updateAudioSourceFunction(); -                        updateMidiFunction(); +                        updateUsbStateBroadcast(); +                        updateUsbFunctions();                      }                      break;                  case MSG_ENABLE_ADB: @@ -642,26 +649,25 @@ public class UsbDeviceManager {                      break;                  case MSG_SET_CURRENT_FUNCTIONS:                      String functions = (String)msg.obj; -                    setEnabledFunctions(functions); +                    setEnabledFunctions(functions, false); +                    break; +                case MSG_UPDATE_USER_RESTRICTIONS: +                    setEnabledFunctions(mCurrentFunctions, false);                      break;                  case MSG_SET_USB_DATA_UNLOCKED:                      mUsbDataUnlocked = (msg.arg1 == 1);                      updateUsbNotification(); -                    updateUsbState(); -                    restartCurrentFunction(); +                    updateUsbStateBroadcast(); +                    setEnabledFunctions(mCurrentFunctions, true);                      break;                  case MSG_SYSTEM_READY: -                    setUsbConfig(mCurrentFunctions); -                    updatePersistentProperty();                      updateUsbNotification();                      updateAdbNotification(); -                    updateUsbState(); -                    updateAudioSourceFunction(); -                    updateMidiFunction(); +                    updateUsbStateBroadcast(); +                    updateUsbFunctions();                      break;                  case MSG_BOOT_COMPLETED:                      mBootCompleted = true; -                    setUsbConfig(mCurrentFunctions);                      if (mCurrentAccessory != null) {                          getCurrentSettings().accessoryAttached(mCurrentAccessory);                      } @@ -670,27 +676,19 @@ public class UsbDeviceManager {                      }                      break;                  case MSG_USER_SWITCHED: { -                    UserManager userManager = -                            (UserManager) mContext.getSystemService(Context.USER_SERVICE); -                    UserHandle userHandle = new UserHandle(msg.arg1); -                    if (userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER, -                            userHandle)) { -                        Slog.v(TAG, "Switched to user " + msg.arg1 + -                                " with DISALLOW_USB_FILE_TRANSFER restriction; disabling USB."); -                        setUsbConfig("none"); +                    if (mCurrentUser != msg.arg1) { +                        // Restart the USB stack and re-apply user restrictions for MTP or PTP. +                        final boolean active = UsbManager.containsFunction(mCurrentFunctions, +                                        UsbManager.USB_FUNCTION_MTP) +                                || UsbManager.containsFunction(mCurrentFunctions, +                                        UsbManager.USB_FUNCTION_PTP); +                        if (active && mCurrentUser != UserHandle.USER_NULL) { +                            Slog.v(TAG, "Current user switched to " + mCurrentUser +                                    + "; resetting USB host stack for MTP or PTP"); +                            setEnabledFunctions(mCurrentFunctions, true); +                        }                          mCurrentUser = msg.arg1; -                        break; -                    } - -                    final boolean mtpActive = -                            containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP) -                            || containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP); -                    if (mtpActive && mCurrentUser != UserHandle.USER_NULL) { -                        Slog.v(TAG, "Current user switched; resetting USB host stack for MTP"); -                        setUsbConfig("none"); -                        setUsbConfig(mCurrentFunctions);                      } -                    mCurrentUser = msg.arg1;                      break;                  }              } @@ -707,16 +705,17 @@ public class UsbDeviceManager {              if (mConnected) {                  if (!mUsbDataUnlocked) {                      id = com.android.internal.R.string.usb_charging_notification_title; -                } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)) { +                } else if (UsbManager.containsFunction(mCurrentFunctions, +                        UsbManager.USB_FUNCTION_MTP)) {                      id = com.android.internal.R.string.usb_mtp_notification_title; -                } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP)) { +                } else if (UsbManager.containsFunction(mCurrentFunctions, +                        UsbManager.USB_FUNCTION_PTP)) {                      id = com.android.internal.R.string.usb_ptp_notification_title; -                } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MIDI)) { +                } else if (UsbManager.containsFunction(mCurrentFunctions, +                        UsbManager.USB_FUNCTION_MIDI)) {                      id = com.android.internal.R.string.usb_midi_notification_title; -                } else if (containsFunction(mCurrentFunctions, -                        UsbManager.USB_FUNCTION_MASS_STORAGE)) { -                    id = com.android.internal.R.string.usb_cd_installer_notification_title; -                } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ACCESSORY)) { +                } else if (UsbManager.containsFunction(mCurrentFunctions, +                        UsbManager.USB_FUNCTION_ACCESSORY)) {                      id = com.android.internal.R.string.usb_accessory_notification_title;                  } else {                      id = com.android.internal.R.string.usb_charging_notification_title; @@ -804,17 +803,14 @@ public class UsbDeviceManager {          }          private String getDefaultFunctions() { -            UserManager userManager = (UserManager)mContext.getSystemService(Context.USER_SERVICE); -            if(userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER, -                new UserHandle(mCurrentUser))) { -               return "none"; -             } -             return mDefaultFunctions; +            return SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY, +                    UsbManager.USB_FUNCTION_ADB);          }          public void dump(FileDescriptor fd, PrintWriter pw) {              pw.println("  USB Device State:"); -            pw.println("    Current Functions: " + mCurrentFunctions); +            pw.println("    mCurrentFunctions: " + mCurrentFunctions); +            pw.println("    mCurrentFunctionsApplied: " + mCurrentFunctionsApplied);              pw.println("    mConnected: " + mConnected);              pw.println("    mConfigured: " + mConfigured);              pw.println("    mCurrentAccessory: " + mCurrentAccessory); @@ -850,6 +846,10 @@ public class UsbDeviceManager {          return nativeOpenAccessory();      } +    public boolean isFunctionEnabled(String function) { +        return UsbManager.containsFunction(SystemProperties.get(USB_CONFIG_PROPERTY), function); +    } +      public void setCurrentFunctions(String functions) {          if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ")");          mHandler.sendMessage(MSG_SET_CURRENT_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 7a3426c5e18e..f82a4dd03158 100644 --- a/services/usb/java/com/android/server/usb/UsbService.java +++ b/services/usb/java/com/android/server/usb/UsbService.java @@ -17,6 +17,7 @@  package com.android.server.usb;  import android.app.PendingIntent; +import android.app.admin.DevicePolicyManager;  import android.content.BroadcastReceiver;  import android.content.Context;  import android.content.Intent; @@ -25,10 +26,11 @@ import android.content.pm.PackageManager;  import android.hardware.usb.IUsbManager;  import android.hardware.usb.UsbAccessory;  import android.hardware.usb.UsbDevice; +import android.hardware.usb.UsbManager;  import android.os.Bundle;  import android.os.ParcelFileDescriptor;  import android.os.UserHandle; -import android.os.UserManager; +import android.util.Slog;  import android.util.SparseArray;  import com.android.internal.annotations.GuardedBy; @@ -63,6 +65,8 @@ public class UsbService extends IUsbManager.Stub {          public void onBootPhase(int phase) {              if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {                  mUsbService.systemReady(); +            } else if (phase == SystemService.PHASE_BOOT_COMPLETED) { +                mUsbService.bootCompleted();              }          }      } @@ -108,13 +112,15 @@ public class UsbService extends IUsbManager.Stub {          setCurrentUser(UserHandle.USER_OWNER); -        final IntentFilter userFilter = new IntentFilter(); -        userFilter.addAction(Intent.ACTION_USER_SWITCHED); -        userFilter.addAction(Intent.ACTION_USER_STOPPED); -        mContext.registerReceiver(mUserReceiver, userFilter, null, null); +        final IntentFilter filter = new IntentFilter(); +        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); +        filter.addAction(Intent.ACTION_USER_SWITCHED); +        filter.addAction(Intent.ACTION_USER_STOPPED); +        filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); +        mContext.registerReceiver(mReceiver, filter, null, null);      } -    private BroadcastReceiver mUserReceiver = new BroadcastReceiver() { +    private BroadcastReceiver mReceiver = new BroadcastReceiver() {          @Override          public void onReceive(Context context, Intent intent) {              final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); @@ -125,6 +131,11 @@ public class UsbService extends IUsbManager.Stub {                  synchronized (mLock) {                      mSettingsByUser.remove(userId);                  } +            } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED +                    .equals(action)) { +                if (mDeviceManager != null) { +                    mDeviceManager.updateUserRestrictions(); +                }              }          }      }; @@ -135,7 +146,7 @@ public class UsbService extends IUsbManager.Stub {              mHostManager.setCurrentSettings(userSettings);          }          if (mDeviceManager != null) { -            mDeviceManager.setCurrentSettings(userSettings); +            mDeviceManager.setCurrentUser(userId, userSettings);          }      } @@ -150,6 +161,12 @@ public class UsbService extends IUsbManager.Stub {          }      } +    public void bootCompleted() { +        if (mDeviceManager != null) { +            mDeviceManager.bootCompleted(); +        } +    } +      /* Returns a list of all currently attached USB devices (host mdoe) */      @Override      public void getDeviceList(Bundle devices) { @@ -252,15 +269,19 @@ public class UsbService extends IUsbManager.Stub {      }      @Override +    public boolean isFunctionEnabled(String function) { +        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); +        return mDeviceManager != null && mDeviceManager.isFunctionEnabled(function); +    } + +    @Override      public void setCurrentFunction(String function) {          mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); -        // If attempt to change USB function while file transfer is restricted, ensure that -        // the current function is set to "none", and return. -        UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); -        if (userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER)) { -            if (mDeviceManager != null) mDeviceManager.setCurrentFunctions("none"); -            return; +        if (!isSupportedCurrentFunction(function)) { +            Slog.w(TAG, "Caller of setCurrentFunction() requested unsupported USB function: " +                    + function); +            function = UsbManager.USB_FUNCTION_NONE;          }          if (mDeviceManager != null) { @@ -270,6 +291,22 @@ public class UsbService extends IUsbManager.Stub {          }      } +    private static boolean isSupportedCurrentFunction(String function) { +        if (function == null) return true; + +        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; +        } + +        return false; +    } +      @Override      public void setUsbDataUnlocked(boolean unlocked) {          mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);  |