getDeviceList
其调用入口位于 UsbManager中:
// frameworks/base/core/java/android/hardware/usb/UsbManager.java
private final IUsbManager mService;
@RequiresFeature(PackageManager.FEATURE_USB_HOST)
public HashMap<String,UsbDevice> getDeviceList() {
HashMap<String,UsbDevice> result = new HashMap<String,UsbDevice>();
if (mService == null) {
return result;
}
Bundle bundle = new Bundle();
try {
mService.getDeviceList(bundle);
for (String name : bundle.keySet()) {
result.put(name, (UsbDevice)bundle.get(name));
}
return result;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
实际上调用的是 IUsbManager的,也就是通过AIDL调用了对应的 UsbService 远端的实现,我们看下UsbService的实现,这里的实现就是调用UsbHostManager的对应的方法向bundle中塞入数据。(frameworks/base/services/usb/java/com/android/server/usb/UsbService.java)的。
// frameworks/base/services/usb/java/com/android/server/usb/UsbService.java
// com.android.server.usb.UsbService#getDeviceList
/* Returns a list of all currently attached USB devices (host mdoe) */
@Override
public void getDeviceList(Bundle devices) {
if (mHostManager != null) {
mHostManager.getDeviceList(devices);
}
}
UsbHostManager#getDeviceList 实现: 就是从成员变量mDevice中取出设备名称,然后塞到返回对象中,所以我们看下mDevice是何时填充的数据。
// frameworks/base/services/usb/java/com/android/server/usb/UsbHostManager.java
// com.android.server.usb.UsbHostManager#getDeviceList
/* Returns a list of all currently attached USB devices */
public void getDeviceList(Bundle devices) {
synchronized (mLock) {
for (String name : mDevices.keySet()) {
devices.putParcelable(name, mDevices.get(name));
}
}
}
mDevices 添加数据
可以看到,mDevices 改变的地方位于 usbDeviceAdded 和 usbDeviceRemoved 两个回调方法中。
调用时机:
之前已经有过分析,在UsbService初始化的时候,会添加对于usb设备目录的监听,当有设备添加或者移除时,会调用 usbDeviceAdded 和 usbDeviceRemoved 两个回调方法。
接下来看下具体实现
usbDeviceAdded
// frameworks/base/services/usb/java/com/android/server/usb/UsbHostManager.java
// com.android.server.usb.UsbHostManager#usbDeviceAdded
private boolean usbDeviceAdded(String deviceAddress, int deviceClass, int deviceSubclass,
byte[] descriptors) {
if (isBlackListed(deviceAddress)) {
return false;
}
if (isBlackListed(deviceClass, deviceSubclass)) {
return false;
}
UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress, descriptors);
if (deviceClass == UsbConstants.USB_CLASS_PER_INTERFACE
&& !checkUsbInterfacesBlackListed(parser)) {
return false;
}
// Potentially can block as it may read data from the USB device.
logUsbDevice(parser);
synchronized (mLock) {
if (mDevices.get(deviceAddress) != null) {
Slog.w(TAG, "device already on mDevices list: " + deviceAddress);
//TODO If this is the same peripheral as is being connected, replace
// it with the new connection.
return false;
}
UsbDevice.Builder newDeviceBuilder = parser.toAndroidUsbDeviceBuilder();
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,
mPermissionManager, newDeviceBuilder.serialNumber);
UsbDevice newDevice = newDeviceBuilder.build(serialNumberReader);
serialNumberReader.setDevice(newDevice);
mDevices.put(deviceAddress, newDevice);
Slog.d(TAG, "Added device " + newDevice);
// It is fine to call this only for the current user as all broadcasts are
// sent to all profiles of the user and the dialogs should only show once.
ComponentName usbDeviceConnectionHandler = getUsbDeviceConnectionHandler();
if (usbDeviceConnectionHandler == null) {
getCurrentUserSettings().deviceAttached(newDevice);
} else {
getCurrentUserSettings().deviceAttachedForFixedHandler(newDevice,
usbDeviceConnectionHandler);
}
mUsbAlsaManager.usbDeviceAdded(deviceAddress, newDevice, parser);
// Tracking
addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT,
parser.getRawDescriptors());
// Stats collection
FrameworkStatsLog.write(FrameworkStatsLog.USB_DEVICE_ATTACHED,
newDevice.getVendorId(), newDevice.getProductId(),
parser.hasAudioInterface(), parser.hasHIDInterface(),
parser.hasStorageInterface(),
FrameworkStatsLog.USB_DEVICE_ATTACHED__STATE__STATE_CONNECTED, 0);
}
}
if (DEBUG) {
Slog.d(TAG, "beginUsbDeviceAdded(" + deviceAddress + ") end");
}
return true;
}
usbDeviceRemoved
private void usbDeviceRemoved(String deviceAddress) {
if (DEBUG) {
Slog.d(TAG, "usbDeviceRemoved(" + deviceAddress + ") end");
}
synchronized (mLock) {
UsbDevice device = mDevices.remove(deviceAddress);
if (device != null) {
Slog.d(TAG, "Removed device at " + deviceAddress + ": " + device.getProductName());
mUsbAlsaManager.usbDeviceRemoved(deviceAddress);
mPermissionManager.usbDeviceRemoved(device);
getCurrentUserSettings().usbDeviceRemoved(device);
ConnectionRecord current = mConnected.get(deviceAddress);
// Tracking
addConnectionRecord(deviceAddress, ConnectionRecord.DISCONNECT, null);
if (current != null) {
UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress,
current.mDescriptors);
// Stats collection
FrameworkStatsLog.write(FrameworkStatsLog.USB_DEVICE_ATTACHED,
device.getVendorId(), device.getProductId(), parser.hasAudioInterface(),
parser.hasHIDInterface(), parser.hasStorageInterface(),
FrameworkStatsLog.USB_DEVICE_ATTACHED__STATE__STATE_DISCONNECTED,
System.currentTimeMillis() - current.mTimestamp);
}
} else {
Slog.d(TAG, "Removed device at " + deviceAddress + " was already gone");
}
}
}
权限申请
参考UsbManager的使用部分,我们知道 权限申请的方式是直接调用 UsbManager.requestPermission,然后传递对应的device及permissionPendingIntent。
https://shimo.im/docs/cXjRDCCTrc9xYCwC#anchor-8M36
UsbManager#requestPermission
我们看下实现代码:
// android.hardware.usb.UsbManager#requestPermission(android.hardware.usb.UsbDevice, android.app.PendingIntent)
public void requestPermission(UsbDevice device, PendingIntent pi) {
try {
mService.requestDevicePermission(device, mContext.getPackageName(), pi);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
UsbService#requestDevicePermission
实际上最终也是调用 UsbService 的 对应方法 - requestDevicePermission
// com.android.server.usb.UsbService#requestDevicePermission
@Override
public void requestDevicePermission(UsbDevice device, String packageName, PendingIntent pi) {
final int uid = Binder.getCallingUid();
final int pid = Binder.getCallingPid();
final int userId = UserHandle.getUserId(uid);
final long token = Binder.clearCallingIdentity();
try {
getPermissionsForUser(userId).requestPermission(device, packageName, pi, pid, uid);
} finally {
Binder.restoreCallingIdentity(token);
}
}
UsbUserPermissionManager
这边通过Binder获取到用户的Uid,Pid等信息,然后交给 UsbPermissionManager 处理:
- 如果检测已经有权限,则直接启动pendingIntent 指向的intent
- 如果没有权限,则启动 权限申请的 Dialog (实际上是个位于System UI中Dialog风格的 Activity )
// frameworks/base/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
// com.android.server.usb.UsbUserPermissionManager#requestPermission(android.hardware.usb.UsbDevice, java.lang.String, android.app.PendingIntent, int, int)
public void requestPermission(UsbDevice device, String packageName, PendingIntent pi, int pid,
int uid) {
Intent intent = new Intent();
// respond immediately if permission has already been granted
if (hasPermission(device, packageName, pid, 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(TAG, "requestPermission PendingIntent was cancelled");
}
return;
}
if (isCameraDevicePresent(device)) {
if (!isCameraPermissionGranted(packageName, pid, 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(TAG, "requestPermission PendingIntent was cancelled");
}
return;
}
}
requestPermissionDialog(device, null,
mUsbUserSettingsManager.canBeDefault(device, packageName), packageName, pi, uid);
}
// com.android.server.usb.UsbUserPermissionManager#requestPermissionDialog(android.hardware.usb.UsbDevice, android.hardware.usb.UsbAccessory, boolean, java.lang.String, int, android.content.Context, android.app.PendingIntent)
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.setComponent(ComponentName.unflattenFromString(userContext.getResources().getString(
com.android.internal.R.string.config_usbPermissionActivity)));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
userContext.startActivityAsUser(intent, mUser);
} catch (ActivityNotFoundException e) {
Slog.e(TAG, "unable to start UsbPermissionActivity");
} finally {
Binder.restoreCallingIdentity(identity);
}
}
SystemUI#UsbPermissionActivity
定义声明
前面会启动com.android.internal.R.string.config_usbPermissionActivity 定义的 Activity中,此字符串的定义位于 (./frameworks/base/core/res/res/values/config.xml)
<string name="config_usbPermissionActivity" translatable="false">com.android.systemui/com.android.systemui.usb.UsbPermissionActivity</string>
对应的Activity在 ./frameworks/base/packages/SystemUI/AndroidManifest.xml
中声明,其主题为一个Dialog
<!-- started from UsbDeviceSettingsManager -->
<activity android:name=".usb.UsbPermissionActivity"
android:exported="true"
android:permission="android.permission.MANAGE_USB"
android:theme="@style/Theme.SystemUI.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true">
响应
- 点击按钮后,会记录是否赋予了权限;
- 在销毁时,会设置对应的权限到UsbService,然后启动对应的PendingIntent;
// frameworks/base/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
public void onClick(DialogInterface dialog, int which) {
if (which == AlertDialog.BUTTON_POSITIVE) {
mPermissionGranted = true;
}
finish();
}
// com.android.systemui.usb.UsbPermissionActivity#onDestroy
@Override
public void onDestroy() {
IBinder b = ServiceManager.getService(USB_SERVICE);
IUsbManager service = IUsbManager.Stub.asInterface(b);
// send response via pending intent
Intent intent = new Intent();
try {
if (mDevice != null) {
intent.putExtra(UsbManager.EXTRA_DEVICE, mDevice);
if (mPermissionGranted) {
service.grantDevicePermission(mDevice, mUid);
if (mAlwaysUse != null && mAlwaysUse.isChecked()) {
final int userId = UserHandle.getUserId(mUid);
service.setDevicePackage(mDevice, mPackageName, userId);
}
}
}
if (mAccessory != null) {
intent.putExtra(UsbManager.EXTRA_ACCESSORY, mAccessory);
if (mPermissionGranted) {
service.grantAccessoryPermission(mAccessory, mUid);
if (mAlwaysUse != null && mAlwaysUse.isChecked()) {
final int userId = UserHandle.getUserId(mUid);
service.setAccessoryPackage(mAccessory, mPackageName, userId);
}
}
}
intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, mPermissionGranted);
mPendingIntent.send(this, 0, intent);
} catch (PendingIntent.CanceledException e) {
Log.w(TAG, "PendingIntent was cancelled");
} catch (RemoteException e) {
Log.e(TAG, "IUsbService connection failed", e);
}
if (mDisconnectedReceiver != null) {
unregisterReceiver(mDisconnectedReceiver);
}
super.onDestroy();
}