diff options
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"); } |