USB模块分析(四)- 设备列表权限申请
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
// 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 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">
响应
- 点击按钮后,会记录是否赋予了权限;
- 在销毁时,会设置对应的权限到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模块分析(四)- 设备列表权限申请相关推荐
- 安卓USB模块分析(二)- API使用
Android USB 支持两种模式:1. 主机模式:2. 配件模式:这里我们主要梳理HOST模式的使用: USB 模块的使用可参考官方文档: USB 主机和配件概览 | Android 开发者 ...
- Qt编写安防视频监控系统57-子模块1设备列表
一.前言 近期在经历过这次UI大重构以后,很多拆分的功能都以单独的模块的形式出现,以悬停窗体的形式嵌入或者悬浮在主窗体中,这种方式极大的增强了系统的拓展性,客户想要什么模块就开启什么模块,放置到合适的 ...
- Android GNSS 模块分析(四)HAL 层
紧接着上一篇(Android GNSS 模块分析(三)JNI 层),继续来分析下 Android GNSS HAL 层的功能,本篇准备先介绍下 HIDL 层的封装.至于后面的 HAL 层的功能,由于使 ...
- android 申请usb权限,USB 权限申请流程
USB android授权方式 权限的控制分三块: 1:USB host端有个线程循环检测系统是否USB设备插拔,如果有就找到申请权限的APP并调用起来 2:APP运行后主动申请权限,也就是reque ...
- android 申请拍照权限,React Native模块之Permissions权限申请的实例相机
React Native模块之Permissions权限申请的实例相机 发布时间:2020-09-03 23:49:26 来源:脚本之家 阅读:280 作者:lqh React Native模块之Pe ...
- 纳税服务系统四(角色模块)【角色与权限、角色与用户】
需求分析 我们直接来看看原型图,看看需求是怎么样的: 这里写图片描述 这里写图片描述 我们看到上图,就会发现角色模块主要还是CRUD,唯一不同的就是它不再是单独的实体关系.角色与权限是存在关系的. 之 ...
- BetaFlight模块设计之三十四:OSD模块分析
BetaFlight模块设计之三十四:OSD模块分析 1. OSD模块 1.1 osd状态机子模块 1.2 osd_warnings检查子模块 1.3 osd_elements子模块 2. OSD设备 ...
- android挂载usb设备,android usb挂载分析---MountService启动
在android usb挂载分析----vold启动,我们的vold模块已经启动了,通信的机制也已经建立起来了,接下来我们分析一下MountService的启动,也就是我们FrameWork层的启动, ...
- Linux 命令之 lsusb -- 显示本机的USB设备列表信息
文章目录 命令介绍 常用选项 命令示例 (一)显示 USB 设备详细信息 命令介绍 lsusb命令用于显示本机的USB设备列表,以及USB设备的详细信息. lsusb命令显示的USB设备信息来自&qu ...
最新文章
- Eclipse改字体字号
- Python基础知识-优雅的with as语句
- Mysql semi-sync VS group replication, 谁快?
- 使用现代化 C# 语法简化代码
- nuxt.js 配置后端的请求地址
- 从远程(包括ftp,http等协议)地址获取文件流信息
- 字符串string 、byte[]、MemoryStream、Base64String的相互转换
- Photopile JS – 帮助你实现精致的照片堆叠效果
- 南加大计算机硕士学制,2020年南加州大学硕士读几年
- Pod 的生命周期及探针
- php牛牛发牌算法,分享一个牛牛算法
- 前端工程师的前途与价值体现
- 超大图片(4000×3000像素)的畸变矫正,python+OpenCV实现
- 恭主驾到:最新的汽车年审新规,都了解了吗?
- 服务器报错 http error 503.the service is unavailable怎么解决
- 重测序群体遗传进化分析之进化树构建
- 零基础学Java,现已转行一年
- 2022.10.14每日刷题打卡
- Qt串口通信实时曲线上位机源代码
- uci拒绝认证_关于车架上UCI认证贴纸的10个常见问题