am c1aebfa0: Merge "Clean up USB Manager and fix ADB." into mnc-dev
* commit 'c1aebfa02c393471fb344c3a94ee2ae62bb78f93': Clean up USB Manager and fix ADB.
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2884,8 +2884,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. -->
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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;
|
||||
@@ -5446,10 +5445,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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
// 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 void setEnabledFunctions(String functions) {
|
||||
if (DEBUG) Slog.d(TAG, "setEnabledFunctions " + functions);
|
||||
|
||||
private boolean trySetEnabledFunctions(String functions, boolean forceRestart) {
|
||||
if (functions == null) {
|
||||
functions = getDefaultFunctions();
|
||||
}
|
||||
functions = applyAdbFunction(functions);
|
||||
functions = applyUserRestrictions(functions);
|
||||
|
||||
if (mAdbEnabled) {
|
||||
functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
|
||||
} 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 {
|
||||
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);
|
||||
// revert to previous configuration if we fail
|
||||
setUsbConfig(mCurrentFunctions);
|
||||
return false;
|
||||
}
|
||||
|
||||
mCurrentFunctionsApplied = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private String applyAdbFunction(String functions) {
|
||||
if (mAdbEnabled) {
|
||||
functions = UsbManager.addFunction(functions, UsbManager.USB_FUNCTION_ADB);
|
||||
} else {
|
||||
functions = UsbManager.removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
|
||||
}
|
||||
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);
|
||||
|
||||
@@ -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) {
|
||||
@@ -251,16 +268,20 @@ public class UsbService extends IUsbManager.Stub {
|
||||
getSettingsForUser(userId).clearDefaults(packageName);
|
||||
}
|
||||
|
||||
@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);
|
||||
|
||||
Reference in New Issue
Block a user