Modify how USB connections are handled.

* Introduce a new "charger only" mode. In this mode, MTP is disabled,
and no file transfers can occur.
* Make charger only mode the default.
* Modify "persist.sys.usb.config" so it now only holds the adb status.
* Make the USB settings non-persistent. Unplugging the USB connection will
reset the device back to "charger only" mode.
* Fixup wording per UI guidelines.

TODO: Re-implement MDM restrictions for USB / MTP access controls.

Bug: 18905620
Change-Id: I99a50d9132a81e98187f431166fd9fef4d437e4f
This commit is contained in:
Nick Kralevich
2015-05-13 11:54:03 -07:00
parent 2047ce8240
commit fcf10f7c12
9 changed files with 93 additions and 152 deletions

View File

@@ -50,7 +50,7 @@ public class UsbCommand extends Svc.Command {
IUsbManager usbMgr = IUsbManager.Stub.asInterface(ServiceManager.getService(
Context.USB_SERVICE));
try {
usbMgr.setCurrentFunction((args.length >=3 ? args[2] : null), false);
usbMgr.setCurrentFunction((args.length >=3 ? args[2] : null));
} catch (RemoteException e) {
System.err.println("Error communicating with UsbManager: " + e);
}

View File

@@ -83,7 +83,7 @@ interface IUsbManager
void clearDefaults(String packageName, int userId);
/* Sets the current USB function. */
void setCurrentFunction(String function, boolean makeDefault);
void setCurrentFunction(String function);
/* 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.

View File

@@ -228,6 +228,23 @@ 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;
@@ -410,21 +427,26 @@ 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 the current default USB function.
* Returns true if the specified USB function is currently enabled.
*
* @return name of the default function.
* @param function name of the USB function
* @return true if the USB function is enabled.
*
* {@hide}
*/
public String getDefaultFunction() {
String functions = SystemProperties.get("persist.sys.usb.config", "");
int commaIndex = functions.indexOf(',');
if (commaIndex > 0) {
return functions.substring(0, commaIndex);
} else {
return functions;
}
public boolean isFunctionEnabled(String function) {
return propertyContainsFunction(USB_SETTINGS_PROPERTY, function);
}
/**
@@ -432,13 +454,12 @@ public class UsbManager {
* If function is null, then the current function is set to the default function.
*
* @param function name of the USB function, or null to restore the default function
* @param makeDefault true if the function should be set as the new default function
*
* {@hide}
*/
public void setCurrentFunction(String function, boolean makeDefault) {
public void setCurrentFunction(String function) {
try {
mService.setCurrentFunction(function, makeDefault);
mService.setCurrentFunction(function);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in setCurrentFunction", e);
}

View File

@@ -2916,18 +2916,20 @@
<!-- USB_STORAGE_ERROR dialog ok button-->
<string name="dlg_ok">OK</string>
<!-- USB_PREFERENCES: Notification for when the user connected to the charger only. This is the title -->
<string name="usb_charging_notification_title">USB for charging</string>
<!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in MTP mode. This is the title -->
<string name="usb_mtp_notification_title">Connected as a media device</string>
<string name="usb_mtp_notification_title">USB for file transfer</string>
<!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in PTP mode. This is the title -->
<string name="usb_ptp_notification_title">Connected as a camera</string>
<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">Connected as a MIDI device</string>
<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. -->
<string name="usb_notification_message">Touch for other USB options.</string>
<string name="usb_notification_message">Touch for more options.</string>
<!-- External media format dialog strings -->
<!-- This is the label for the activity, and should never be visible to the user. -->

View File

@@ -1790,6 +1790,7 @@
<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" />
<java-symbol type="string" name="use_physical_keyboard" />
<java-symbol type="string" name="usb_ptp_notification_title" />

View File

@@ -608,12 +608,12 @@ public class Tethering extends BaseNetworkObserver {
tetherUsb(true);
} else {
mUsbTetherRequested = true;
usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false);
usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS);
}
} else {
tetherUsb(false);
if (mRndisEnabled) {
usbManager.setCurrentFunction(null, false);
usbManager.setCurrentFunction(null);
}
mUsbTetherRequested = false;
}

View File

@@ -5362,7 +5362,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
} else if (UserManager.DISALLOW_USB_FILE_TRANSFER.equals(key)) {
UsbManager manager =
(UsbManager) mContext.getSystemService(Context.USB_SERVICE);
manager.setCurrentFunction("none", false);
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,

View File

@@ -92,7 +92,6 @@ public class UsbDeviceManager {
private static final int MSG_BOOT_COMPLETED = 4;
private static final int MSG_USER_SWITCHED = 5;
private static final int AUDIO_MODE_NONE = 0;
private static final int AUDIO_MODE_SOURCE = 1;
// Delay for debouncing USB disconnects.
@@ -107,8 +106,6 @@ public class UsbDeviceManager {
// Request is cancelled if host does not configure device within 10 seconds.
private static final int ACCESSORY_REQUEST_TIMEOUT = 10 * 1000;
private static final String BOOT_MODE_PROPERTY = "ro.bootmode";
private UsbHandler mHandler;
private boolean mBootCompleted;
@@ -245,7 +242,7 @@ public class UsbDeviceManager {
if (functions != null) {
mAccessoryModeRequestTime = SystemClock.elapsedRealtime();
setCurrentFunctions(functions, false);
setCurrentFunctions(functions);
}
}
@@ -318,7 +315,6 @@ public class UsbDeviceManager {
private boolean mConnected;
private boolean mConfigured;
private String mCurrentFunctions;
private String mDefaultFunctions;
private UsbAccessory mCurrentAccessory;
private int mUsbNotificationId;
private boolean mAdbNotificationShown;
@@ -343,25 +339,20 @@ public class UsbDeviceManager {
public UsbHandler(Looper looper) {
super(looper);
try {
// Special note about persist.sys.usb.config: We only ever look at the adb value
// from that property. Other values are ignored. persist.sys.usb.config is now
// only used to determine if adb is enabled or not.
// 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");
// Check if USB mode needs to be overridden depending on OEM specific bootmode.
mDefaultFunctions = processOemUsbOverride(mDefaultFunctions);
mAdbEnabled = containsFunction(
SystemProperties.get(UsbManager.ADB_PERSISTENT_PROPERTY, "adb"),
UsbManager.USB_FUNCTION_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);
}
mCurrentFunctions = getDefaultFunctions();
mCurrentFunctions = mAdbEnabled ? "adb" : "none";
String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
updateState(state);
mAdbEnabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
// register observer to listen for settings changes
mContentResolver.registerContentObserver(
@@ -396,14 +387,6 @@ public class UsbDeviceManager {
sendMessage(m);
}
public void sendMessage(int what, Object arg0, boolean arg1) {
removeMessages(what);
Message m = Message.obtain(this, what);
m.obj = arg0;
m.arg1 = (arg1 ? 1 : 0);
sendMessage(m);
}
public void updateState(String state) {
int connected, configured;
@@ -443,7 +426,7 @@ public class UsbDeviceManager {
private boolean setUsbConfig(String config) {
if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
// set the new configuration
SystemProperties.set("sys.usb.config", config);
SystemProperties.set(UsbManager.USB_SETTINGS_PROPERTY, config);
return waitForState(config);
}
@@ -453,9 +436,9 @@ public class UsbDeviceManager {
mAdbEnabled = enable;
// Due to the persist.sys.usb.config property trigger, changing adb state requires
// persisting default function
setEnabledFunctions(mDefaultFunctions, true);
SystemProperties.set(UsbManager.ADB_PERSISTENT_PROPERTY, mAdbEnabled ? "adb" : "none");
// After persisting them use the lock-down aware function set
setEnabledFunctions(getDefaultFunctions(), false);
setEnabledFunctions(getDefaultFunctions());
updateAdbNotification();
}
if (mDebuggingManager != null) {
@@ -463,65 +446,31 @@ public class UsbDeviceManager {
}
}
private void setEnabledFunctions(String functions, boolean makeDefault) {
if (DEBUG) Slog.d(TAG, "setEnabledFunctions " + functions
+ " makeDefault: " + makeDefault);
private void setEnabledFunctions(String functions) {
if (DEBUG) Slog.d(TAG, "setEnabledFunctions " + functions);
// Do not update persystent.sys.usb.config if the device is booted up
// with OEM specific mode.
if (functions != null && makeDefault && !needsOemUsbOverride()) {
if (functions == null) {
functions = "none";
}
if (mAdbEnabled) {
functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
} else {
functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
}
if (!mDefaultFunctions.equals(functions)) {
if (!setUsbConfig("none")) {
Slog.e(TAG, "Failed to disable USB");
// revert to previous configuration if we fail
setUsbConfig(mCurrentFunctions);
return;
}
// setting this property will also change the current USB state
// via a property trigger
SystemProperties.set("persist.sys.usb.config", functions);
if (waitForState(functions)) {
mCurrentFunctions = functions;
mDefaultFunctions = functions;
} else {
Slog.e(TAG, "Failed to switch persistent USB config to " + functions);
// revert to previous configuration if we fail
SystemProperties.set("persist.sys.usb.config", mDefaultFunctions);
}
}
if (mAdbEnabled) {
functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
} else {
if (functions == null) {
functions = mDefaultFunctions;
functions = 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;
}
// Override with bootmode specific usb mode if needed
functions = processOemUsbOverride(functions);
if (mAdbEnabled) {
functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
if (setUsbConfig(functions)) {
mCurrentFunctions = functions;
} else {
functions = 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);
}
Slog.e(TAG, "Failed to switch USB config to " + functions);
// revert to previous configuration if we fail
setUsbConfig(mCurrentFunctions);
}
}
}
@@ -551,7 +500,7 @@ public class UsbDeviceManager {
// make sure accessory mode is off
// and restore default functions
Slog.d(TAG, "exited USB accessory mode");
setEnabledFunctions(getDefaultFunctions(), false);
setEnabledFunctions(getDefaultFunctions());
if (mCurrentAccessory != null) {
if (mBootCompleted) {
@@ -644,7 +593,7 @@ public class UsbDeviceManager {
updateCurrentAccessory();
} else if (!mConnected) {
// restore defaults when USB is disconnected
setEnabledFunctions(getDefaultFunctions(), false);
setEnabledFunctions(getDefaultFunctions());
}
if (mBootCompleted) {
updateUsbState();
@@ -657,10 +606,11 @@ public class UsbDeviceManager {
break;
case MSG_SET_CURRENT_FUNCTIONS:
String functions = (String)msg.obj;
boolean makeDefault = (msg.arg1 == 1);
setEnabledFunctions(functions, makeDefault);
setEnabledFunctions(functions);
break;
case MSG_SYSTEM_READY:
setUsbConfig(mCurrentFunctions);
SystemProperties.set(UsbManager.ADB_PERSISTENT_PROPERTY, mAdbEnabled ? "adb" : "none");
updateUsbNotification();
updateAdbNotification();
updateUsbState();
@@ -669,6 +619,7 @@ public class UsbDeviceManager {
break;
case MSG_BOOT_COMPLETED:
mBootCompleted = true;
setUsbConfig(mCurrentFunctions);
if (mCurrentAccessory != null) {
getCurrentSettings().accessoryAttached(mCurrentAccessory);
}
@@ -724,10 +675,7 @@ public class UsbDeviceManager {
} else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ACCESSORY)) {
id = com.android.internal.R.string.usb_accessory_notification_title;
} else {
// There is a different notification for USB tethering so we don't need one here
//if (!containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_RNDIS)) {
// Slog.e(TAG, "No known USB function in updateUsbNotification");
//}
id = com.android.internal.R.string.usb_charging_notification_title;
}
}
if (id != mUsbNotificationId) {
@@ -754,7 +702,7 @@ public class UsbDeviceManager {
Intent intent = Intent.makeRestartActivityTask(
new ComponentName("com.android.settings",
"com.android.settings.UsbSettings"));
"com.android.settings.deviceinfo.UsbModeChooserActivity"));
PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
intent, 0, null, UserHandle.CURRENT);
notification.color = mContext.getColor(
@@ -810,18 +758,12 @@ 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 "none";
}
public void dump(FileDescriptor fd, PrintWriter pw) {
pw.println(" USB Device State:");
pw.println(" Current Functions: " + mCurrentFunctions);
pw.println(" Default Functions: " + mDefaultFunctions);
pw.println(" mConnected: " + mConnected);
pw.println(" mConfigured: " + mConfigured);
pw.println(" mCurrentAccessory: " + mCurrentAccessory);
@@ -857,9 +799,9 @@ public class UsbDeviceManager {
return nativeOpenAccessory();
}
public void setCurrentFunctions(String functions, boolean makeDefault) {
if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ") default: " + makeDefault);
mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, makeDefault);
public void setCurrentFunctions(String functions) {
if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ")");
mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions);
}
private void readOemUsbOverrideConfig() {
@@ -884,31 +826,6 @@ public class UsbDeviceManager {
}
}
private boolean needsOemUsbOverride() {
if (mOemModeMap == null) return false;
String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
return (mOemModeMap.get(bootMode) != null) ? true : false;
}
private String processOemUsbOverride(String usbFunctions) {
if ((usbFunctions == null) || (mOemModeMap == null)) return usbFunctions;
String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
List<Pair<String, String>> overrides = mOemModeMap.get(bootMode);
if (overrides != null) {
for (Pair<String, String> pair: overrides) {
if (pair.first.equals(usbFunctions)) {
Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second);
return pair.second;
}
}
}
// return passed in functions as is.
return usbFunctions;
}
public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
if (mDebuggingManager != null) {
mDebuggingManager.allowUsbDebugging(alwaysAllow, publicKey);

View File

@@ -252,19 +252,19 @@ public class UsbService extends IUsbManager.Stub {
}
@Override
public void setCurrentFunction(String function, boolean makeDefault) {
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", false);
if (mDeviceManager != null) mDeviceManager.setCurrentFunctions("none");
return;
}
if (mDeviceManager != null) {
mDeviceManager.setCurrentFunctions(function, makeDefault);
mDeviceManager.setCurrentFunctions(function);
} else {
throw new IllegalStateException("USB device mode not supported");
}