Require permission to read USB device's serial number.

Fixes: 110953952
Test: CtsVerifier USB Device test
Change-Id: I99b52bac6c800d869198e282e364f3a530336803
diff --git a/Android.bp b/Android.bp
index 2ab91a1..bfd961e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -194,6 +194,7 @@
         "core/java/android/hardware/radio/ITunerCallback.aidl",
         "core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl",
         "core/java/android/hardware/usb/IUsbManager.aidl",
+        "core/java/android/hardware/usb/IUsbSerialReader.aidl",
         "core/java/android/net/ICaptivePortal.aidl",
         "core/java/android/net/IConnectivityManager.aidl",
         "core/java/android/net/IIpConnectivityMetrics.aidl",
diff --git a/core/java/android/hardware/usb/IUsbSerialReader.aidl b/core/java/android/hardware/usb/IUsbSerialReader.aidl
new file mode 100644
index 0000000..787d5cd
--- /dev/null
+++ b/core/java/android/hardware/usb/IUsbSerialReader.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb;
+
+/** @hide */
+interface IUsbSerialReader
+{
+    /* Returns a serial for the accessory/device */
+    String getSerial(String packageName);
+}
diff --git a/core/java/android/hardware/usb/UsbAccessory.java b/core/java/android/hardware/usb/UsbAccessory.java
index 4aeb40c..b418d43 100644
--- a/core/java/android/hardware/usb/UsbAccessory.java
+++ b/core/java/android/hardware/usb/UsbAccessory.java
@@ -18,8 +18,11 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityThread;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.RemoteException;
+
 import com.android.internal.util.Preconditions;
 
 /**
@@ -54,7 +57,7 @@
     private final @Nullable String mDescription;
     private final @Nullable String mVersion;
     private final @Nullable String mUri;
-    private final @Nullable String mSerial;
+    private final @NonNull IUsbSerialReader mSerialNumberReader;
 
     /** @hide */
     public static final int MANUFACTURER_STRING = 0;
@@ -75,22 +78,38 @@
      */
     public UsbAccessory(@NonNull String manufacturer, @NonNull String model,
             @Nullable String description, @Nullable String version, @Nullable String uri,
-            @Nullable String serial) {
+            @NonNull IUsbSerialReader serialNumberReader) {
         mManufacturer = Preconditions.checkNotNull(manufacturer);
         mModel = Preconditions.checkNotNull(model);
         mDescription = description;
         mVersion = version;
         mUri = uri;
-        mSerial = serial;
+        mSerialNumberReader = serialNumberReader;
+
+        // Make sure the binder belongs to the system
+        if (ActivityThread.isSystem()) {
+            Preconditions.checkArgument(mSerialNumberReader instanceof IUsbSerialReader.Stub);
+        }
     }
 
     /**
-     * UsbAccessory should only be instantiated by UsbService implementation
+     * DO NOT USE. Only for backwards compatibility with
+     * {@link com.android.future.usb.UsbAccessory}.
+     *
      * @hide
+     * @deprecated use {@link UsbAccessory#UsbAccessory(String, String, String, String, String,
+     *             IUsbSerialReader) instead}
      */
-    public UsbAccessory(String[] strings) {
-        this(strings[MANUFACTURER_STRING], strings[MODEL_STRING], strings[DESCRIPTION_STRING],
-                strings[VERSION_STRING], strings[URI_STRING], strings[SERIAL_STRING]);
+    @Deprecated
+    public UsbAccessory(@NonNull String manufacturer, @NonNull String model,
+            @Nullable String description, @Nullable String version, @Nullable String uri,
+            @Nullable String serialNumber) {
+        this(manufacturer, model, description, version, uri, new IUsbSerialReader.Stub() {
+            @Override
+            public String getSerial(String packageName) {
+                return serialNumber;
+            }
+        });
     }
 
     /**
@@ -146,9 +165,17 @@
      * between individual accessories of the same model and manufacturer
      *
      * @return the unique serial number, or {@code null} if not set
+     *
+     * @throws SecurityException if the app targets SDK >= {@value android.os.Build.VERSION_CODES#Q}
+     *                           and the app does not have permission to read from the accessory.
      */
     public @Nullable String getSerial() {
-        return mSerial;
+        try {
+            return mSerialNumberReader.getSerial(ActivityThread.currentPackageName());
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+            return null;
+        }
     }
 
     private static boolean compare(String s1, String s2) {
@@ -165,7 +192,7 @@
                     compare(mDescription, accessory.getDescription()) &&
                     compare(mVersion, accessory.getVersion()) &&
                     compare(mUri, accessory.getUri()) &&
-                    compare(mSerial, accessory.getSerial()));
+                    compare(getSerial(), accessory.getSerial()));
         }
         return false;
     }
@@ -175,7 +202,7 @@
         return mManufacturer.hashCode() ^ mModel.hashCode() ^
                 (mDescription == null ? 0 : mDescription.hashCode()) ^
                 (mVersion == null ? 0 : mVersion.hashCode()) ^
-                (mUri == null ? 0 : mUri.hashCode()) ^ (mSerial == null ? 0 : mSerial.hashCode());
+                (mUri == null ? 0 : mUri.hashCode());
     }
 
     @Override
@@ -185,7 +212,7 @@
                             ", mDescription=" + mDescription +
                             ", mVersion=" + mVersion +
                             ", mUri=" + mUri +
-                            ", mSerial=" + mSerial + "]";
+                            ", mSerialNumberReader=" + mSerialNumberReader + "]";
     }
 
     public static final Parcelable.Creator<UsbAccessory> CREATOR =
@@ -196,8 +223,11 @@
             String description = in.readString();
             String version = in.readString();
             String uri = in.readString();
-            String serial = in.readString();
-            return new UsbAccessory(manufacturer, model, description, version, uri, serial);
+            IUsbSerialReader serialNumberReader = IUsbSerialReader.Stub.asInterface(
+                    in.readStrongBinder());
+
+            return new UsbAccessory(manufacturer, model, description, version, uri,
+                    serialNumberReader);
         }
 
         public UsbAccessory[] newArray(int size) {
@@ -215,6 +245,6 @@
         parcel.writeString(mDescription);
         parcel.writeString(mVersion);
         parcel.writeString(mUri);
-        parcel.writeString(mSerial);
+        parcel.writeStrongBinder(mSerialNumberReader.asBinder());
    }
 }
diff --git a/core/java/android/hardware/usb/UsbDevice.java b/core/java/android/hardware/usb/UsbDevice.java
index 26c5a95..b08212c 100644
--- a/core/java/android/hardware/usb/UsbDevice.java
+++ b/core/java/android/hardware/usb/UsbDevice.java
@@ -19,8 +19,11 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
+import android.app.ActivityThread;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.RemoteException;
+
 import com.android.internal.util.Preconditions;
 
 /**
@@ -50,27 +53,27 @@
     private final @Nullable String mManufacturerName;
     private final @Nullable String mProductName;
     private final @NonNull String mVersion;
-    private final @Nullable String mSerialNumber;
+    private final @NonNull UsbConfiguration[] mConfigurations;
+    private final @NonNull IUsbSerialReader mSerialNumberReader;
     private final int mVendorId;
     private final int mProductId;
     private final int mClass;
     private final int mSubclass;
     private final int mProtocol;
 
-    /** All configurations for this device, only null during creation */
-    private @Nullable Parcelable[] mConfigurations;
-
     /** All interfaces on the device. Initialized on first call to getInterfaceList */
     @UnsupportedAppUsage
     private @Nullable UsbInterface[] mInterfaces;
 
     /**
-     * UsbDevice should only be instantiated by UsbService implementation
+     * Create a new UsbDevice object. Only called by {@link Builder#build(IUsbSerialReader)}
+     *
      * @hide
      */
-    public UsbDevice(@NonNull String name, int vendorId, int productId, int Class, int subClass,
+    private UsbDevice(@NonNull String name, int vendorId, int productId, int Class, int subClass,
             int protocol, @Nullable String manufacturerName, @Nullable String productName,
-            @NonNull String version, @Nullable String serialNumber) {
+            @NonNull String version, @NonNull UsbConfiguration[] configurations,
+            @NonNull IUsbSerialReader serialNumberReader) {
         mName = Preconditions.checkNotNull(name);
         mVendorId = vendorId;
         mProductId = productId;
@@ -80,7 +83,13 @@
         mManufacturerName = manufacturerName;
         mProductName = productName;
         mVersion = Preconditions.checkStringNotEmpty(version);
-        mSerialNumber = serialNumber;
+        mConfigurations = Preconditions.checkArrayElementsNotNull(configurations, "configurations");
+        mSerialNumberReader = Preconditions.checkNotNull(serialNumberReader);
+
+        // Make sure the binder belongs to the system
+        if (ActivityThread.isSystem()) {
+            Preconditions.checkArgument(mSerialNumberReader instanceof IUsbSerialReader.Stub);
+        }
     }
 
     /**
@@ -125,9 +134,17 @@
      * Returns the serial number of the device.
      *
      * @return the serial number name, or {@code null} if the property could not be read
+     *
+     * @throws SecurityException if the app targets SDK >= {@value android.os.Build.VERSION_CODES#Q}
+     *                           and the app does not have permission to read from the device.
      */
     public @Nullable String getSerialNumber() {
-        return mSerialNumber;
+        try {
+            return mSerialNumberReader.getSerial(ActivityThread.currentPackageName());
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+            return null;
+        }
     }
 
     /**
@@ -203,7 +220,7 @@
      * @return the configuration
      */
     public @NonNull UsbConfiguration getConfiguration(int index) {
-        return (UsbConfiguration)mConfigurations[index];
+        return mConfigurations[index];
     }
 
     private @Nullable UsbInterface[] getInterfaceList() {
@@ -211,14 +228,14 @@
             int configurationCount = mConfigurations.length;
             int interfaceCount = 0;
             for (int i = 0; i < configurationCount; i++) {
-                UsbConfiguration configuration = (UsbConfiguration)mConfigurations[i];
+                UsbConfiguration configuration = mConfigurations[i];
                 interfaceCount += configuration.getInterfaceCount();
             }
 
             mInterfaces = new UsbInterface[interfaceCount];
             int offset = 0;
             for (int i = 0; i < configurationCount; i++) {
-                UsbConfiguration configuration = (UsbConfiguration)mConfigurations[i];
+                UsbConfiguration configuration = mConfigurations[i];
                 interfaceCount = configuration.getInterfaceCount();
                 for (int j = 0; j < interfaceCount; j++) {
                     mInterfaces[offset++] = configuration.getInterface(j);
@@ -251,14 +268,6 @@
         return getInterfaceList()[index];
     }
 
-    /**
-     * Only used by UsbService implementation
-     * @hide
-     */
-    public void setConfigurations(@NonNull Parcelable[] configuration) {
-        mConfigurations = Preconditions.checkArrayElementsNotNull(configuration, "configuration");
-    }
-
     @Override
     public boolean equals(Object o) {
         if (o instanceof UsbDevice) {
@@ -281,7 +290,8 @@
                 ",mVendorId=" + mVendorId + ",mProductId=" + mProductId +
                 ",mClass=" + mClass + ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol +
                 ",mManufacturerName=" + mManufacturerName + ",mProductName=" + mProductName +
-                ",mVersion=" + mVersion + ",mSerialNumber=" + mSerialNumber + ",mConfigurations=[");
+                ",mVersion=" + mVersion + ",mSerialNumberReader=" + mSerialNumberReader
+                + ",mConfigurations=[");
         for (int i = 0; i < mConfigurations.length; i++) {
             builder.append("\n");
             builder.append(mConfigurations[i].toString());
@@ -302,11 +312,13 @@
             String manufacturerName = in.readString();
             String productName = in.readString();
             String version = in.readString();
-            String serialNumber = in.readString();
-            Parcelable[] configurations = in.readParcelableArray(UsbInterface.class.getClassLoader());
+            IUsbSerialReader serialNumberReader =
+                    IUsbSerialReader.Stub.asInterface(in.readStrongBinder());
+            UsbConfiguration[] configurations = in.readParcelableArray(
+                    UsbConfiguration.class.getClassLoader(), UsbConfiguration.class);
             UsbDevice device = new UsbDevice(name, vendorId, productId, clasz, subClass, protocol,
-                                 manufacturerName, productName, version, serialNumber);
-            device.setConfigurations(configurations);
+                                 manufacturerName, productName, version, configurations,
+                    serialNumberReader);
             return device;
         }
 
@@ -329,7 +341,7 @@
         parcel.writeString(mManufacturerName);
         parcel.writeString(mProductName);
         parcel.writeString(mVersion);
-        parcel.writeString(mSerialNumber);
+        parcel.writeStrongBinder(mSerialNumberReader.asBinder());
         parcel.writeParcelableArray(mConfigurations, 0);
    }
 
@@ -343,4 +355,53 @@
 
     private static native int native_get_device_id(String name);
     private static native String native_get_device_name(int id);
+
+    /**
+     * @hide
+     */
+    public static class Builder {
+        private final @NonNull String mName;
+        private final int mVendorId;
+        private final int mProductId;
+        private final int mClass;
+        private final int mSubclass;
+        private final int mProtocol;
+        private final @Nullable String mManufacturerName;
+        private final @Nullable String mProductName;
+        private final @NonNull String mVersion;
+        private final @NonNull UsbConfiguration[] mConfigurations;
+
+        // Temporary storage for serial number. Serial number reader need to be wrapped in a
+        // IUsbSerialReader as they might be used as PII.
+        public final @Nullable String serialNumber;
+
+        public Builder(@NonNull String name, int vendorId, int productId, int Class, int subClass,
+                int protocol, @Nullable String manufacturerName, @Nullable String productName,
+                @NonNull String version, @NonNull UsbConfiguration[] configurations,
+                @Nullable String serialNumber) {
+            mName = Preconditions.checkNotNull(name);
+            mVendorId = vendorId;
+            mProductId = productId;
+            mClass = Class;
+            mSubclass = subClass;
+            mProtocol = protocol;
+            mManufacturerName = manufacturerName;
+            mProductName = productName;
+            mVersion = Preconditions.checkStringNotEmpty(version);
+            mConfigurations = configurations;
+            this.serialNumber = serialNumber;
+        }
+
+        /**
+         * Create a new {@link UsbDevice}
+         *
+         * @param serialReader The method to read the serial number.
+         *
+         * @return The usb device
+         */
+        public UsbDevice build(@NonNull IUsbSerialReader serialReader) {
+            return new UsbDevice(mName, mVendorId, mProductId, mClass, mSubclass, mProtocol,
+                    mManufacturerName, mProductName, mVersion, mConfigurations, serialReader);
+        }
+    }
 }
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 57f1668..bd3e745 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -20,8 +20,6 @@
 import static com.android.internal.util.dump.DumpUtils.writeStringIfNotNull;
 
 import android.app.ActivityManager;
-
-import com.android.server.wm.ActivityTaskManagerInternal;
 import android.app.KeyguardManager;
 import android.app.Notification;
 import android.app.NotificationChannel;
@@ -52,6 +50,7 @@
 import android.hidl.manager.V1_0.IServiceManager;
 import android.hidl.manager.V1_0.IServiceNotification;
 import android.os.BatteryManager;
+import android.os.Binder;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.Handler;
@@ -82,6 +81,7 @@
 import com.android.internal.util.dump.DualDumpOutputStream;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
+import com.android.server.wm.ActivityTaskManagerInternal;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -658,7 +658,19 @@
                 // successfully entered accessory mode
                 String[] accessoryStrings = mUsbDeviceManager.getAccessoryStrings();
                 if (accessoryStrings != null) {
-                    mCurrentAccessory = new UsbAccessory(accessoryStrings);
+                    UsbSerialReader serialReader = new UsbSerialReader(mContext, mSettingsManager,
+                            accessoryStrings[UsbAccessory.SERIAL_STRING]);
+
+                    mCurrentAccessory = new UsbAccessory(
+                            accessoryStrings[UsbAccessory.MANUFACTURER_STRING],
+                            accessoryStrings[UsbAccessory.MODEL_STRING],
+                            accessoryStrings[UsbAccessory.DESCRIPTION_STRING],
+                            accessoryStrings[UsbAccessory.VERSION_STRING],
+                            accessoryStrings[UsbAccessory.URI_STRING],
+                            serialReader);
+
+                    serialReader.setDevice(mCurrentAccessory);
+
                     Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
                     // defer accessoryAttached if system is not ready
                     if (mBootCompleted) {
@@ -1982,7 +1994,7 @@
                     + currentAccessory;
             throw new IllegalArgumentException(error);
         }
-        settings.checkPermission(accessory);
+        settings.checkPermission(accessory, Binder.getCallingUid());
         return nativeOpenAccessory();
     }
 
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 589bcdc..a4c29a6 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -370,13 +370,18 @@
                 return false;
             }
 
-            UsbDevice newDevice = parser.toAndroidUsbDevice();
-            if (newDevice == null) {
+            UsbDevice.Builder newDeviceBuilder = parser.toAndroidUsbDevice();
+            if (newDeviceBuilder == null) {
                 Slog.e(TAG, "Couldn't create UsbDevice object.");
                 // Tracking
                 addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT_BADDEVICE,
                         parser.getRawDescriptors());
             } else {
+                UsbSerialReader serialNumberReader = new UsbSerialReader(mContext, mSettingsManager,
+                        newDeviceBuilder.serialNumber);
+                UsbDevice newDevice = newDeviceBuilder.build(serialNumberReader);
+                serialNumberReader.setDevice(newDevice);
+
                 mDevices.put(deviceAddress, newDevice);
                 Slog.d(TAG, "Added device " + newDevice);
 
diff --git a/services/usb/java/com/android/server/usb/UsbPermissionManager.java b/services/usb/java/com/android/server/usb/UsbPermissionManager.java
index 2c9ee36..dd2f29b 100644
--- a/services/usb/java/com/android/server/usb/UsbPermissionManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPermissionManager.java
@@ -148,11 +148,11 @@
      * Returns true if caller has permission to access the accessory.
      *
      * @param accessory to check permission for
+     * @param uid to check permission for
      * @return {@code true} if caller has permssion
      */
-    boolean hasPermission(@NonNull UsbAccessory accessory) {
+    boolean hasPermission(@NonNull UsbAccessory accessory, int uid) {
         synchronized (mLock) {
-            int uid = Binder.getCallingUid();
             if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) {
                 return true;
             }
diff --git a/services/usb/java/com/android/server/usb/UsbSerialReader.java b/services/usb/java/com/android/server/usb/UsbSerialReader.java
new file mode 100644
index 0000000..5bf94af
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/UsbSerialReader.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.usb;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.hardware.usb.IUsbSerialReader;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbDevice;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+
+import com.android.internal.util.ArrayUtils;
+
+/**
+ * Allows an app to read the serial number of the {@link UsbDevice}/{@link UsbAccessory} only if
+ * the app has got the permission to do so.
+ */
+class UsbSerialReader extends IUsbSerialReader.Stub {
+    private final @Nullable String mSerialNumber;
+    private final @NonNull Context mContext;
+    private final @NonNull UsbSettingsManager mSettingsManager;
+
+    private Object mDevice;
+
+    /**
+     * Create an new {@link UsbSerialReader}. It is mandatory to call {@link #setDevice(Object)}
+     * immediately after this.
+     *
+     * @param context A context to be used by the reader
+     * @param settingsManager The USB settings manager
+     * @param serialNumber The serial number that might be read
+     */
+    UsbSerialReader(@NonNull Context context, @NonNull UsbSettingsManager settingsManager,
+            @Nullable String serialNumber) {
+        mContext = context;
+        mSettingsManager = settingsManager;
+        mSerialNumber = serialNumber;
+    }
+
+    /**
+     * Set the {@link UsbDevice}/{@link UsbAccessory} the serial number belongs to
+     *
+     * @param device The device/accessory
+     */
+    public void setDevice(@NonNull Object device) {
+        mDevice = device;
+    }
+
+    @Override
+    public String getSerial(String packageName) throws RemoteException {
+        int pid = Binder.getCallingPid();
+        int uid = Binder.getCallingUid();
+
+        if (uid != Process.SYSTEM_UID) {
+            enforcePackageBelongsToUid(uid, packageName);
+
+            PackageInfo pkg;
+            try {
+                pkg = mContext.getPackageManager().getPackageInfo(packageName, 0);
+            } catch (PackageManager.NameNotFoundException e) {
+                throw new RemoteException("package " + packageName + " cannot be found");
+            }
+
+            if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q) {
+                if (mContext.checkPermission(android.Manifest.permission.MANAGE_USB, pid, uid)
+                        == PackageManager.PERMISSION_DENIED) {
+                    UsbUserSettingsManager settings = mSettingsManager.getSettingsForUser(
+                            UserHandle.getUserId(uid));
+
+                    if (mDevice instanceof UsbDevice) {
+                        settings.checkPermission((UsbDevice) mDevice, packageName, uid);
+                    } else {
+                        settings.checkPermission((UsbAccessory) mDevice, uid);
+                    }
+                }
+            }
+        }
+
+        return mSerialNumber;
+    }
+
+    private void enforcePackageBelongsToUid(int uid, @NonNull String packageName) {
+        String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
+
+        if (!ArrayUtils.contains(packages, packageName)) {
+            throw new IllegalArgumentException(packageName + " does to belong to the " + uid);
+        }
+    }
+}
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index e92bd74..4be70af 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -318,8 +318,13 @@
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
 
         UserHandle user = UserHandle.of(userId);
-        mSettingsManager.getSettingsForProfileGroup(user).setDevicePackage(device, packageName,
-                user);
+        final long token = Binder.clearCallingIdentity();
+        try {
+            mSettingsManager.getSettingsForProfileGroup(user).setDevicePackage(device, packageName,
+                    user);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     @Override
@@ -329,49 +334,93 @@
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
 
         UserHandle user = UserHandle.of(userId);
-        mSettingsManager.getSettingsForProfileGroup(user).setAccessoryPackage(accessory,
-                packageName, user);
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            mSettingsManager.getSettingsForProfileGroup(user).setAccessoryPackage(accessory,
+                    packageName, user);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     @Override
     public boolean hasDevicePermission(UsbDevice device, String packageName) {
-        final int userId = UserHandle.getCallingUserId();
-        return getSettingsForUser(userId).hasPermission(device, packageName,
-                Binder.getCallingUid());
+        final int uid = Binder.getCallingUid();
+        final int userId = UserHandle.getUserId(uid);
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return getSettingsForUser(userId).hasPermission(device, packageName, uid);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     @Override
     public boolean hasAccessoryPermission(UsbAccessory accessory) {
-        final int userId = UserHandle.getCallingUserId();
-        return getSettingsForUser(userId).hasPermission(accessory);
+        final int uid = Binder.getCallingUid();
+        final int userId = UserHandle.getUserId(uid);
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return getSettingsForUser(userId).hasPermission(accessory, uid);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     @Override
     public void requestDevicePermission(UsbDevice device, String packageName, PendingIntent pi) {
-        final int userId = UserHandle.getCallingUserId();
-        getSettingsForUser(userId).requestPermission(device, packageName, pi,
-                Binder.getCallingUid());
+        final int uid = Binder.getCallingUid();
+        final int userId = UserHandle.getUserId(uid);
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            getSettingsForUser(userId).requestPermission(device, packageName, pi, uid);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     @Override
     public void requestAccessoryPermission(
             UsbAccessory accessory, String packageName, PendingIntent pi) {
-        final int userId = UserHandle.getCallingUserId();
-        getSettingsForUser(userId).requestPermission(accessory, packageName, pi);
+        final int uid = Binder.getCallingUid();
+        final int userId = UserHandle.getUserId(uid);
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            getSettingsForUser(userId).requestPermission(accessory, packageName, pi, uid);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     @Override
     public void grantDevicePermission(UsbDevice device, int uid) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
         final int userId = UserHandle.getUserId(uid);
-        getSettingsForUser(userId).grantDevicePermission(device, uid);
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            getSettingsForUser(userId).grantDevicePermission(device, uid);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     @Override
     public void grantAccessoryPermission(UsbAccessory accessory, int uid) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
         final int userId = UserHandle.getUserId(uid);
-        getSettingsForUser(userId).grantAccessoryPermission(accessory, uid);
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            getSettingsForUser(userId).grantAccessoryPermission(accessory, uid);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     @Override
@@ -381,7 +430,13 @@
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
 
         UserHandle user = UserHandle.of(userId);
-        return mSettingsManager.getSettingsForProfileGroup(user).hasDefaults(packageName, user);
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return mSettingsManager.getSettingsForProfileGroup(user).hasDefaults(packageName, user);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     @Override
@@ -391,7 +446,13 @@
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
 
         UserHandle user = UserHandle.of(userId);
-        mSettingsManager.getSettingsForProfileGroup(user).clearDefaults(packageName, user);
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            mSettingsManager.getSettingsForProfileGroup(user).clearDefaults(packageName, user);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     @Override
diff --git a/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java b/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java
index fe93399..0121d30 100644
--- a/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java
@@ -168,19 +168,21 @@
         return mUsbPermissionManager.hasPermission(device, uid);
     }
 
-    public boolean hasPermission(UsbAccessory accessory) {
-        return mUsbPermissionManager.hasPermission(accessory);
+    public boolean hasPermission(UsbAccessory accessory, int uid) {
+        return mUsbPermissionManager.hasPermission(accessory, uid);
     }
 
     public void checkPermission(UsbDevice device, String packageName, int uid) {
         if (!hasPermission(device, packageName, uid)) {
-            throw new SecurityException("User has not given permission to device " + device);
+            throw new SecurityException("User has not given " + uid + "/" + packageName
+                    + " permission to access device " + device.getDeviceName());
         }
     }
 
-    public void checkPermission(UsbAccessory accessory) {
-        if (!hasPermission(accessory)) {
-            throw new SecurityException("User has not given permission to accessory " + accessory);
+    public void checkPermission(UsbAccessory accessory, int uid) {
+        if (!hasPermission(accessory, uid)) {
+            throw new SecurityException("User has not given " + uid + " permission to accessory "
+                    + accessory);
         }
     }
 
@@ -236,9 +238,10 @@
         requestPermissionDialog(device, null, canBeDefault(device, packageName), packageName, pi);
     }
 
-    public void requestPermission(UsbAccessory accessory, String packageName, PendingIntent pi) {
+    public void requestPermission(UsbAccessory accessory, String packageName, PendingIntent pi,
+            int uid) {
         // respond immediately if permission has already been granted
-        if (hasPermission(accessory)) {
+        if (hasPermission(accessory, uid)) {
             Intent intent = new Intent();
             intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
             intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
index e615428..c021101 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
@@ -271,13 +271,13 @@
     /**
      * @hide
      */
-    public UsbDevice toAndroidUsbDevice() {
+    public UsbDevice.Builder toAndroidUsbDevice() {
         if (mDeviceDescriptor == null) {
             Log.e(TAG, "toAndroidUsbDevice() ERROR - No Device Descriptor");
             return null;
         }
 
-        UsbDevice device = mDeviceDescriptor.toAndroid(this);
+        UsbDevice.Builder device = mDeviceDescriptor.toAndroid(this);
         if (device == null) {
             Log.e(TAG, "toAndroidUsbDevice() ERROR Creating Device");
         }
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
index fae594a..f50b9cb 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
@@ -135,7 +135,7 @@
     /**
      * @hide
      */
-    public UsbDevice toAndroid(UsbDescriptorParser parser) {
+    public UsbDevice.Builder toAndroid(UsbDescriptorParser parser) {
         if (DEBUG) {
             Log.d(TAG, "toAndroid()");
         }
@@ -152,16 +152,14 @@
             Log.d(TAG, "  versionString:" + versionString + " serialStr:" + serialStr);
         }
 
-        UsbDevice device = new UsbDevice(parser.getDeviceAddr(), mVendorID, mProductID,
-                mDevClass, mDevSubClass,
-                mProtocol, mfgName, prodName,
-                versionString, serialStr);
         UsbConfiguration[] configs = new UsbConfiguration[mConfigDescriptors.size()];
         Log.d(TAG, "  " + configs.length + " configs");
         for (int index = 0; index < mConfigDescriptors.size(); index++) {
             configs[index] = mConfigDescriptors.get(index).toAndroid(parser);
         }
-        device.setConfigurations(configs);
+        UsbDevice.Builder device = new UsbDevice.Builder(parser.getDeviceAddr(), mVendorID,
+                mProductID, mDevClass, mDevSubClass, mProtocol, mfgName, prodName, versionString,
+                configs, serialStr);
 
         return device;
     }