getDeviceList

其调用入口位于 UsbManager中:

// frameworks/base/core/java/android/hardware/usb/UsbManager.javaprivate 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#usbDeviceAddedprivate 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.");// TrackingaddConnectionRecord(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);// TrackingaddConnectionRecord(deviceAddress, ConnectionRecord.CONNECT,parser.getRawDescriptors());// Stats collectionFrameworkStatsLog.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);// TrackingaddConnectionRecord(deviceAddress, ConnectionRecord.DISCONNECT, null);if (current != null) {UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress,current.mDescriptors);// Stats collectionFrameworkStatsLog.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 处理:

  1. 如果检测已经有权限,则直接启动pendingIntent 指向的intent
  2. 如果没有权限,则启动 权限申请的 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 grantedif (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">

响应

  1. 点击按钮后,会记录是否赋予了权限;
  2. 在销毁时,会设置对应的权限到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 intentIntent 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();
}

USB模块分析(四)- 设备列表权限申请相关推荐

  1. 安卓USB模块分析(二)- API使用

    Android USB 支持两种模式:1. 主机模式:2. 配件模式:这里我们主要梳理HOST模式的使用: USB 模块的使用可参考官方文档: USB 主机和配件概览  |  Android 开发者 ...

  2. Qt编写安防视频监控系统57-子模块1设备列表

    一.前言 近期在经历过这次UI大重构以后,很多拆分的功能都以单独的模块的形式出现,以悬停窗体的形式嵌入或者悬浮在主窗体中,这种方式极大的增强了系统的拓展性,客户想要什么模块就开启什么模块,放置到合适的 ...

  3. Android GNSS 模块分析(四)HAL 层

    紧接着上一篇(Android GNSS 模块分析(三)JNI 层),继续来分析下 Android GNSS HAL 层的功能,本篇准备先介绍下 HIDL 层的封装.至于后面的 HAL 层的功能,由于使 ...

  4. android 申请usb权限,USB 权限申请流程

    USB android授权方式 权限的控制分三块: 1:USB host端有个线程循环检测系统是否USB设备插拔,如果有就找到申请权限的APP并调用起来 2:APP运行后主动申请权限,也就是reque ...

  5. android 申请拍照权限,React Native模块之Permissions权限申请的实例相机

    React Native模块之Permissions权限申请的实例相机 发布时间:2020-09-03 23:49:26 来源:脚本之家 阅读:280 作者:lqh React Native模块之Pe ...

  6. 纳税服务系统四(角色模块)【角色与权限、角色与用户】

    需求分析 我们直接来看看原型图,看看需求是怎么样的: 这里写图片描述 这里写图片描述 我们看到上图,就会发现角色模块主要还是CRUD,唯一不同的就是它不再是单独的实体关系.角色与权限是存在关系的. 之 ...

  7. BetaFlight模块设计之三十四:OSD模块分析

    BetaFlight模块设计之三十四:OSD模块分析 1. OSD模块 1.1 osd状态机子模块 1.2 osd_warnings检查子模块 1.3 osd_elements子模块 2. OSD设备 ...

  8. android挂载usb设备,android usb挂载分析---MountService启动

    在android usb挂载分析----vold启动,我们的vold模块已经启动了,通信的机制也已经建立起来了,接下来我们分析一下MountService的启动,也就是我们FrameWork层的启动, ...

  9. Linux 命令之 lsusb -- 显示本机的USB设备列表信息

    文章目录 命令介绍 常用选项 命令示例 (一)显示 USB 设备详细信息 命令介绍 lsusb命令用于显示本机的USB设备列表,以及USB设备的详细信息. lsusb命令显示的USB设备信息来自&qu ...

最新文章

  1. Eclipse改字体字号
  2. Python基础知识-优雅的with as语句
  3. Mysql semi-sync VS group replication, 谁快?
  4. 使用现代化 C# 语法简化代码
  5. nuxt.js 配置后端的请求地址
  6. 从远程(包括ftp,http等协议)地址获取文件流信息
  7. 字符串string 、byte[]、MemoryStream、Base64String的相互转换
  8. Photopile JS – 帮助你实现精致的照片堆叠效果
  9. 南加大计算机硕士学制,2020年南加州大学硕士读几年
  10. Pod 的生命周期及探针
  11. php牛牛发牌算法,分享一个牛牛算法
  12. 前端工程师的前途与价值体现
  13. 超大图片(4000×3000像素)的畸变矫正,python+OpenCV实现
  14. 恭主驾到:最新的汽车年审新规,都了解了吗?
  15. 服务器报错 http error 503.the service is unavailable怎么解决
  16. 重测序群体遗传进化分析之进化树构建
  17. 零基础学Java,现已转行一年
  18. 2022.10.14每日刷题打卡
  19. Qt串口通信实时曲线上位机源代码
  20. uci拒绝认证_关于车架上UCI认证贴纸的10个常见问题

热门文章

  1. 乐见Safengine licensor终于有了脱壳脚本
  2. 清华大学镜像及其他镜像
  3. Slidetoshutdown滑动关机命令
  4. 源码分析如何注解使用AOP
  5. vue-quill-editor设置字体大小并上传图片
  6. 【雷达成像】合成孔径雷达RD成像算法matlab仿真
  7. 火炬电阻_火炬神经网络的对抗性攻击和防御
  8. Keras : 对比CCN和RNN在影戏评论IMDB数据集上的表现
  9. js 万年历农历转阳历 方法_利用JS制作万年历的方法
  10. 测试绝地求生显卡使用率软件,多分辨率《绝地求生:大逃杀》显卡性能测试!...