Merge "Separate Usb permissions from Usb settings"
This commit is contained in:
committed by
Android (Google) Code Review
commit
9727c0581a
@@ -250,7 +250,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
|
||||
}
|
||||
|
||||
public UsbDeviceManager(Context context, UsbAlsaManager alsaManager,
|
||||
UsbSettingsManager settingsManager) {
|
||||
UsbSettingsManager settingsManager, UsbPermissionManager permissionManager) {
|
||||
mContext = context;
|
||||
mContentResolver = context.getContentResolver();
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
@@ -284,13 +284,13 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
|
||||
* Initialze the legacy UsbHandler
|
||||
*/
|
||||
mHandler = new UsbHandlerLegacy(FgThread.get().getLooper(), mContext, this,
|
||||
alsaManager, settingsManager);
|
||||
alsaManager, permissionManager);
|
||||
} else {
|
||||
/**
|
||||
* Initialize HAL based UsbHandler
|
||||
*/
|
||||
mHandler = new UsbHandlerHal(FgThread.get().getLooper(), mContext, this,
|
||||
alsaManager, settingsManager);
|
||||
alsaManager, permissionManager);
|
||||
}
|
||||
|
||||
if (nativeIsStartRequested()) {
|
||||
@@ -468,7 +468,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
|
||||
|
||||
private final Context mContext;
|
||||
private final UsbAlsaManager mUsbAlsaManager;
|
||||
private final UsbSettingsManager mSettingsManager;
|
||||
private final UsbPermissionManager mPermissionManager;
|
||||
private NotificationManager mNotificationManager;
|
||||
|
||||
protected long mScreenUnlockedFunctions;
|
||||
@@ -489,12 +489,12 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
|
||||
protected static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config";
|
||||
|
||||
UsbHandler(Looper looper, Context context, UsbDeviceManager deviceManager,
|
||||
UsbAlsaManager alsaManager, UsbSettingsManager settingsManager) {
|
||||
UsbAlsaManager alsaManager, UsbPermissionManager permissionManager) {
|
||||
super(looper);
|
||||
mContext = context;
|
||||
mUsbDeviceManager = deviceManager;
|
||||
mUsbAlsaManager = alsaManager;
|
||||
mSettingsManager = settingsManager;
|
||||
mPermissionManager = permissionManager;
|
||||
mContentResolver = context.getContentResolver();
|
||||
|
||||
mCurrentUser = ActivityManager.getCurrentUser();
|
||||
@@ -625,7 +625,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
|
||||
// successfully entered accessory mode
|
||||
String[] accessoryStrings = mUsbDeviceManager.getAccessoryStrings();
|
||||
if (accessoryStrings != null) {
|
||||
UsbSerialReader serialReader = new UsbSerialReader(mContext, mSettingsManager,
|
||||
UsbSerialReader serialReader = new UsbSerialReader(mContext, mPermissionManager,
|
||||
accessoryStrings[UsbAccessory.SERIAL_STRING]);
|
||||
|
||||
mCurrentAccessory = new UsbAccessory(
|
||||
@@ -663,7 +663,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
|
||||
|
||||
if (mCurrentAccessory != null) {
|
||||
if (mBootCompleted) {
|
||||
mSettingsManager.usbAccessoryRemoved(mCurrentAccessory);
|
||||
mPermissionManager.usbAccessoryRemoved(mCurrentAccessory);
|
||||
}
|
||||
mCurrentAccessory = null;
|
||||
}
|
||||
@@ -1343,8 +1343,8 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
|
||||
private boolean mUsbDataUnlocked;
|
||||
|
||||
UsbHandlerLegacy(Looper looper, Context context, UsbDeviceManager deviceManager,
|
||||
UsbAlsaManager alsaManager, UsbSettingsManager settingsManager) {
|
||||
super(looper, context, deviceManager, alsaManager, settingsManager);
|
||||
UsbAlsaManager alsaManager, UsbPermissionManager permissionManager) {
|
||||
super(looper, context, deviceManager, alsaManager, permissionManager);
|
||||
try {
|
||||
readOemUsbOverrideConfig(context);
|
||||
// Restore default functions.
|
||||
@@ -1738,8 +1738,8 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
|
||||
protected boolean mCurrentUsbFunctionsRequested;
|
||||
|
||||
UsbHandlerHal(Looper looper, Context context, UsbDeviceManager deviceManager,
|
||||
UsbAlsaManager alsaManager, UsbSettingsManager settingsManager) {
|
||||
super(looper, context, deviceManager, alsaManager, settingsManager);
|
||||
UsbAlsaManager alsaManager, UsbPermissionManager permissionManager) {
|
||||
super(looper, context, deviceManager, alsaManager, permissionManager);
|
||||
try {
|
||||
ServiceNotification serviceNotification = new ServiceNotification();
|
||||
|
||||
@@ -1977,7 +1977,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
|
||||
* @param uid Uid of the caller
|
||||
*/
|
||||
public ParcelFileDescriptor openAccessory(UsbAccessory accessory,
|
||||
UsbUserSettingsManager settings, int uid) {
|
||||
UsbUserPermissionManager permissions, int uid) {
|
||||
UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
|
||||
if (currentAccessory == null) {
|
||||
throw new IllegalArgumentException("no accessory attached");
|
||||
@@ -1988,7 +1988,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
|
||||
+ currentAccessory;
|
||||
throw new IllegalArgumentException(error);
|
||||
}
|
||||
settings.checkPermission(accessory, uid);
|
||||
permissions.checkPermission(accessory, uid);
|
||||
return nativeOpenAccessory();
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ public class UsbHostManager {
|
||||
private final String[] mHostBlacklist;
|
||||
|
||||
private final UsbAlsaManager mUsbAlsaManager;
|
||||
private final UsbSettingsManager mSettingsManager;
|
||||
private final UsbPermissionManager mPermissionManager;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
@GuardedBy("mLock")
|
||||
@@ -232,13 +232,13 @@ public class UsbHostManager {
|
||||
* UsbHostManager
|
||||
*/
|
||||
public UsbHostManager(Context context, UsbAlsaManager alsaManager,
|
||||
UsbSettingsManager settingsManager) {
|
||||
UsbPermissionManager permissionManager) {
|
||||
mContext = context;
|
||||
|
||||
mHostBlacklist = context.getResources().getStringArray(
|
||||
com.android.internal.R.array.config_usbHostBlacklist);
|
||||
mUsbAlsaManager = alsaManager;
|
||||
mSettingsManager = settingsManager;
|
||||
mPermissionManager = permissionManager;
|
||||
String deviceConnectionHandler = context.getResources().getString(
|
||||
com.android.internal.R.string.config_UsbDeviceConnectionHandling_component);
|
||||
if (!TextUtils.isEmpty(deviceConnectionHandler)) {
|
||||
@@ -393,8 +393,8 @@ public class UsbHostManager {
|
||||
addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT_BADDEVICE,
|
||||
parser.getRawDescriptors());
|
||||
} else {
|
||||
UsbSerialReader serialNumberReader = new UsbSerialReader(mContext, mSettingsManager,
|
||||
newDeviceBuilder.serialNumber);
|
||||
UsbSerialReader serialNumberReader = new UsbSerialReader(mContext,
|
||||
mPermissionManager, newDeviceBuilder.serialNumber);
|
||||
UsbDevice newDevice = newDeviceBuilder.build(serialNumberReader);
|
||||
serialNumberReader.setDevice(newDevice);
|
||||
|
||||
@@ -444,7 +444,7 @@ public class UsbHostManager {
|
||||
if (device != null) {
|
||||
Slog.d(TAG, "Removed device at " + deviceAddress + ": " + device.getProductName());
|
||||
mUsbAlsaManager.usbDeviceRemoved(deviceAddress);
|
||||
mSettingsManager.usbDeviceRemoved(device);
|
||||
mPermissionManager.usbDeviceRemoved(device);
|
||||
getCurrentUserSettings().usbDeviceRemoved(device);
|
||||
ConnectionRecord current = mConnected.get(deviceAddress);
|
||||
// Tracking
|
||||
@@ -484,9 +484,11 @@ public class UsbHostManager {
|
||||
}
|
||||
}
|
||||
|
||||
/* Opens the specified USB device */
|
||||
public ParcelFileDescriptor openDevice(String deviceAddress, UsbUserSettingsManager settings,
|
||||
String packageName, int uid) {
|
||||
/**
|
||||
* Opens the specified USB device
|
||||
*/
|
||||
public ParcelFileDescriptor openDevice(String deviceAddress,
|
||||
UsbUserPermissionManager permissions, String packageName, int uid) {
|
||||
synchronized (mLock) {
|
||||
if (isBlackListed(deviceAddress)) {
|
||||
throw new SecurityException("USB device is on a restricted bus");
|
||||
@@ -498,7 +500,7 @@ public class UsbHostManager {
|
||||
"device " + deviceAddress + " does not exist or is restricted");
|
||||
}
|
||||
|
||||
settings.checkPermission(device, packageName, uid);
|
||||
permissions.checkPermission(device, packageName, uid);
|
||||
return nativeOpenDevice(deviceAddress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
* Copyright (C) 2019 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.
|
||||
@@ -17,230 +17,95 @@
|
||||
package com.android.server.usb;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.hardware.usb.UsbAccessory;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbManager;
|
||||
import android.os.Binder;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.service.usb.UsbSettingsAccessoryPermissionProto;
|
||||
import android.service.usb.UsbSettingsDevicePermissionProto;
|
||||
import android.service.usb.UsbUserSettingsManagerProto;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.util.dump.DualDumpOutputStream;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* UsbPermissionManager manages usb device or accessory access permissions.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
class UsbPermissionManager {
|
||||
private static final String LOG_TAG = UsbPermissionManager.class.getSimpleName();
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
/** Temporary mapping USB device name to list of UIDs with permissions for the device*/
|
||||
private final HashMap<String, SparseBooleanArray> mDevicePermissionMap =
|
||||
new HashMap<>();
|
||||
@GuardedBy("mLock")
|
||||
/** Temporary mapping UsbAccessory to list of UIDs with permissions for the accessory*/
|
||||
private final HashMap<UsbAccessory, SparseBooleanArray> mAccessoryPermissionMap =
|
||||
new HashMap<>();
|
||||
/** Context to be used by this module */
|
||||
private final @NonNull Context mContext;
|
||||
|
||||
private final UserHandle mUser;
|
||||
private final boolean mDisablePermissionDialogs;
|
||||
/** Map from user id to {@link UsbUserPermissionManager} for the user */
|
||||
@GuardedBy("mPermissionsByUser")
|
||||
private final SparseArray<UsbUserPermissionManager> mPermissionsByUser = new SparseArray<>();
|
||||
|
||||
private final Object mLock = new Object();
|
||||
final UsbService mUsbService;
|
||||
|
||||
UsbPermissionManager(@NonNull Context context, @NonNull UserHandle user) {
|
||||
mUser = user;
|
||||
mDisablePermissionDialogs = context.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_disableUsbPermissionDialogs);
|
||||
UsbPermissionManager(@NonNull Context context,
|
||||
@NonNull UsbService usbService) {
|
||||
mContext = context;
|
||||
mUsbService = usbService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes access permissions of all packages for the USB accessory.
|
||||
*
|
||||
* @param accessory to remove permissions for
|
||||
*/
|
||||
void removeAccessoryPermissions(@NonNull UsbAccessory accessory) {
|
||||
synchronized (mLock) {
|
||||
mAccessoryPermissionMap.remove(accessory);
|
||||
@NonNull UsbUserPermissionManager getPermissionsForUser(@UserIdInt int userId) {
|
||||
synchronized (mPermissionsByUser) {
|
||||
UsbUserPermissionManager permissions = mPermissionsByUser.get(userId);
|
||||
if (permissions == null) {
|
||||
permissions = new UsbUserPermissionManager(mContext, UserHandle.of(userId),
|
||||
mUsbService.getSettingsForUser(userId));
|
||||
mPermissionsByUser.put(userId, permissions);
|
||||
}
|
||||
return permissions;
|
||||
}
|
||||
}
|
||||
|
||||
void remove(@NonNull UserHandle userToRemove) {
|
||||
synchronized (mPermissionsByUser) {
|
||||
mPermissionsByUser.remove(userToRemove.getIdentifier());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes access permissions of all packages for the USB device.
|
||||
* Remove temporary access permission and broadcast that a device was removed.
|
||||
*
|
||||
* @param device to remove permissions for
|
||||
* @param device The device that is removed
|
||||
*/
|
||||
void removeDevicePermissions(@NonNull UsbDevice device) {
|
||||
synchronized (mLock) {
|
||||
mDevicePermissionMap.remove(device.getDeviceName());
|
||||
void usbDeviceRemoved(@NonNull UsbDevice device) {
|
||||
synchronized (mPermissionsByUser) {
|
||||
for (int i = 0; i < mPermissionsByUser.size(); i++) {
|
||||
// clear temporary permissions for the device
|
||||
mPermissionsByUser.valueAt(i).removeDevicePermissions(device);
|
||||
}
|
||||
}
|
||||
|
||||
Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
|
||||
intent.putExtra(UsbManager.EXTRA_DEVICE, device);
|
||||
|
||||
if (DEBUG) {
|
||||
Slog.d(LOG_TAG, "usbDeviceRemoved, sending " + intent);
|
||||
}
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Grants permission for USB device without showing system dialog for package with uid.
|
||||
* Remove temporary access permission and broadcast that a accessory was removed.
|
||||
*
|
||||
* @param device to grant permission for
|
||||
* @param uid to grant permission for
|
||||
* @param accessory The accessory that is removed
|
||||
*/
|
||||
void grantDevicePermission(@NonNull UsbDevice device, int uid) {
|
||||
synchronized (mLock) {
|
||||
String deviceName = device.getDeviceName();
|
||||
SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName);
|
||||
if (uidList == null) {
|
||||
uidList = new SparseBooleanArray(1);
|
||||
mDevicePermissionMap.put(deviceName, uidList);
|
||||
void usbAccessoryRemoved(@NonNull UsbAccessory accessory) {
|
||||
synchronized (mPermissionsByUser) {
|
||||
for (int i = 0; i < mPermissionsByUser.size(); i++) {
|
||||
// clear temporary permissions for the accessory
|
||||
mPermissionsByUser.valueAt(i).removeAccessoryPermissions(accessory);
|
||||
}
|
||||
uidList.put(uid, true);
|
||||
}
|
||||
|
||||
Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
|
||||
intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Grants permission for USB accessory without showing system dialog for package with uid.
|
||||
*
|
||||
* @param accessory to grant permission for
|
||||
* @param uid to grant permission for
|
||||
*/
|
||||
void grantAccessoryPermission(@NonNull UsbAccessory accessory, int uid) {
|
||||
synchronized (mLock) {
|
||||
SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
|
||||
if (uidList == null) {
|
||||
uidList = new SparseBooleanArray(1);
|
||||
mAccessoryPermissionMap.put(accessory, uidList);
|
||||
}
|
||||
uidList.put(uid, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if package with uid has permission to access the device.
|
||||
*
|
||||
* @param device to check permission for
|
||||
* @param uid to check permission for
|
||||
* @return {@code true} if package with uid has permission
|
||||
*/
|
||||
boolean hasPermission(@NonNull UsbDevice device, int uid) {
|
||||
synchronized (mLock) {
|
||||
if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) {
|
||||
return true;
|
||||
}
|
||||
SparseBooleanArray uidList = mDevicePermissionMap.get(device.getDeviceName());
|
||||
if (uidList == null) {
|
||||
return false;
|
||||
}
|
||||
return uidList.get(uid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, int uid) {
|
||||
synchronized (mLock) {
|
||||
if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) {
|
||||
return true;
|
||||
}
|
||||
SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
|
||||
if (uidList == null) {
|
||||
return false;
|
||||
}
|
||||
return uidList.get(uid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates UI dialog to request permission for the given package to access the device
|
||||
* or accessory.
|
||||
*
|
||||
* @param device The USB device attached
|
||||
* @param accessory The USB accessory attached
|
||||
* @param canBeDefault Whether the calling pacakge can set as default handler
|
||||
* of the USB device or accessory
|
||||
* @param packageName The package name of the calling package
|
||||
* @param uid The uid of the calling package
|
||||
* @param userContext The context to start the UI dialog
|
||||
* @param pi PendingIntent for returning result
|
||||
*/
|
||||
void requestPermissionDialog(@Nullable UsbDevice device,
|
||||
@Nullable UsbAccessory accessory,
|
||||
boolean canBeDefault,
|
||||
@NonNull String packageName,
|
||||
int uid,
|
||||
@NonNull Context userContext,
|
||||
@NonNull PendingIntent pi) {
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
Intent intent = new Intent();
|
||||
if (device != null) {
|
||||
intent.putExtra(UsbManager.EXTRA_DEVICE, device);
|
||||
} else {
|
||||
intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
|
||||
}
|
||||
intent.putExtra(Intent.EXTRA_INTENT, pi);
|
||||
intent.putExtra(Intent.EXTRA_UID, uid);
|
||||
intent.putExtra(UsbManager.EXTRA_CAN_BE_DEFAULT, canBeDefault);
|
||||
intent.putExtra(UsbManager.EXTRA_PACKAGE, packageName);
|
||||
intent.setClassName("com.android.systemui",
|
||||
"com.android.systemui.usb.UsbPermissionActivity");
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
|
||||
try {
|
||||
userContext.startActivityAsUser(intent, mUser);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Slog.e(LOG_TAG, "unable to start UsbPermissionActivity");
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
void dump(@NonNull DualDumpOutputStream dump) {
|
||||
synchronized (mLock) {
|
||||
for (String deviceName : mDevicePermissionMap.keySet()) {
|
||||
long devicePermissionToken = dump.start("device_permissions",
|
||||
UsbUserSettingsManagerProto.DEVICE_PERMISSIONS);
|
||||
|
||||
dump.write("device_name", UsbSettingsDevicePermissionProto.DEVICE_NAME, deviceName);
|
||||
|
||||
SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName);
|
||||
int count = uidList.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
dump.write("uids", UsbSettingsDevicePermissionProto.UIDS, uidList.keyAt(i));
|
||||
}
|
||||
|
||||
dump.end(devicePermissionToken);
|
||||
}
|
||||
|
||||
for (UsbAccessory accessory : mAccessoryPermissionMap.keySet()) {
|
||||
long accessoryPermissionToken = dump.start("accessory_permissions",
|
||||
UsbUserSettingsManagerProto.ACCESSORY_PERMISSIONS);
|
||||
|
||||
dump.write("accessory_description",
|
||||
UsbSettingsAccessoryPermissionProto.ACCESSORY_DESCRIPTION,
|
||||
accessory.getDescription());
|
||||
|
||||
SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
|
||||
int count = uidList.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
dump.write("uids", UsbSettingsAccessoryPermissionProto.UIDS, uidList.keyAt(i));
|
||||
}
|
||||
|
||||
dump.end(accessoryPermissionToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -783,7 +783,7 @@ class UsbProfileGroupSettingsManager {
|
||||
return;
|
||||
}
|
||||
|
||||
mSettingsManager.getSettingsForUser(UserHandle.getUserId(appInfo.uid))
|
||||
mSettingsManager.mUsbService.getPermissionsForUser(UserHandle.getUserId(appInfo.uid))
|
||||
.grantDevicePermission(device, appInfo.uid);
|
||||
|
||||
Intent activityIntent = new Intent(intent);
|
||||
@@ -844,14 +844,15 @@ class UsbProfileGroupSettingsManager {
|
||||
}
|
||||
|
||||
if (defaultActivity != null) {
|
||||
UsbUserSettingsManager defaultRIUserSettings = mSettingsManager.getSettingsForUser(
|
||||
UserHandle.getUserId(defaultActivity.applicationInfo.uid));
|
||||
UsbUserPermissionManager defaultRIUserPermissions =
|
||||
mSettingsManager.mUsbService.getPermissionsForUser(
|
||||
UserHandle.getUserId(defaultActivity.applicationInfo.uid));
|
||||
// grant permission for default activity
|
||||
if (device != null) {
|
||||
defaultRIUserSettings.
|
||||
grantDevicePermission(device, defaultActivity.applicationInfo.uid);
|
||||
defaultRIUserPermissions
|
||||
.grantDevicePermission(device, defaultActivity.applicationInfo.uid);
|
||||
} else if (accessory != null) {
|
||||
defaultRIUserSettings.grantAccessoryPermission(accessory,
|
||||
defaultRIUserPermissions.grantAccessoryPermission(accessory,
|
||||
defaultActivity.applicationInfo.uid);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ import com.android.internal.util.ArrayUtils;
|
||||
class UsbSerialReader extends IUsbSerialReader.Stub {
|
||||
private final @Nullable String mSerialNumber;
|
||||
private final @NonNull Context mContext;
|
||||
private final @NonNull UsbSettingsManager mSettingsManager;
|
||||
private final @NonNull UsbPermissionManager mPermissionManager;
|
||||
|
||||
private Object mDevice;
|
||||
|
||||
@@ -51,10 +51,10 @@ class UsbSerialReader extends IUsbSerialReader.Stub {
|
||||
* @param settingsManager The USB settings manager
|
||||
* @param serialNumber The serial number that might be read
|
||||
*/
|
||||
UsbSerialReader(@NonNull Context context, @NonNull UsbSettingsManager settingsManager,
|
||||
UsbSerialReader(@NonNull Context context, @NonNull UsbPermissionManager permissionManager,
|
||||
@Nullable String serialNumber) {
|
||||
mContext = context;
|
||||
mSettingsManager = settingsManager;
|
||||
mPermissionManager = permissionManager;
|
||||
mSerialNumber = serialNumber;
|
||||
}
|
||||
|
||||
@@ -89,13 +89,14 @@ class UsbSerialReader extends IUsbSerialReader.Stub {
|
||||
if (packageTargetSdkVersion >= Build.VERSION_CODES.Q) {
|
||||
if (mContext.checkPermission(android.Manifest.permission.MANAGE_USB, pid, uid)
|
||||
== PackageManager.PERMISSION_DENIED) {
|
||||
UsbUserSettingsManager settings = mSettingsManager.getSettingsForUser(
|
||||
UserHandle.getUserId(uid));
|
||||
|
||||
int userId = UserHandle.getUserId(uid);
|
||||
if (mDevice instanceof UsbDevice) {
|
||||
settings.checkPermission((UsbDevice) mDevice, packageName, uid);
|
||||
mPermissionManager.getPermissionsForUser(userId)
|
||||
.checkPermission((UsbDevice) mDevice, packageName, uid);
|
||||
} else {
|
||||
settings.checkPermission((UsbAccessory) mDevice, uid);
|
||||
mPermissionManager.getPermissionsForUser(userId)
|
||||
.checkPermission((UsbAccessory) mDevice, uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +121,7 @@ public class UsbService extends IUsbManager.Stub {
|
||||
private final UsbAlsaManager mAlsaManager;
|
||||
|
||||
private final UsbSettingsManager mSettingsManager;
|
||||
private final UsbPermissionManager mPermissionManager;
|
||||
|
||||
/**
|
||||
* The user id of the current user. There might be several profiles (with separate user ids)
|
||||
@@ -131,23 +132,35 @@ public class UsbService extends IUsbManager.Stub {
|
||||
|
||||
private final Object mLock = new Object();
|
||||
|
||||
private UsbUserSettingsManager getSettingsForUser(@UserIdInt int userIdInt) {
|
||||
return mSettingsManager.getSettingsForUser(userIdInt);
|
||||
/**
|
||||
* @return the {@link UsbUserSettingsManager} for the given userId
|
||||
*/
|
||||
UsbUserSettingsManager getSettingsForUser(@UserIdInt int userId) {
|
||||
return mSettingsManager.getSettingsForUser(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link UsbUserPermissionManager} for the given userId
|
||||
*/
|
||||
UsbUserPermissionManager getPermissionsForUser(@UserIdInt int userId) {
|
||||
return mPermissionManager.getPermissionsForUser(userId);
|
||||
}
|
||||
|
||||
public UsbService(Context context) {
|
||||
mContext = context;
|
||||
|
||||
mUserManager = context.getSystemService(UserManager.class);
|
||||
mSettingsManager = new UsbSettingsManager(context);
|
||||
mSettingsManager = new UsbSettingsManager(context, this);
|
||||
mPermissionManager = new UsbPermissionManager(context, this);
|
||||
mAlsaManager = new UsbAlsaManager(context);
|
||||
|
||||
final PackageManager pm = mContext.getPackageManager();
|
||||
if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
|
||||
mHostManager = new UsbHostManager(context, mAlsaManager, mSettingsManager);
|
||||
mHostManager = new UsbHostManager(context, mAlsaManager, mPermissionManager);
|
||||
}
|
||||
if (new File("/sys/class/android_usb").exists()) {
|
||||
mDeviceManager = new UsbDeviceManager(context, mAlsaManager, mSettingsManager);
|
||||
mDeviceManager = new UsbDeviceManager(context, mAlsaManager, mSettingsManager,
|
||||
mPermissionManager);
|
||||
}
|
||||
if (mHostManager != null || mDeviceManager != null) {
|
||||
mPortManager = new UsbPortManager(context);
|
||||
@@ -255,7 +268,7 @@ public class UsbService extends IUsbManager.Stub {
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
if (mUserManager.isSameProfileGroup(user, mCurrentUserId)) {
|
||||
fd = mHostManager.openDevice(deviceName, getSettingsForUser(user),
|
||||
fd = mHostManager.openDevice(deviceName, getPermissionsForUser(user),
|
||||
packageName, uid);
|
||||
} else {
|
||||
Slog.w(TAG, "Cannot open " + deviceName + " for user " + user
|
||||
@@ -292,7 +305,7 @@ public class UsbService extends IUsbManager.Stub {
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
if (mUserManager.isSameProfileGroup(user, mCurrentUserId)) {
|
||||
return mDeviceManager.openAccessory(accessory, getSettingsForUser(user),
|
||||
return mDeviceManager.openAccessory(accessory, getPermissionsForUser(user),
|
||||
uid);
|
||||
} else {
|
||||
Slog.w(TAG, "Cannot open " + accessory + " for user " + user
|
||||
@@ -354,7 +367,7 @@ public class UsbService extends IUsbManager.Stub {
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return getSettingsForUser(userId).hasPermission(device, packageName, uid);
|
||||
return getPermissionsForUser(userId).hasPermission(device, packageName, uid);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
@@ -367,7 +380,7 @@ public class UsbService extends IUsbManager.Stub {
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return getSettingsForUser(userId).hasPermission(accessory, uid);
|
||||
return getPermissionsForUser(userId).hasPermission(accessory, uid);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
@@ -380,7 +393,7 @@ public class UsbService extends IUsbManager.Stub {
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
getSettingsForUser(userId).requestPermission(device, packageName, pi, uid);
|
||||
getPermissionsForUser(userId).requestPermission(device, packageName, pi, uid);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
@@ -394,7 +407,7 @@ public class UsbService extends IUsbManager.Stub {
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
getSettingsForUser(userId).requestPermission(accessory, packageName, pi, uid);
|
||||
getPermissionsForUser(userId).requestPermission(accessory, packageName, pi, uid);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
@@ -407,7 +420,7 @@ public class UsbService extends IUsbManager.Stub {
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
getSettingsForUser(userId).grantDevicePermission(device, uid);
|
||||
getPermissionsForUser(userId).grantDevicePermission(device, uid);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
@@ -420,7 +433,7 @@ public class UsbService extends IUsbManager.Stub {
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
getSettingsForUser(userId).grantAccessoryPermission(accessory, uid);
|
||||
getPermissionsForUser(userId).grantAccessoryPermission(accessory, uid);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
|
||||
@@ -19,15 +19,10 @@ package com.android.server.usb;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.hardware.usb.UsbAccessory;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbManager;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.service.usb.UsbSettingsManagerProto;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
@@ -59,8 +54,11 @@ class UsbSettingsManager {
|
||||
private UserManager mUserManager;
|
||||
private UsbHandlerManager mUsbHandlerManager;
|
||||
|
||||
public UsbSettingsManager(@NonNull Context context) {
|
||||
final UsbService mUsbService;
|
||||
|
||||
UsbSettingsManager(@NonNull Context context, UsbService usbService) {
|
||||
mContext = context;
|
||||
mUsbService = usbService;
|
||||
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
||||
mUsbHandlerManager = new UsbHandlerManager(context);
|
||||
}
|
||||
@@ -76,8 +74,7 @@ class UsbSettingsManager {
|
||||
synchronized (mSettingsByUser) {
|
||||
UsbUserSettingsManager settings = mSettingsByUser.get(userId);
|
||||
if (settings == null) {
|
||||
settings = new UsbUserSettingsManager(mContext, UserHandle.of(userId),
|
||||
new UsbPermissionManager(mContext, UserHandle.of(userId)));
|
||||
settings = new UsbUserSettingsManager(mContext, UserHandle.of(userId));
|
||||
mSettingsByUser.put(userId, settings);
|
||||
}
|
||||
return settings;
|
||||
@@ -164,46 +161,4 @@ class UsbSettingsManager {
|
||||
|
||||
dump.end(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove temporary access permission and broadcast that a device was removed.
|
||||
*
|
||||
* @param device The device that is removed
|
||||
*/
|
||||
void usbDeviceRemoved(@NonNull UsbDevice device) {
|
||||
synchronized (mSettingsByUser) {
|
||||
for (int i = 0; i < mSettingsByUser.size(); i++) {
|
||||
// clear temporary permissions for the device
|
||||
mSettingsByUser.valueAt(i).removeDevicePermissions(device);
|
||||
}
|
||||
}
|
||||
|
||||
Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
|
||||
intent.putExtra(UsbManager.EXTRA_DEVICE, device);
|
||||
|
||||
if (DEBUG) {
|
||||
Slog.d(LOG_TAG, "usbDeviceRemoved, sending " + intent);
|
||||
}
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove temporary access permission and broadcast that a accessory was removed.
|
||||
*
|
||||
* @param accessory The accessory that is removed
|
||||
*/
|
||||
void usbAccessoryRemoved(@NonNull UsbAccessory accessory) {
|
||||
synchronized (mSettingsByUser) {
|
||||
for (int i = 0; i < mSettingsByUser.size(); i++) {
|
||||
// clear temporary permissions for the accessory
|
||||
mSettingsByUser.valueAt(i).removeAccessoryPermissions(accessory);
|
||||
}
|
||||
}
|
||||
|
||||
Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
|
||||
intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,407 @@
|
||||
/*
|
||||
* 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.app.PendingIntent;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.usb.UsbAccessory;
|
||||
import android.hardware.usb.UsbConstants;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbInterface;
|
||||
import android.hardware.usb.UsbManager;
|
||||
import android.os.Binder;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.service.usb.UsbSettingsAccessoryPermissionProto;
|
||||
import android.service.usb.UsbSettingsDevicePermissionProto;
|
||||
import android.service.usb.UsbUserSettingsManagerProto;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseBooleanArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.util.dump.DualDumpOutputStream;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* UsbUserPermissionManager manages usb device or accessory access permissions.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
class UsbUserPermissionManager {
|
||||
private static final String LOG_TAG = UsbUserPermissionManager.class.getSimpleName();
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
/** Temporary mapping USB device name to list of UIDs with permissions for the device*/
|
||||
private final HashMap<String, SparseBooleanArray> mDevicePermissionMap =
|
||||
new HashMap<>();
|
||||
@GuardedBy("mLock")
|
||||
/** Temporary mapping UsbAccessory to list of UIDs with permissions for the accessory*/
|
||||
private final HashMap<UsbAccessory, SparseBooleanArray> mAccessoryPermissionMap =
|
||||
new HashMap<>();
|
||||
|
||||
private final Context mContext;
|
||||
private final UserHandle mUser;
|
||||
private final UsbUserSettingsManager mUsbUserSettingsManager;
|
||||
private final boolean mDisablePermissionDialogs;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
|
||||
UsbUserPermissionManager(@NonNull Context context, @NonNull UserHandle user,
|
||||
@NonNull UsbUserSettingsManager usbUserSettingsManager) {
|
||||
mContext = context;
|
||||
mUser = user;
|
||||
mUsbUserSettingsManager = usbUserSettingsManager;
|
||||
mDisablePermissionDialogs = context.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_disableUsbPermissionDialogs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes access permissions of all packages for the USB accessory.
|
||||
*
|
||||
* @param accessory to remove permissions for
|
||||
*/
|
||||
void removeAccessoryPermissions(@NonNull UsbAccessory accessory) {
|
||||
synchronized (mLock) {
|
||||
mAccessoryPermissionMap.remove(accessory);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes access permissions of all packages for the USB device.
|
||||
*
|
||||
* @param device to remove permissions for
|
||||
*/
|
||||
void removeDevicePermissions(@NonNull UsbDevice device) {
|
||||
synchronized (mLock) {
|
||||
mDevicePermissionMap.remove(device.getDeviceName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Grants permission for USB device without showing system dialog for package with uid.
|
||||
*
|
||||
* @param device to grant permission for
|
||||
* @param uid to grant permission for
|
||||
*/
|
||||
void grantDevicePermission(@NonNull UsbDevice device, int uid) {
|
||||
synchronized (mLock) {
|
||||
String deviceName = device.getDeviceName();
|
||||
SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName);
|
||||
if (uidList == null) {
|
||||
uidList = new SparseBooleanArray(1);
|
||||
mDevicePermissionMap.put(deviceName, uidList);
|
||||
}
|
||||
uidList.put(uid, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Grants permission for USB accessory without showing system dialog for package with uid.
|
||||
*
|
||||
* @param accessory to grant permission for
|
||||
* @param uid to grant permission for
|
||||
*/
|
||||
void grantAccessoryPermission(@NonNull UsbAccessory accessory, int uid) {
|
||||
synchronized (mLock) {
|
||||
SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
|
||||
if (uidList == null) {
|
||||
uidList = new SparseBooleanArray(1);
|
||||
mAccessoryPermissionMap.put(accessory, uidList);
|
||||
}
|
||||
uidList.put(uid, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if package with uid has permission to access the device.
|
||||
*
|
||||
* @param device to check permission for
|
||||
* @param uid to check permission for
|
||||
* @return {@code true} if package with uid has permission
|
||||
*/
|
||||
boolean hasPermission(@NonNull UsbDevice device, int uid) {
|
||||
synchronized (mLock) {
|
||||
if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) {
|
||||
return true;
|
||||
}
|
||||
SparseBooleanArray uidList = mDevicePermissionMap.get(device.getDeviceName());
|
||||
if (uidList == null) {
|
||||
return false;
|
||||
}
|
||||
return uidList.get(uid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, int uid) {
|
||||
synchronized (mLock) {
|
||||
if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) {
|
||||
return true;
|
||||
}
|
||||
SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
|
||||
if (uidList == null) {
|
||||
return false;
|
||||
}
|
||||
return uidList.get(uid);
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasPermission(UsbDevice device, String packageName, int uid) {
|
||||
if (isCameraDevicePresent(device)) {
|
||||
if (!isCameraPermissionGranted(packageName, uid)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return hasPermission(device, uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates UI dialog to request permission for the given package to access the device
|
||||
* or accessory.
|
||||
*
|
||||
* @param device The USB device attached
|
||||
* @param accessory The USB accessory attached
|
||||
* @param canBeDefault Whether the calling pacakge can set as default handler
|
||||
* of the USB device or accessory
|
||||
* @param packageName The package name of the calling package
|
||||
* @param uid The uid of the calling package
|
||||
* @param userContext The context to start the UI dialog
|
||||
* @param pi PendingIntent for returning result
|
||||
*/
|
||||
void requestPermissionDialog(@Nullable UsbDevice device,
|
||||
@Nullable UsbAccessory accessory,
|
||||
boolean canBeDefault,
|
||||
@NonNull String packageName,
|
||||
int uid,
|
||||
@NonNull Context userContext,
|
||||
@NonNull PendingIntent pi) {
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
Intent intent = new Intent();
|
||||
if (device != null) {
|
||||
intent.putExtra(UsbManager.EXTRA_DEVICE, device);
|
||||
} else {
|
||||
intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
|
||||
}
|
||||
intent.putExtra(Intent.EXTRA_INTENT, pi);
|
||||
intent.putExtra(Intent.EXTRA_UID, uid);
|
||||
intent.putExtra(UsbManager.EXTRA_CAN_BE_DEFAULT, canBeDefault);
|
||||
intent.putExtra(UsbManager.EXTRA_PACKAGE, packageName);
|
||||
intent.setClassName("com.android.systemui",
|
||||
"com.android.systemui.usb.UsbPermissionActivity");
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
|
||||
try {
|
||||
userContext.startActivityAsUser(intent, mUser);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Slog.e(LOG_TAG, "unable to start UsbPermissionActivity");
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
void dump(@NonNull DualDumpOutputStream dump) {
|
||||
synchronized (mLock) {
|
||||
for (String deviceName : mDevicePermissionMap.keySet()) {
|
||||
long devicePermissionToken = dump.start("device_permissions",
|
||||
UsbUserSettingsManagerProto.DEVICE_PERMISSIONS);
|
||||
|
||||
dump.write("device_name", UsbSettingsDevicePermissionProto.DEVICE_NAME, deviceName);
|
||||
|
||||
SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName);
|
||||
int count = uidList.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
dump.write("uids", UsbSettingsDevicePermissionProto.UIDS, uidList.keyAt(i));
|
||||
}
|
||||
|
||||
dump.end(devicePermissionToken);
|
||||
}
|
||||
|
||||
for (UsbAccessory accessory : mAccessoryPermissionMap.keySet()) {
|
||||
long accessoryPermissionToken = dump.start("accessory_permissions",
|
||||
UsbUserSettingsManagerProto.ACCESSORY_PERMISSIONS);
|
||||
|
||||
dump.write("accessory_description",
|
||||
UsbSettingsAccessoryPermissionProto.ACCESSORY_DESCRIPTION,
|
||||
accessory.getDescription());
|
||||
|
||||
SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
|
||||
int count = uidList.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
dump.write("uids", UsbSettingsAccessoryPermissionProto.UIDS, uidList.keyAt(i));
|
||||
}
|
||||
|
||||
dump.end(accessoryPermissionToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = mContext.getPackageManager().getApplicationInfo(packageName, 0);
|
||||
// compare uid with packageName to foil apps pretending to be someone else
|
||||
if (aInfo.uid != uid) {
|
||||
Slog.i(LOG_TAG, "Package " + packageName + " does not match caller's uid " + uid);
|
||||
return false;
|
||||
}
|
||||
targetSdkVersion = aInfo.targetSdkVersion;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Slog.i(LOG_TAG, "Package not found, likely due to invalid package name!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (targetSdkVersion >= android.os.Build.VERSION_CODES.P) {
|
||||
int allowed = mContext.checkCallingPermission(android.Manifest.permission.CAMERA);
|
||||
if (android.content.pm.PackageManager.PERMISSION_DENIED == allowed) {
|
||||
Slog.i(LOG_TAG, "Camera permission required for USB video class devices");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void checkPermission(UsbDevice device, String packageName, int uid) {
|
||||
if (!hasPermission(device, packageName, uid)) {
|
||||
throw new SecurityException("User has not given " + uid + "/" + packageName
|
||||
+ " permission to access device " + device.getDeviceName());
|
||||
}
|
||||
}
|
||||
|
||||
public void checkPermission(UsbAccessory accessory, int uid) {
|
||||
if (!hasPermission(accessory, uid)) {
|
||||
throw new SecurityException("User has not given " + uid + " permission to accessory "
|
||||
+ accessory);
|
||||
}
|
||||
}
|
||||
|
||||
private void requestPermissionDialog(@Nullable UsbDevice device,
|
||||
@Nullable UsbAccessory accessory,
|
||||
boolean canBeDefault,
|
||||
String packageName,
|
||||
PendingIntent pi,
|
||||
int uid) {
|
||||
// compare uid with packageName to foil apps pretending to be someone else
|
||||
try {
|
||||
ApplicationInfo aInfo = mContext.getPackageManager().getApplicationInfo(packageName, 0);
|
||||
if (aInfo.uid != uid) {
|
||||
throw new IllegalArgumentException("package " + packageName
|
||||
+ " does not match caller's uid " + uid);
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
throw new IllegalArgumentException("package " + packageName + " not found");
|
||||
}
|
||||
|
||||
requestPermissionDialog(device, accessory, canBeDefault, packageName, uid, mContext, 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, packageName, uid)) {
|
||||
intent.putExtra(UsbManager.EXTRA_DEVICE, device);
|
||||
intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
|
||||
try {
|
||||
pi.send(mContext, 0, intent);
|
||||
} catch (PendingIntent.CanceledException e) {
|
||||
if (DEBUG) Slog.d(LOG_TAG, "requestPermission PendingIntent was cancelled");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (isCameraDevicePresent(device)) {
|
||||
if (!isCameraPermissionGranted(packageName, uid)) {
|
||||
intent.putExtra(UsbManager.EXTRA_DEVICE, device);
|
||||
intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false);
|
||||
try {
|
||||
pi.send(mContext, 0, intent);
|
||||
} catch (PendingIntent.CanceledException e) {
|
||||
if (DEBUG) Slog.d(LOG_TAG, "requestPermission PendingIntent was cancelled");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
requestPermissionDialog(device, null,
|
||||
mUsbUserSettingsManager.canBeDefault(device, packageName), packageName, pi, uid);
|
||||
}
|
||||
|
||||
public void requestPermission(UsbAccessory accessory, String packageName, PendingIntent pi,
|
||||
int uid) {
|
||||
// respond immediately if permission has already been granted
|
||||
if (hasPermission(accessory, uid)) {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
|
||||
intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
|
||||
try {
|
||||
pi.send(mContext, 0, intent);
|
||||
} catch (PendingIntent.CanceledException e) {
|
||||
if (DEBUG) Slog.d(LOG_TAG, "requestPermission PendingIntent was cancelled");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
requestPermissionDialog(null, accessory,
|
||||
mUsbUserSettingsManager.canBeDefault(accessory, packageName), packageName, pi, uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -21,13 +21,10 @@ import static com.android.server.usb.UsbProfileGroupSettingsManager.getAccessory
|
||||
import static com.android.server.usb.UsbProfileGroupSettingsManager.getDeviceFilters;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
@@ -36,9 +33,7 @@ import android.content.res.XmlResourceParser;
|
||||
import android.hardware.usb.AccessoryFilter;
|
||||
import android.hardware.usb.DeviceFilter;
|
||||
import android.hardware.usb.UsbAccessory;
|
||||
import android.hardware.usb.UsbConstants;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbInterface;
|
||||
import android.hardware.usb.UsbManager;
|
||||
import android.os.UserHandle;
|
||||
import android.service.usb.UsbAccessoryAttachedActivities;
|
||||
@@ -62,12 +57,10 @@ class UsbUserSettingsManager {
|
||||
|
||||
private final Context mUserContext;
|
||||
private final PackageManager mPackageManager;
|
||||
private final UsbPermissionManager mUsbPermissionManager;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
|
||||
UsbUserSettingsManager(Context context, UserHandle user,
|
||||
@NonNull UsbPermissionManager usbPermissionManager) {
|
||||
UsbUserSettingsManager(Context context, UserHandle user) {
|
||||
if (DEBUG) Slog.v(TAG, "Creating settings for " + user);
|
||||
|
||||
try {
|
||||
@@ -79,189 +72,6 @@ class UsbUserSettingsManager {
|
||||
mPackageManager = mUserContext.getPackageManager();
|
||||
|
||||
mUser = user;
|
||||
mUsbPermissionManager = usbPermissionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all access permission for a device.
|
||||
*
|
||||
* @param device The device the permissions are for
|
||||
*/
|
||||
void removeDevicePermissions(@NonNull UsbDevice device) {
|
||||
mUsbPermissionManager.removeDevicePermissions(device);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all access permission for a accessory.
|
||||
*
|
||||
* @param accessory The accessory the permissions are for
|
||||
*/
|
||||
void removeAccessoryPermissions(@NonNull UsbAccessory accessory) {
|
||||
mUsbPermissionManager.removeAccessoryPermissions(accessory);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, String packageName, int uid) {
|
||||
if (isCameraDevicePresent(device)) {
|
||||
if (!isCameraPermissionGranted(packageName, uid)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return mUsbPermissionManager.hasPermission(device, uid);
|
||||
}
|
||||
|
||||
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 " + uid + "/" + packageName
|
||||
+ " permission to access device " + device.getDeviceName());
|
||||
}
|
||||
}
|
||||
|
||||
public void checkPermission(UsbAccessory accessory, int uid) {
|
||||
if (!hasPermission(accessory, uid)) {
|
||||
throw new SecurityException("User has not given " + uid + " permission to accessory "
|
||||
+ accessory);
|
||||
}
|
||||
}
|
||||
|
||||
private void requestPermissionDialog(@Nullable UsbDevice device,
|
||||
@Nullable UsbAccessory accessory,
|
||||
boolean canBeDefault,
|
||||
String packageName,
|
||||
PendingIntent pi,
|
||||
int uid) {
|
||||
// compare uid with packageName to foil apps pretending to be someone else
|
||||
try {
|
||||
ApplicationInfo aInfo = mPackageManager.getApplicationInfo(packageName, 0);
|
||||
if (aInfo.uid != uid) {
|
||||
throw new IllegalArgumentException("package " + packageName +
|
||||
" does not match caller's uid " + uid);
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
throw new IllegalArgumentException("package " + packageName + " not found");
|
||||
}
|
||||
|
||||
mUsbPermissionManager.requestPermissionDialog(device,
|
||||
accessory, canBeDefault, packageName, uid, mUserContext, 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, packageName, uid)) {
|
||||
intent.putExtra(UsbManager.EXTRA_DEVICE, device);
|
||||
intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
|
||||
try {
|
||||
pi.send(mUserContext, 0, intent);
|
||||
} catch (PendingIntent.CanceledException e) {
|
||||
if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled");
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
requestPermissionDialog(device, null, canBeDefault(device, packageName), packageName, pi,
|
||||
uid);
|
||||
}
|
||||
|
||||
public void requestPermission(UsbAccessory accessory, String packageName, PendingIntent pi,
|
||||
int uid) {
|
||||
// respond immediately if permission has already been granted
|
||||
if (hasPermission(accessory, uid)) {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
|
||||
intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
|
||||
try {
|
||||
pi.send(mUserContext, 0, intent);
|
||||
} catch (PendingIntent.CanceledException e) {
|
||||
if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
requestPermissionDialog(null, accessory, canBeDefault(accessory, packageName), packageName,
|
||||
pi, uid);
|
||||
}
|
||||
|
||||
public void grantDevicePermission(UsbDevice device, int uid) {
|
||||
mUsbPermissionManager.grantDevicePermission(device, uid);
|
||||
}
|
||||
|
||||
public void grantAccessoryPermission(UsbAccessory accessory, int uid) {
|
||||
mUsbPermissionManager.grantAccessoryPermission(accessory, uid);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -285,7 +95,7 @@ class UsbUserSettingsManager {
|
||||
*
|
||||
* @return {@code true} if the app can be default
|
||||
*/
|
||||
private boolean canBeDefault(@NonNull UsbDevice device, String packageName) {
|
||||
boolean canBeDefault(@NonNull UsbDevice device, String packageName) {
|
||||
ActivityInfo[] activities = getPackageActivities(packageName);
|
||||
if (activities != null) {
|
||||
int numActivities = activities.length;
|
||||
@@ -327,7 +137,7 @@ class UsbUserSettingsManager {
|
||||
*
|
||||
* @return {@code true} if the app can be default
|
||||
*/
|
||||
private boolean canBeDefault(@NonNull UsbAccessory accessory, String packageName) {
|
||||
boolean canBeDefault(@NonNull UsbAccessory accessory, String packageName) {
|
||||
ActivityInfo[] activities = getPackageActivities(packageName);
|
||||
if (activities != null) {
|
||||
int numActivities = activities.length;
|
||||
@@ -377,8 +187,6 @@ class UsbUserSettingsManager {
|
||||
synchronized (mLock) {
|
||||
dump.write("user_id", UsbUserSettingsManagerProto.USER_ID, mUser.getIdentifier());
|
||||
|
||||
mUsbPermissionManager.dump(dump);
|
||||
|
||||
List<ResolveInfo> deviceAttachedActivities = queryIntentActivities(
|
||||
new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED));
|
||||
int numDeviceAttachedActivities = deviceAttachedActivities.size();
|
||||
|
||||
@@ -63,6 +63,8 @@ public class UsbHandlerTest {
|
||||
@Mock
|
||||
private UsbSettingsManager mUsbSettingsManager;
|
||||
@Mock
|
||||
private UsbPermissionManager mUsbPermissionManager;
|
||||
@Mock
|
||||
private SharedPreferences mSharedPreferences;
|
||||
@Mock
|
||||
private SharedPreferences.Editor mEditor;
|
||||
@@ -87,8 +89,9 @@ public class UsbHandlerTest {
|
||||
Intent mBroadcastedIntent;
|
||||
|
||||
MockUsbHandler(Looper looper, Context context, UsbDeviceManager deviceManager,
|
||||
UsbAlsaManager alsaManager, UsbSettingsManager settingsManager) {
|
||||
super(looper, context, deviceManager, alsaManager, settingsManager);
|
||||
UsbAlsaManager alsaManager, UsbSettingsManager settingsManager,
|
||||
UsbPermissionManager permissionManager) {
|
||||
super(looper, context, deviceManager, alsaManager, permissionManager);
|
||||
mUseUsbNotification = false;
|
||||
mIsUsbTransferAllowed = true;
|
||||
mCurrentUsbFunctionsReceived = true;
|
||||
@@ -142,7 +145,7 @@ public class UsbHandlerTest {
|
||||
|
||||
mUsbHandler = new MockUsbHandler(FgThread.get().getLooper(),
|
||||
InstrumentationRegistry.getContext(), mUsbDeviceManager, mUsbAlsaManager,
|
||||
mUsbSettingsManager);
|
||||
mUsbSettingsManager, mUsbPermissionManager);
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
@@ -205,7 +208,7 @@ public class UsbHandlerTest {
|
||||
UsbManager.USB_FUNCTION_ADB);
|
||||
mUsbHandler = new MockUsbHandler(FgThread.get().getLooper(),
|
||||
InstrumentationRegistry.getContext(), mUsbDeviceManager, mUsbAlsaManager,
|
||||
mUsbSettingsManager);
|
||||
mUsbSettingsManager, mUsbPermissionManager);
|
||||
|
||||
sendBootCompleteMessages(mUsbHandler);
|
||||
mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_ENABLE_ADB, 0));
|
||||
@@ -228,7 +231,7 @@ public class UsbHandlerTest {
|
||||
mMockProperties.put(UsbDeviceManager.UsbHandler.USB_PERSISTENT_CONFIG_PROPERTY, "adb");
|
||||
mUsbHandler = new MockUsbHandler(FgThread.get().getLooper(),
|
||||
InstrumentationRegistry.getContext(), mUsbDeviceManager, mUsbAlsaManager,
|
||||
mUsbSettingsManager);
|
||||
mUsbSettingsManager, mUsbPermissionManager);
|
||||
|
||||
sendBootCompleteMessages(mUsbHandler);
|
||||
assertEquals(mUsbHandler.getEnabledFunctions(), UsbManager.FUNCTION_NONE);
|
||||
@@ -316,7 +319,7 @@ public class UsbHandlerTest {
|
||||
.thenReturn(UsbManager.USB_FUNCTION_MTP);
|
||||
mUsbHandler = new MockUsbHandler(FgThread.get().getLooper(),
|
||||
InstrumentationRegistry.getContext(), mUsbDeviceManager, mUsbAlsaManager,
|
||||
mUsbSettingsManager);
|
||||
mUsbSettingsManager, mUsbPermissionManager);
|
||||
sendBootCompleteMessages(mUsbHandler);
|
||||
mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_UPDATE_SCREEN_LOCK, 1));
|
||||
mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_UPDATE_SCREEN_LOCK, 0));
|
||||
|
||||
Reference in New Issue
Block a user