diff options
author | Jeff Sharkey <jsharkey@android.com> | 2012-10-01 21:45:52 -0700 |
---|---|---|
committer | Jeff Sharkey <jsharkey@android.com> | 2012-10-02 18:09:10 -0700 |
commit | fc3f24b4b60c10e0d3f41f70df37e11ea311cc2c (patch) | |
tree | be61172447392620b42c88517ad58a5210adf5cb | |
parent | c6e570dbadc3689bc80c0516492a3209d5f6742b (diff) | |
download | frameworks_base-fc3f24b4b60c10e0d3f41f70df37e11ea311cc2c.zip frameworks_base-fc3f24b4b60c10e0d3f41f70df37e11ea311cc2c.tar.gz frameworks_base-fc3f24b4b60c10e0d3f41f70df37e11ea311cc2c.tar.bz2 |
Make USB services multi-user aware.
USB settings are now isolated per-user, since they revolve around
installed packages. User-specific settings are returned based on
calling user, or referenced by UserHandle passed to SystemUI. Each
settings Context is wrapped as a specific user, so all broadcasts are
sent correctly. Upgrades any existing USB settings to OWNER.
Physical events, like new devices, are routed to the currently active
user. Switch to using AtomicFile when persisting settings.
Bug: 7244888
Change-Id: I8a723ad3d55ac1bff99276c5f3a3f5e8f013432f
10 files changed, 311 insertions, 146 deletions
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index c41405b..59fa1e0 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1703,6 +1703,7 @@ class ContextImpl extends Context { if (packageName.equals("system") || packageName.equals("android")) { final ContextImpl context = new ContextImpl(mMainThread.getSystemContext()); context.mBasePackageName = mBasePackageName; + context.mUser = user; return context; } diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl index 98bd4f5..8286686 100644 --- a/core/java/android/hardware/usb/IUsbManager.aidl +++ b/core/java/android/hardware/usb/IUsbManager.aidl @@ -44,12 +44,12 @@ interface IUsbManager /* Sets the default package for a USB device * (or clears it if the package name is null) */ - void setDevicePackage(in UsbDevice device, String packageName); + void setDevicePackage(in UsbDevice device, String packageName, int userId); /* Sets the default package for a USB accessory * (or clears it if the package name is null) */ - void setAccessoryPackage(in UsbAccessory accessory, String packageName); + void setAccessoryPackage(in UsbAccessory accessory, String packageName, int userId); /* Returns true if the caller has permission to access the device. */ boolean hasDevicePermission(in UsbDevice device); @@ -77,10 +77,10 @@ interface IUsbManager void grantAccessoryPermission(in UsbAccessory accessory, int uid); /* Returns true if the USB manager has default preferences or permissions for the package */ - boolean hasDefaults(String packageName); + boolean hasDefaults(String packageName, int userId); /* Clears default preferences and permissions for the package */ - void clearDefaults(String packageName); + void clearDefaults(String packageName, int userId); /* Sets the current USB function. */ void setCurrentFunction(String function, boolean makeDefault); diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java index 5007cf4..ff06630 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java @@ -26,6 +26,7 @@ import android.net.Uri; import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbManager; import android.os.Bundle; +import android.os.UserHandle; import android.util.Log; import com.android.internal.app.AlertActivity; @@ -90,7 +91,7 @@ public class UsbAccessoryUriActivity extends AlertActivity intent.addCategory(Intent.CATEGORY_BROWSABLE); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { - startActivity(intent); + startActivityAsUser(intent, UserHandle.CURRENT); } catch (ActivityNotFoundException e) { Log.e(TAG, "startActivity failed for " + mUri); } diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java index 030a261..3eccccd 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java @@ -16,23 +16,21 @@ package com.android.systemui.usb; -import android.app.Activity; import android.app.AlertDialog; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.hardware.usb.IUsbManager; -import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbAccessory; +import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; import android.os.Bundle; import android.os.IBinder; -import android.os.RemoteException; import android.os.ServiceManager; +import android.os.UserHandle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -42,7 +40,6 @@ import android.widget.TextView; import com.android.internal.app.AlertActivity; import com.android.internal.app.AlertController; - import com.android.systemui.R; public class UsbConfirmActivity extends AlertActivity @@ -62,10 +59,10 @@ public class UsbConfirmActivity extends AlertActivity public void onCreate(Bundle icicle) { super.onCreate(icicle); - Intent intent = getIntent(); - mDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); + Intent intent = getIntent(); + mDevice = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); - mResolveInfo = (ResolveInfo)intent.getParcelableExtra("rinfo"); + mResolveInfo = (ResolveInfo) intent.getParcelableExtra("rinfo"); PackageManager packageManager = getPackageManager(); String appName = mResolveInfo.loadLabel(packageManager).toString(); @@ -117,7 +114,8 @@ public class UsbConfirmActivity extends AlertActivity try { IBinder b = ServiceManager.getService(USB_SERVICE); IUsbManager service = IUsbManager.Stub.asInterface(b); - int uid = mResolveInfo.activityInfo.applicationInfo.uid; + final int uid = mResolveInfo.activityInfo.applicationInfo.uid; + final int userId = UserHandle.myUserId(); boolean alwaysUse = mAlwaysUse.isChecked(); Intent intent = null; @@ -129,9 +127,10 @@ public class UsbConfirmActivity extends AlertActivity service.grantDevicePermission(mDevice, uid); // set or clear default setting if (alwaysUse) { - service.setDevicePackage(mDevice, mResolveInfo.activityInfo.packageName); + service.setDevicePackage( + mDevice, mResolveInfo.activityInfo.packageName, userId); } else { - service.setDevicePackage(mDevice, null); + service.setDevicePackage(mDevice, null, userId); } } else if (mAccessory != null) { intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED); @@ -141,10 +140,10 @@ public class UsbConfirmActivity extends AlertActivity service.grantAccessoryPermission(mAccessory, uid); // set or clear default setting if (alwaysUse) { - service.setAccessoryPackage(mAccessory, - mResolveInfo.activityInfo.packageName); + service.setAccessoryPackage( + mAccessory, mResolveInfo.activityInfo.packageName, userId); } else { - service.setAccessoryPackage(mAccessory, null); + service.setAccessoryPackage(mAccessory, null, userId); } } @@ -152,7 +151,7 @@ public class UsbConfirmActivity extends AlertActivity intent.setComponent( new ComponentName(mResolveInfo.activityInfo.packageName, mResolveInfo.activityInfo.name)); - startActivity(intent); + startActivityAsUser(intent, new UserHandle(userId)); } catch (Exception e) { Log.e(TAG, "Unable to start activity", e); } diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java index c384f50..6e88d0d 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java @@ -32,6 +32,7 @@ import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.UserHandle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -67,7 +68,7 @@ public class UsbPermissionActivity extends AlertActivity mDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); mPendingIntent = (PendingIntent)intent.getParcelableExtra(Intent.EXTRA_INTENT); - mUid = intent.getIntExtra("uid", 0); + mUid = intent.getIntExtra(Intent.EXTRA_UID, -1); mPackageName = intent.getStringExtra("package"); PackageManager packageManager = getPackageManager(); @@ -128,7 +129,8 @@ public class UsbPermissionActivity extends AlertActivity if (mPermissionGranted) { service.grantDevicePermission(mDevice, mUid); if (mAlwaysUse.isChecked()) { - service.setDevicePackage(mDevice, mPackageName); + final int userId = UserHandle.getUserId(mUid); + service.setDevicePackage(mDevice, mPackageName, userId); } } } @@ -137,7 +139,8 @@ public class UsbPermissionActivity extends AlertActivity if (mPermissionGranted) { service.grantAccessoryPermission(mAccessory, mUid); if (mAlwaysUse.isChecked()) { - service.setAccessoryPackage(mAccessory, mPackageName); + final int userId = UserHandle.getUserId(mUid); + service.setAccessoryPackage(mAccessory, mPackageName, userId); } } } diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java index f61ecb1..9928f7f 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java @@ -16,8 +16,6 @@ package com.android.systemui.usb; -import com.android.internal.app.ResolverActivity; - import android.content.ActivityNotFoundException; import android.content.Intent; import android.content.pm.ResolveInfo; @@ -30,9 +28,11 @@ import android.os.IBinder; import android.os.Parcelable; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.UserHandle; import android.util.Log; import android.widget.CheckBox; +import com.android.internal.app.ResolverActivity; import com.android.systemui.R; import java.util.ArrayList; @@ -92,34 +92,36 @@ public class UsbResolverActivity extends ResolverActivity { super.onDestroy(); } + @Override protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) { try { IBinder b = ServiceManager.getService(USB_SERVICE); IUsbManager service = IUsbManager.Stub.asInterface(b); - int uid = ri.activityInfo.applicationInfo.uid; + final int uid = ri.activityInfo.applicationInfo.uid; + final int userId = UserHandle.myUserId(); if (mDevice != null) { // grant permission for the device service.grantDevicePermission(mDevice, uid); // set or clear default setting if (alwaysCheck) { - service.setDevicePackage(mDevice, ri.activityInfo.packageName); + service.setDevicePackage(mDevice, ri.activityInfo.packageName, userId); } else { - service.setDevicePackage(mDevice, null); + service.setDevicePackage(mDevice, null, userId); } } else if (mAccessory != null) { // grant permission for the accessory service.grantAccessoryPermission(mAccessory, uid); // set or clear default setting if (alwaysCheck) { - service.setAccessoryPackage(mAccessory, ri.activityInfo.packageName); + service.setAccessoryPackage(mAccessory, ri.activityInfo.packageName, userId); } else { - service.setAccessoryPackage(mAccessory, null); + service.setAccessoryPackage(mAccessory, null, userId); } } try { - startActivity(intent); + startActivityAsUser(intent, new UserHandle(userId)); } catch (ActivityNotFoundException e) { Log.e(TAG, "startActivity failed", e); } diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java index 10011aa..95797ef 100644 --- a/services/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/java/com/android/server/usb/UsbDeviceManager.java @@ -16,9 +16,9 @@ package com.android.server.usb; -import android.app.PendingIntent; import android.app.Notification; import android.app.NotificationManager; +import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; @@ -30,23 +30,19 @@ import android.content.res.Resources; import android.database.ContentObserver; import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbManager; -import android.net.Uri; -import android.os.Binder; -import android.os.Bundle; import android.os.FileUtils; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; -import android.os.Parcelable; import android.os.ParcelFileDescriptor; import android.os.Process; -import android.os.UserHandle; -import android.os.storage.StorageManager; -import android.os.storage.StorageVolume; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UEventObserver; +import android.os.UserHandle; +import android.os.storage.StorageManager; +import android.os.storage.StorageVolume; import android.provider.Settings; import android.util.Pair; import android.util.Slog; @@ -56,10 +52,9 @@ import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; -import java.util.ArrayList; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.HashMap; import java.util.Map; import java.util.Scanner; @@ -106,9 +101,12 @@ public class UsbDeviceManager { private UsbHandler mHandler; private boolean mBootCompleted; + private final Object mLock = new Object(); + private final Context mContext; private final ContentResolver mContentResolver; - private final UsbSettingsManager mSettingsManager; + // @GuardedBy("mLock") + private UsbSettingsManager mCurrentSettings; private NotificationManager mNotificationManager; private final boolean mHasUsbAccessory; private boolean mUseUsbNotification; @@ -149,10 +147,9 @@ public class UsbDeviceManager { } }; - public UsbDeviceManager(Context context, UsbSettingsManager settingsManager) { + public UsbDeviceManager(Context context) { mContext = context; mContentResolver = context.getContentResolver(); - mSettingsManager = settingsManager; PackageManager pm = mContext.getPackageManager(); mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY); initRndisAddress(); @@ -175,6 +172,18 @@ public class UsbDeviceManager { } } + public void setCurrentSettings(UsbSettingsManager settings) { + synchronized (mLock) { + mCurrentSettings = settings; + } + } + + private UsbSettingsManager getCurrentSettings() { + synchronized (mLock) { + return mCurrentSettings; + } + } + public void systemReady() { if (DEBUG) Slog.d(TAG, "systemReady"); @@ -516,7 +525,7 @@ public class UsbDeviceManager { Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory); // defer accessoryAttached if system is not ready if (mBootCompleted) { - mSettingsManager.accessoryAttached(mCurrentAccessory); + getCurrentSettings().accessoryAttached(mCurrentAccessory); } // else handle in mBootCompletedReceiver } else { Slog.e(TAG, "nativeGetAccessoryStrings failed"); @@ -529,7 +538,7 @@ public class UsbDeviceManager { if (mCurrentAccessory != null) { if (mBootCompleted) { - mSettingsManager.accessoryDetached(mCurrentAccessory); + getCurrentSettings().accessoryDetached(mCurrentAccessory); } mCurrentAccessory = null; mAccessoryStrings = null; @@ -618,7 +627,7 @@ public class UsbDeviceManager { case MSG_BOOT_COMPLETED: mBootCompleted = true; if (mCurrentAccessory != null) { - mSettingsManager.accessoryAttached(mCurrentAccessory); + getCurrentSettings().accessoryAttached(mCurrentAccessory); } if (mDebuggingManager != null) { mDebuggingManager.setAdbEnabled(mAdbEnabled); @@ -774,7 +783,7 @@ public class UsbDeviceManager { + currentAccessory; throw new IllegalArgumentException(error); } - mSettingsManager.checkPermission(accessory); + getCurrentSettings().checkPermission(accessory); return nativeOpenAccessory(); } diff --git a/services/java/com/android/server/usb/UsbHostManager.java b/services/java/com/android/server/usb/UsbHostManager.java index 0a0ff59..175ae6f 100644 --- a/services/java/com/android/server/usb/UsbHostManager.java +++ b/services/java/com/android/server/usb/UsbHostManager.java @@ -16,35 +16,19 @@ package com.android.server.usb; -import android.app.PendingIntent; -import android.content.BroadcastReceiver; -import android.content.ContentResolver; import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.hardware.usb.IUsbManager; import android.hardware.usb.UsbConstants; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbEndpoint; import android.hardware.usb.UsbInterface; -import android.hardware.usb.UsbManager; -import android.net.Uri; -import android.os.Binder; import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.Parcelable; import android.os.ParcelFileDescriptor; -import android.os.UEventObserver; -import android.provider.Settings; +import android.os.Parcelable; import android.util.Slog; -import java.io.File; import java.io.FileDescriptor; -import java.io.FileReader; import java.io.PrintWriter; import java.util.HashMap; -import java.util.List; /** * UsbHostManager manages USB state in host mode. @@ -54,22 +38,35 @@ public class UsbHostManager { private static final boolean LOG = false; // contains all connected USB devices - private final HashMap<String,UsbDevice> mDevices = new HashMap<String,UsbDevice>(); + private final HashMap<String, UsbDevice> mDevices = new HashMap<String, UsbDevice>(); // USB busses to exclude from USB host support private final String[] mHostBlacklist; private final Context mContext; private final Object mLock = new Object(); - private final UsbSettingsManager mSettingsManager; - public UsbHostManager(Context context, UsbSettingsManager settingsManager) { + // @GuardedBy("mLock") + private UsbSettingsManager mCurrentSettings; + + public UsbHostManager(Context context) { mContext = context; - mSettingsManager = settingsManager; mHostBlacklist = context.getResources().getStringArray( com.android.internal.R.array.config_usbHostBlacklist); } + public void setCurrentSettings(UsbSettingsManager settings) { + synchronized (mLock) { + mCurrentSettings = settings; + } + } + + private UsbSettingsManager getCurrentSettings() { + synchronized (mLock) { + return mCurrentSettings; + } + } + private boolean isBlackListed(String deviceName) { int count = mHostBlacklist.length; for (int i = 0; i < count; i++) { @@ -154,7 +151,7 @@ public class UsbHostManager { UsbDevice device = new UsbDevice(deviceName, vendorID, productID, deviceClass, deviceSubclass, deviceProtocol, interfaces); mDevices.put(deviceName, device); - mSettingsManager.deviceAttached(device); + getCurrentSettings().deviceAttached(device); } } @@ -163,7 +160,7 @@ public class UsbHostManager { synchronized (mLock) { UsbDevice device = mDevices.remove(deviceName); if (device != null) { - mSettingsManager.deviceDetached(device); + getCurrentSettings().deviceDetached(device); } } } @@ -202,7 +199,7 @@ public class UsbHostManager { throw new IllegalArgumentException( "device " + deviceName + " does not exist or is restricted"); } - mSettingsManager.checkPermission(device); + getCurrentSettings().checkPermission(device); return nativeOpenDevice(deviceName); } } diff --git a/services/java/com/android/server/usb/UsbService.java b/services/java/com/android/server/usb/UsbService.java index bebcd56..629f5fa 100644 --- a/services/java/com/android/server/usb/UsbService.java +++ b/services/java/com/android/server/usb/UsbService.java @@ -17,15 +17,20 @@ package com.android.server.usb; import android.app.PendingIntent; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; import android.hardware.usb.IUsbManager; import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbDevice; -import android.net.Uri; -import android.os.Binder; import android.os.Bundle; import android.os.ParcelFileDescriptor; +import android.os.UserHandle; +import android.util.SparseArray; + +import com.android.internal.util.IndentingPrintWriter; import java.io.File; import java.io.FileDescriptor; @@ -37,21 +42,72 @@ import java.io.PrintWriter; * support is delegated to UsbDeviceManager. */ public class UsbService extends IUsbManager.Stub { + private static final String TAG = "UsbService"; + private final Context mContext; + private UsbDeviceManager mDeviceManager; private UsbHostManager mHostManager; - private final UsbSettingsManager mSettingsManager; + private final Object mLock = new Object(); + + /** Map from {@link UserHandle} to {@link UsbSettingsManager} */ + // @GuardedBy("mLock") + private final SparseArray<UsbSettingsManager> + mSettingsByUser = new SparseArray<UsbSettingsManager>(); + + private UsbSettingsManager getSettingsForUser(int userId) { + synchronized (mLock) { + UsbSettingsManager settings = mSettingsByUser.get(userId); + if (settings == null) { + settings = new UsbSettingsManager(mContext, new UserHandle(userId)); + mSettingsByUser.put(userId, settings); + } + return settings; + } + } public UsbService(Context context) { mContext = context; - mSettingsManager = new UsbSettingsManager(context); - PackageManager pm = mContext.getPackageManager(); + + final PackageManager pm = mContext.getPackageManager(); if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) { - mHostManager = new UsbHostManager(context, mSettingsManager); + mHostManager = new UsbHostManager(context); } if (new File("/sys/class/android_usb").exists()) { - mDeviceManager = new UsbDeviceManager(context, mSettingsManager); + mDeviceManager = new UsbDeviceManager(context); + } + + 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); + } + + private BroadcastReceiver mUserReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); + final String action = intent.getAction(); + if (Intent.ACTION_USER_SWITCHED.equals(action)) { + setCurrentUser(userId); + } else if (Intent.ACTION_USER_STOPPED.equals(action)) { + synchronized (mLock) { + mSettingsByUser.remove(userId); + } + } + } + }; + + private void setCurrentUser(int userId) { + final UsbSettingsManager userSettings = getSettingsForUser(userId); + if (mHostManager != null) { + mHostManager.setCurrentSettings(userSettings); + } + if (mDeviceManager != null) { + mDeviceManager.setCurrentSettings(userSettings); } } @@ -65,6 +121,7 @@ public class UsbService extends IUsbManager.Stub { } /* Returns a list of all currently attached USB devices (host mdoe) */ + @Override public void getDeviceList(Bundle devices) { if (mHostManager != null) { mHostManager.getDeviceList(devices); @@ -72,6 +129,7 @@ public class UsbService extends IUsbManager.Stub { } /* Opens the specified USB device (host mode) */ + @Override public ParcelFileDescriptor openDevice(String deviceName) { if (mHostManager != null) { return mHostManager.openDevice(deviceName); @@ -81,6 +139,7 @@ public class UsbService extends IUsbManager.Stub { } /* returns the currently attached USB accessory (device mode) */ + @Override public UsbAccessory getCurrentAccessory() { if (mDeviceManager != null) { return mDeviceManager.getCurrentAccessory(); @@ -90,6 +149,7 @@ public class UsbService extends IUsbManager.Stub { } /* opens the currently attached USB accessory (device mode) */ + @Override public ParcelFileDescriptor openAccessory(UsbAccessory accessory) { if (mDeviceManager != null) { return mDeviceManager.openAccessory(accessory); @@ -98,54 +158,70 @@ public class UsbService extends IUsbManager.Stub { } } - public void setDevicePackage(UsbDevice device, String packageName) { + @Override + public void setDevicePackage(UsbDevice device, String packageName, int userId) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); - mSettingsManager.setDevicePackage(device, packageName); + getSettingsForUser(userId).setDevicePackage(device, packageName); } - public void setAccessoryPackage(UsbAccessory accessory, String packageName) { + @Override + public void setAccessoryPackage(UsbAccessory accessory, String packageName, int userId) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); - mSettingsManager.setAccessoryPackage(accessory, packageName); + getSettingsForUser(userId).setAccessoryPackage(accessory, packageName); } + @Override public boolean hasDevicePermission(UsbDevice device) { - return mSettingsManager.hasPermission(device); + final int userId = UserHandle.getCallingUserId(); + return getSettingsForUser(userId).hasPermission(device); } + @Override public boolean hasAccessoryPermission(UsbAccessory accessory) { - return mSettingsManager.hasPermission(accessory); + final int userId = UserHandle.getCallingUserId(); + return getSettingsForUser(userId).hasPermission(accessory); } - public void requestDevicePermission(UsbDevice device, String packageName, - PendingIntent pi) { - mSettingsManager.requestPermission(device, packageName, pi); + @Override + public void requestDevicePermission(UsbDevice device, String packageName, PendingIntent pi) { + final int userId = UserHandle.getCallingUserId(); + getSettingsForUser(userId).requestPermission(device, packageName, pi); } - public void requestAccessoryPermission(UsbAccessory accessory, String packageName, - PendingIntent pi) { - mSettingsManager.requestPermission(accessory, packageName, pi); + @Override + public void requestAccessoryPermission( + UsbAccessory accessory, String packageName, PendingIntent pi) { + final int userId = UserHandle.getCallingUserId(); + getSettingsForUser(userId).requestPermission(accessory, packageName, pi); } + @Override public void grantDevicePermission(UsbDevice device, int uid) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); - mSettingsManager.grantDevicePermission(device, uid); + final int userId = UserHandle.getUserId(uid); + getSettingsForUser(userId).grantDevicePermission(device, uid); } + @Override public void grantAccessoryPermission(UsbAccessory accessory, int uid) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); - mSettingsManager.grantAccessoryPermission(accessory, uid); + final int userId = UserHandle.getUserId(uid); + getSettingsForUser(userId).grantAccessoryPermission(accessory, uid); } - public boolean hasDefaults(String packageName) { + @Override + public boolean hasDefaults(String packageName, int userId) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); - return mSettingsManager.hasDefaults(packageName); + return getSettingsForUser(userId).hasDefaults(packageName); } - public void clearDefaults(String packageName) { + @Override + public void clearDefaults(String packageName, int userId) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); - mSettingsManager.clearDefaults(packageName); + getSettingsForUser(userId).clearDefaults(packageName); } + @Override public void setCurrentFunction(String function, boolean makeDefault) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); if (mDeviceManager != null) { @@ -155,6 +231,7 @@ public class UsbService extends IUsbManager.Stub { } } + @Override public void setMassStorageBackingFile(String path) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); if (mDeviceManager != null) { @@ -164,34 +241,41 @@ public class UsbService extends IUsbManager.Stub { } } + @Override public void allowUsbDebugging(boolean alwaysAllow, String publicKey) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); mDeviceManager.allowUsbDebugging(alwaysAllow, publicKey); } + @Override public void denyUsbDebugging() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); mDeviceManager.denyUsbDebugging(); } @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump UsbManager from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } + public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); + final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); pw.println("USB Manager State:"); - if (mDeviceManager != null) { mDeviceManager.dump(fd, pw); } if (mHostManager != null) { mHostManager.dump(fd, pw); } - mSettingsManager.dump(fd, pw); + + synchronized (mLock) { + for (int i = 0; i < mSettingsByUser.size(); i++) { + final int userId = mSettingsByUser.keyAt(i); + final UsbSettingsManager settings = mSettingsByUser.valueAt(i); + pw.increaseIndent(); + pw.println("Settings for user " + userId + ":"); + settings.dump(fd, pw); + pw.decreaseIndent(); + } + } + pw.decreaseIndent(); } } diff --git a/services/java/com/android/server/usb/UsbSettingsManager.java b/services/java/com/android/server/usb/UsbSettingsManager.java index a8453d3..4b2bbfe 100644 --- a/services/java/com/android/server/usb/UsbSettingsManager.java +++ b/services/java/com/android/server/usb/UsbSettingsManager.java @@ -33,9 +33,10 @@ import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbInterface; import android.hardware.usb.UsbManager; import android.os.Binder; -import android.os.FileUtils; -import android.os.Process; +import android.os.Environment; import android.os.UserHandle; +import android.util.AtomicFile; +import android.util.Log; import android.util.Slog; import android.util.SparseBooleanArray; import android.util.Xml; @@ -48,7 +49,6 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; -import java.io.BufferedOutputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; @@ -60,13 +60,21 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; -class UsbSettingsManager { +import libcore.io.IoUtils; +class UsbSettingsManager { private static final String TAG = "UsbSettingsManager"; private static final boolean DEBUG = false; - private static final File sSettingsFile = new File("/data/system/usb_device_manager.xml"); + + /** Legacy settings file, before multi-user */ + private static final File sSingleUserSettingsFile = new File( + "/data/system/usb_device_manager.xml"); + + private final UserHandle mUser; + private final AtomicFile mSettingsFile; private final Context mContext; + private final Context mUserContext; private final PackageManager mPackageManager; // Temporary mapping USB device name to list of UIDs with permissions for the device @@ -350,28 +358,49 @@ class UsbSettingsManager { } private class MyPackageMonitor extends PackageMonitor { - + @Override public void onPackageAdded(String packageName, int uid) { handlePackageUpdate(packageName); } + @Override public void onPackageChanged(String packageName, int uid, String[] components) { handlePackageUpdate(packageName); } + @Override public void onPackageRemoved(String packageName, int uid) { clearDefaults(packageName); } } + MyPackageMonitor mPackageMonitor = new MyPackageMonitor(); - public UsbSettingsManager(Context context) { + public UsbSettingsManager(Context context, UserHandle user) { + if (DEBUG) Slog.v(TAG, "Creating settings for " + user); + + try { + mUserContext = context.createPackageContextAsUser("android", 0, user); + } catch (NameNotFoundException e) { + throw new RuntimeException("Missing android package"); + } + mContext = context; - mPackageManager = context.getPackageManager(); + mPackageManager = mUserContext.getPackageManager(); + + mUser = user; + mSettingsFile = new AtomicFile(new File( + Environment.getUserSystemDirectory(user.getIdentifier()), + "usb_device_manager.xml")); + synchronized (mLock) { + if (UserHandle.OWNER.equals(user)) { + upgradeSingleUserLocked(); + } readSettingsLocked(); } - mPackageMonitor.register(context, null, true); + + mPackageMonitor.register(mUserContext, null, true); } private void readPreference(XmlPullParser parser) @@ -395,10 +424,54 @@ class UsbSettingsManager { XmlUtils.nextElement(parser); } + /** + * Upgrade any single-user settings from {@link #sSingleUserSettingsFile}. + * Should only by called by owner. + */ + private void upgradeSingleUserLocked() { + if (sSingleUserSettingsFile.exists()) { + mDevicePreferenceMap.clear(); + mAccessoryPreferenceMap.clear(); + + FileInputStream fis = null; + try { + fis = new FileInputStream(sSingleUserSettingsFile); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(fis, null); + + XmlUtils.nextElement(parser); + while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { + final String tagName = parser.getName(); + if ("preference".equals(tagName)) { + readPreference(parser); + } else { + XmlUtils.nextElement(parser); + } + } + } catch (IOException e) { + Log.wtf(TAG, "Failed to read single-user settings", e); + } catch (XmlPullParserException e) { + Log.wtf(TAG, "Failed to read single-user settings", e); + } finally { + IoUtils.closeQuietly(fis); + } + + writeSettingsLocked(); + + // Success or failure, we delete single-user file + sSingleUserSettingsFile.delete(); + } + } + private void readSettingsLocked() { + if (DEBUG) Slog.v(TAG, "readSettingsLocked()"); + + mDevicePreferenceMap.clear(); + mAccessoryPreferenceMap.clear(); + FileInputStream stream = null; try { - stream = new FileInputStream(sSettingsFile); + stream = mSettingsFile.openRead(); XmlPullParser parser = Xml.newPullParser(); parser.setInput(stream, null); @@ -407,7 +480,7 @@ class UsbSettingsManager { String tagName = parser.getName(); if ("preference".equals(tagName)) { readPreference(parser); - } else { + } else { XmlUtils.nextElement(parser); } } @@ -415,25 +488,21 @@ class UsbSettingsManager { if (DEBUG) Slog.d(TAG, "settings file not found"); } catch (Exception e) { Slog.e(TAG, "error reading settings file, deleting to start fresh", e); - sSettingsFile.delete(); + mSettingsFile.delete(); } finally { - if (stream != null) { - try { - stream.close(); - } catch (IOException e) { - } - } + IoUtils.closeQuietly(stream); } } private void writeSettingsLocked() { + if (DEBUG) Slog.v(TAG, "writeSettingsLocked()"); + FileOutputStream fos = null; try { - FileOutputStream fstr = new FileOutputStream(sSettingsFile); - if (DEBUG) Slog.d(TAG, "writing settings to " + fstr); - BufferedOutputStream str = new BufferedOutputStream(fstr); + fos = mSettingsFile.startWrite(); + FastXmlSerializer serializer = new FastXmlSerializer(); - serializer.setOutput(str, "utf-8"); + serializer.setOutput(fos, "utf-8"); serializer.startDocument(null, true); serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); serializer.startTag(null, "settings"); @@ -455,12 +524,12 @@ class UsbSettingsManager { serializer.endTag(null, "settings"); serializer.endDocument(); - str.flush(); - FileUtils.sync(fstr); - str.close(); - } catch (Exception e) { - Slog.e(TAG, "error writing settings file, deleting to start fresh", e); - sSettingsFile.delete(); + mSettingsFile.finishWrite(fos); + } catch (IOException e) { + Slog.e(TAG, "Failed to write settings", e); + if (fos != null) { + mSettingsFile.failWrite(fos); + } } } @@ -547,7 +616,7 @@ class UsbSettingsManager { } // Send broadcast to running activity with registered intent - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + mUserContext.sendBroadcast(intent); // Start activity with registered intent resolveActivity(intent, matches, defaultPackage, device, null); @@ -608,7 +677,7 @@ class UsbSettingsManager { dialogIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory); dialogIntent.putExtra("uri", uri); try { - mContext.startActivity(dialogIntent); + mUserContext.startActivityAsUser(dialogIntent, mUser); } catch (ActivityNotFoundException e) { Slog.e(TAG, "unable to start UsbAccessoryUriActivity"); } @@ -656,7 +725,7 @@ class UsbSettingsManager { intent.setComponent( new ComponentName(defaultRI.activityInfo.packageName, defaultRI.activityInfo.name)); - mContext.startActivity(intent); + mUserContext.startActivityAsUser(intent, mUser); } catch (ActivityNotFoundException e) { Slog.e(TAG, "startActivity failed", e); } @@ -683,7 +752,7 @@ class UsbSettingsManager { resolverIntent.putExtra(Intent.EXTRA_INTENT, intent); } try { - mContext.startActivity(resolverIntent); + mUserContext.startActivityAsUser(resolverIntent, mUser); } catch (ActivityNotFoundException e) { Slog.e(TAG, "unable to start activity " + resolverIntent); } @@ -814,7 +883,7 @@ class UsbSettingsManager { } private void requestPermissionDialog(Intent intent, String packageName, PendingIntent pi) { - int uid = Binder.getCallingUid(); + final int uid = Binder.getCallingUid(); // compare uid with packageName to foil apps pretending to be someone else try { @@ -833,9 +902,9 @@ class UsbSettingsManager { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(Intent.EXTRA_INTENT, pi); intent.putExtra("package", packageName); - intent.putExtra("uid", uid); + intent.putExtra(Intent.EXTRA_UID, uid); try { - mContext.startActivity(intent); + mUserContext.startActivityAsUser(intent, mUser); } catch (ActivityNotFoundException e) { Slog.e(TAG, "unable to start UsbPermissionActivity"); } finally { @@ -851,7 +920,7 @@ class UsbSettingsManager { intent.putExtra(UsbManager.EXTRA_DEVICE, device); intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true); try { - pi.send(mContext, 0, intent); + pi.send(mUserContext, 0, intent); } catch (PendingIntent.CanceledException e) { if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled"); } @@ -864,14 +933,14 @@ class UsbSettingsManager { } public void requestPermission(UsbAccessory accessory, String packageName, PendingIntent pi) { - Intent intent = new Intent(); + Intent intent = new Intent(); // respond immediately if permission has already been granted if (hasPermission(accessory)) { intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory); intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true); - try { - pi.send(mContext, 0, intent); + try { + pi.send(mUserContext, 0, intent); } catch (PendingIntent.CanceledException e) { if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled"); } |