summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/usb/IUsbManager.aidl4
-rw-r--r--core/java/android/hardware/usb/UsbManager.java11
-rw-r--r--services/usb/java/com/android/server/usb/UsbHostManager.java5
-rw-r--r--services/usb/java/com/android/server/usb/UsbService.java13
-rw-r--r--services/usb/java/com/android/server/usb/UsbUserSettingsManager.java86
5 files changed, 102 insertions, 17 deletions
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index 025d46d12567..151e62de7b70 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -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();
@@ -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);
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 6ce96698e444..bdb90bcca4f8 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -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);
@@ -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
@@ -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();
}
@@ -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
*/
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 095fdc63975c..9bc9cd04957c 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -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");
@@ -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);
}
}
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index e4fcea77fa44..17de83f0cac9 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -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) {
@@ -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.");
@@ -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
@@ -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
diff --git a/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java b/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java
index 96c5211cecf4..11e43e308e8a 100644
--- a/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java
@@ -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;
@@ -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;
+ }
+ }
- public boolean hasPermission(UsbDevice device) {
+ return true;
+ }
+
+ 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;
}
@@ -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);
}
}
@@ -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 {
@@ -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);