Loading core/java/android/hardware/usb/IUsbManager.aidl +2 −2 Original line number Diff line number Diff line Loading @@ -34,7 +34,7 @@ interface IUsbManager /* Returns a file descriptor for communicating with the USB device. * The native fd can be passed to usb_device_new() in libusbhost. */ ParcelFileDescriptor openDevice(String deviceName); ParcelFileDescriptor openDevice(String deviceName, String packageName); /* Returns the currently attached USB accessory */ UsbAccessory getCurrentAccessory(); Loading @@ -55,7 +55,7 @@ interface IUsbManager 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); boolean hasDevicePermission(in UsbDevice device, String packageName); /* Returns true if the caller has permission to access the accessory. */ boolean hasAccessoryPermission(in UsbAccessory accessory); Loading core/java/android/hardware/usb/UsbManager.java +9 −2 Original line number Diff line number Diff line Loading @@ -344,7 +344,7 @@ public class UsbManager { public UsbDeviceConnection openDevice(UsbDevice device) { try { String deviceName = device.getDeviceName(); ParcelFileDescriptor pfd = mService.openDevice(deviceName); ParcelFileDescriptor pfd = mService.openDevice(deviceName, mContext.getPackageName()); if (pfd != null) { UsbDeviceConnection connection = new UsbDeviceConnection(device); boolean result = connection.open(deviceName, pfd, mContext); Loading Loading @@ -400,6 +400,9 @@ public class UsbManager { * Permission might have been granted temporarily via * {@link #requestPermission(UsbDevice, PendingIntent)} or * by the user choosing the caller as the default application for the device. * Permission for USB devices of class {@link UsbConstants#USB_CLASS_VIDEO} for clients that * target SDK {@link android.os.Build.VERSION_CODES#P} and above can be granted only if they * have additionally the {@link android.Manifest.permission#CAMERA} permission. * * @param device to check permissions for * @return true if caller has permission Loading @@ -409,7 +412,7 @@ public class UsbManager { return false; } try { return mService.hasDevicePermission(device); return mService.hasDevicePermission(device, mContext.getPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading Loading @@ -450,6 +453,10 @@ public class UsbManager { * permission was granted by the user * </ul> * * Permission for USB devices of class {@link UsbConstants#USB_CLASS_VIDEO} for clients that * target SDK {@link android.os.Build.VERSION_CODES#P} and above can be granted only if they * have additionally the {@link android.Manifest.permission#CAMERA} permission. * * @param device to request permissions for * @param pi PendingIntent for returning result */ Loading services/usb/java/com/android/server/usb/UsbHostManager.java +3 −2 Original line number Diff line number Diff line Loading @@ -323,7 +323,8 @@ public class UsbHostManager { } /* Opens the specified USB device */ public ParcelFileDescriptor openDevice(String deviceName, UsbUserSettingsManager settings) { public ParcelFileDescriptor openDevice(String deviceName, UsbUserSettingsManager settings, String packageName, int uid) { synchronized (mLock) { if (isBlackListed(deviceName)) { throw new SecurityException("USB device is on a restricted bus"); Loading @@ -334,7 +335,7 @@ public class UsbHostManager { throw new IllegalArgumentException( "device " + deviceName + " does not exist or is restricted"); } settings.checkPermission(device); settings.checkPermission(device, packageName, uid); return nativeOpenDevice(deviceName); } } Loading services/usb/java/com/android/server/usb/UsbService.java +8 −5 Original line number Diff line number Diff line Loading @@ -232,7 +232,7 @@ public class UsbService extends IUsbManager.Stub { /* Opens the specified USB device (host mode) */ @Override public ParcelFileDescriptor openDevice(String deviceName) { public ParcelFileDescriptor openDevice(String deviceName, String packageName) { ParcelFileDescriptor fd = null; if (mHostManager != null) { Loading @@ -242,7 +242,8 @@ public class UsbService extends IUsbManager.Stub { boolean isCurrentUser = isCallerInCurrentUserProfileGroupLocked(); if (isCurrentUser) { fd = mHostManager.openDevice(deviceName, getSettingsForUser(userIdInt)); fd = mHostManager.openDevice(deviceName, getSettingsForUser(userIdInt), packageName, Binder.getCallingUid()); } else { Slog.w(TAG, "Cannot open " + deviceName + " for user " + userIdInt + " as user is not active."); Loading Loading @@ -308,9 +309,10 @@ public class UsbService extends IUsbManager.Stub { } @Override public boolean hasDevicePermission(UsbDevice device) { public boolean hasDevicePermission(UsbDevice device, String packageName) { final int userId = UserHandle.getCallingUserId(); return getSettingsForUser(userId).hasPermission(device); return getSettingsForUser(userId).hasPermission(device, packageName, Binder.getCallingUid()); } @Override Loading @@ -322,7 +324,8 @@ public class UsbService extends IUsbManager.Stub { @Override public void requestDevicePermission(UsbDevice device, String packageName, PendingIntent pi) { final int userId = UserHandle.getCallingUserId(); getSettingsForUser(userId).requestPermission(device, packageName, pi); getSettingsForUser(userId).requestPermission(device, packageName, pi, Binder.getCallingUid()); } @Override Loading services/usb/java/com/android/server/usb/UsbUserSettingsManager.java +80 −6 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbInterface; import android.hardware.usb.UsbConstants; import android.hardware.usb.UsbManager; import android.os.Binder; import android.os.Process; Loading Loading @@ -95,10 +97,70 @@ class UsbUserSettingsManager { } } /** * Check whether a particular device or any of its interfaces * is of class VIDEO. * * @param device The device that needs to get scanned * @return True in case a VIDEO device or interface is present, * False otherwise. */ private boolean isCameraDevicePresent(UsbDevice device) { if (device.getDeviceClass() == UsbConstants.USB_CLASS_VIDEO) { return true; } for (int i = 0; i < device.getInterfaceCount(); i++) { UsbInterface iface = device.getInterface(i); if (iface.getInterfaceClass() == UsbConstants.USB_CLASS_VIDEO) { return true; } } return false; } /** * Check for camera permission of the calling process. * * @param packageName Package name of the caller. * @param uid Linux uid of the calling process. * * @return True in case camera permission is available, False otherwise. */ private boolean isCameraPermissionGranted(String packageName, int uid) { int targetSdkVersion = android.os.Build.VERSION_CODES.P; try { ApplicationInfo aInfo = mPackageManager.getApplicationInfo(packageName, 0); // compare uid with packageName to foil apps pretending to be someone else if (aInfo.uid != uid) { Slog.i(TAG, "Package " + packageName + " does not match caller's uid " + uid); return false; } targetSdkVersion = aInfo.targetSdkVersion; } catch (PackageManager.NameNotFoundException e) { Slog.i(TAG, "Package not found, likely due to invalid package name!"); return false; } if (targetSdkVersion >= android.os.Build.VERSION_CODES.P) { int allowed = mUserContext.checkCallingPermission(android.Manifest.permission.CAMERA); if (android.content.pm.PackageManager.PERMISSION_DENIED == allowed) { Slog.i(TAG, "Camera permission required for USB video class devices"); return false; } } return true; } public boolean hasPermission(UsbDevice device) { public boolean hasPermission(UsbDevice device, String packageName, int uid) { synchronized (mLock) { int uid = Binder.getCallingUid(); if (isCameraDevicePresent(device)) { if (!isCameraPermissionGranted(packageName, uid)) { return false; } } if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) { return true; } Loading @@ -124,8 +186,8 @@ class UsbUserSettingsManager { } } public void checkPermission(UsbDevice device) { if (!hasPermission(device)) { 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); } } Loading Loading @@ -166,11 +228,11 @@ class UsbUserSettingsManager { } } public void requestPermission(UsbDevice device, String packageName, PendingIntent pi) { public void requestPermission(UsbDevice device, String packageName, PendingIntent pi, int uid) { Intent intent = new Intent(); // respond immediately if permission has already been granted if (hasPermission(device)) { if (hasPermission(device, packageName, uid)) { intent.putExtra(UsbManager.EXTRA_DEVICE, device); intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true); try { Loading @@ -180,6 +242,18 @@ class UsbUserSettingsManager { } return; } if (isCameraDevicePresent(device)) { if (!isCameraPermissionGranted(packageName, uid)) { intent.putExtra(UsbManager.EXTRA_DEVICE, device); intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false); try { pi.send(mUserContext, 0, intent); } catch (PendingIntent.CanceledException e) { if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled"); } return; } } // start UsbPermissionActivity so user can choose an activity intent.putExtra(UsbManager.EXTRA_DEVICE, device); Loading Loading
core/java/android/hardware/usb/IUsbManager.aidl +2 −2 Original line number Diff line number Diff line Loading @@ -34,7 +34,7 @@ interface IUsbManager /* Returns a file descriptor for communicating with the USB device. * The native fd can be passed to usb_device_new() in libusbhost. */ ParcelFileDescriptor openDevice(String deviceName); ParcelFileDescriptor openDevice(String deviceName, String packageName); /* Returns the currently attached USB accessory */ UsbAccessory getCurrentAccessory(); Loading @@ -55,7 +55,7 @@ interface IUsbManager 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); boolean hasDevicePermission(in UsbDevice device, String packageName); /* Returns true if the caller has permission to access the accessory. */ boolean hasAccessoryPermission(in UsbAccessory accessory); Loading
core/java/android/hardware/usb/UsbManager.java +9 −2 Original line number Diff line number Diff line Loading @@ -344,7 +344,7 @@ public class UsbManager { public UsbDeviceConnection openDevice(UsbDevice device) { try { String deviceName = device.getDeviceName(); ParcelFileDescriptor pfd = mService.openDevice(deviceName); ParcelFileDescriptor pfd = mService.openDevice(deviceName, mContext.getPackageName()); if (pfd != null) { UsbDeviceConnection connection = new UsbDeviceConnection(device); boolean result = connection.open(deviceName, pfd, mContext); Loading Loading @@ -400,6 +400,9 @@ public class UsbManager { * Permission might have been granted temporarily via * {@link #requestPermission(UsbDevice, PendingIntent)} or * by the user choosing the caller as the default application for the device. * Permission for USB devices of class {@link UsbConstants#USB_CLASS_VIDEO} for clients that * target SDK {@link android.os.Build.VERSION_CODES#P} and above can be granted only if they * have additionally the {@link android.Manifest.permission#CAMERA} permission. * * @param device to check permissions for * @return true if caller has permission Loading @@ -409,7 +412,7 @@ public class UsbManager { return false; } try { return mService.hasDevicePermission(device); return mService.hasDevicePermission(device, mContext.getPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading Loading @@ -450,6 +453,10 @@ public class UsbManager { * permission was granted by the user * </ul> * * Permission for USB devices of class {@link UsbConstants#USB_CLASS_VIDEO} for clients that * target SDK {@link android.os.Build.VERSION_CODES#P} and above can be granted only if they * have additionally the {@link android.Manifest.permission#CAMERA} permission. * * @param device to request permissions for * @param pi PendingIntent for returning result */ Loading
services/usb/java/com/android/server/usb/UsbHostManager.java +3 −2 Original line number Diff line number Diff line Loading @@ -323,7 +323,8 @@ public class UsbHostManager { } /* Opens the specified USB device */ public ParcelFileDescriptor openDevice(String deviceName, UsbUserSettingsManager settings) { public ParcelFileDescriptor openDevice(String deviceName, UsbUserSettingsManager settings, String packageName, int uid) { synchronized (mLock) { if (isBlackListed(deviceName)) { throw new SecurityException("USB device is on a restricted bus"); Loading @@ -334,7 +335,7 @@ public class UsbHostManager { throw new IllegalArgumentException( "device " + deviceName + " does not exist or is restricted"); } settings.checkPermission(device); settings.checkPermission(device, packageName, uid); return nativeOpenDevice(deviceName); } } Loading
services/usb/java/com/android/server/usb/UsbService.java +8 −5 Original line number Diff line number Diff line Loading @@ -232,7 +232,7 @@ public class UsbService extends IUsbManager.Stub { /* Opens the specified USB device (host mode) */ @Override public ParcelFileDescriptor openDevice(String deviceName) { public ParcelFileDescriptor openDevice(String deviceName, String packageName) { ParcelFileDescriptor fd = null; if (mHostManager != null) { Loading @@ -242,7 +242,8 @@ public class UsbService extends IUsbManager.Stub { boolean isCurrentUser = isCallerInCurrentUserProfileGroupLocked(); if (isCurrentUser) { fd = mHostManager.openDevice(deviceName, getSettingsForUser(userIdInt)); fd = mHostManager.openDevice(deviceName, getSettingsForUser(userIdInt), packageName, Binder.getCallingUid()); } else { Slog.w(TAG, "Cannot open " + deviceName + " for user " + userIdInt + " as user is not active."); Loading Loading @@ -308,9 +309,10 @@ public class UsbService extends IUsbManager.Stub { } @Override public boolean hasDevicePermission(UsbDevice device) { public boolean hasDevicePermission(UsbDevice device, String packageName) { final int userId = UserHandle.getCallingUserId(); return getSettingsForUser(userId).hasPermission(device); return getSettingsForUser(userId).hasPermission(device, packageName, Binder.getCallingUid()); } @Override Loading @@ -322,7 +324,8 @@ public class UsbService extends IUsbManager.Stub { @Override public void requestDevicePermission(UsbDevice device, String packageName, PendingIntent pi) { final int userId = UserHandle.getCallingUserId(); getSettingsForUser(userId).requestPermission(device, packageName, pi); getSettingsForUser(userId).requestPermission(device, packageName, pi, Binder.getCallingUid()); } @Override Loading
services/usb/java/com/android/server/usb/UsbUserSettingsManager.java +80 −6 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbInterface; import android.hardware.usb.UsbConstants; import android.hardware.usb.UsbManager; import android.os.Binder; import android.os.Process; Loading Loading @@ -95,10 +97,70 @@ class UsbUserSettingsManager { } } /** * Check whether a particular device or any of its interfaces * is of class VIDEO. * * @param device The device that needs to get scanned * @return True in case a VIDEO device or interface is present, * False otherwise. */ private boolean isCameraDevicePresent(UsbDevice device) { if (device.getDeviceClass() == UsbConstants.USB_CLASS_VIDEO) { return true; } for (int i = 0; i < device.getInterfaceCount(); i++) { UsbInterface iface = device.getInterface(i); if (iface.getInterfaceClass() == UsbConstants.USB_CLASS_VIDEO) { return true; } } return false; } /** * Check for camera permission of the calling process. * * @param packageName Package name of the caller. * @param uid Linux uid of the calling process. * * @return True in case camera permission is available, False otherwise. */ private boolean isCameraPermissionGranted(String packageName, int uid) { int targetSdkVersion = android.os.Build.VERSION_CODES.P; try { ApplicationInfo aInfo = mPackageManager.getApplicationInfo(packageName, 0); // compare uid with packageName to foil apps pretending to be someone else if (aInfo.uid != uid) { Slog.i(TAG, "Package " + packageName + " does not match caller's uid " + uid); return false; } targetSdkVersion = aInfo.targetSdkVersion; } catch (PackageManager.NameNotFoundException e) { Slog.i(TAG, "Package not found, likely due to invalid package name!"); return false; } if (targetSdkVersion >= android.os.Build.VERSION_CODES.P) { int allowed = mUserContext.checkCallingPermission(android.Manifest.permission.CAMERA); if (android.content.pm.PackageManager.PERMISSION_DENIED == allowed) { Slog.i(TAG, "Camera permission required for USB video class devices"); return false; } } return true; } public boolean hasPermission(UsbDevice device) { public boolean hasPermission(UsbDevice device, String packageName, int uid) { synchronized (mLock) { int uid = Binder.getCallingUid(); if (isCameraDevicePresent(device)) { if (!isCameraPermissionGranted(packageName, uid)) { return false; } } if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) { return true; } Loading @@ -124,8 +186,8 @@ class UsbUserSettingsManager { } } public void checkPermission(UsbDevice device) { if (!hasPermission(device)) { 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); } } Loading Loading @@ -166,11 +228,11 @@ class UsbUserSettingsManager { } } public void requestPermission(UsbDevice device, String packageName, PendingIntent pi) { public void requestPermission(UsbDevice device, String packageName, PendingIntent pi, int uid) { Intent intent = new Intent(); // respond immediately if permission has already been granted if (hasPermission(device)) { if (hasPermission(device, packageName, uid)) { intent.putExtra(UsbManager.EXTRA_DEVICE, device); intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true); try { Loading @@ -180,6 +242,18 @@ class UsbUserSettingsManager { } return; } if (isCameraDevicePresent(device)) { if (!isCameraPermissionGranted(packageName, uid)) { intent.putExtra(UsbManager.EXTRA_DEVICE, device); intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false); try { pi.send(mUserContext, 0, intent); } catch (PendingIntent.CanceledException e) { if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled"); } return; } } // start UsbPermissionActivity so user can choose an activity intent.putExtra(UsbManager.EXTRA_DEVICE, device); Loading