RK-USB白名单功能实现

发布于:2025-06-27 ⋅ 阅读:(13) ⋅ 点赞:(0)

实现USB白名单功能


需求

定制客户有相关USB 白名单需求,

具备USB白名单功能,只有指定VID和PID的USB设备才可接入。其他USB设备禁止接入(出厂默认允许所有USB设备),大体界面参考WIFI白名单界面
在这里插入图片描述


一、参考资料

RKAndroid11-WIFI白名单功能实现 之前写过WIFI 白名单功能,思路、业务其实一样的。 维护一份白名单集合,过滤;业务上实现具体的需求即可。

USBHostManager.java 在线源码

USBService.java 在线源码

UVC for USBCamera in Android 之前的笔记,可参考部分UVC相关基础知识

其它知识储备:

  • 基本的USB相关知识,USB摄像机 vid/pid 概念
  • USB HOST/Device 模式 区别
  • USB 外设相关基本知识储备

二、修改的文件

\frameworks\base\core\java\android\hardware\usb\IUsbManager.aidl
\frameworks\base\services\usb\java\com\android\server\usb\UsbService.java
\frameworks\base\services\usb\java\com\android\server\usb\UsbHostManager.java

三、架构分析-IUsbManager-UsbService-UsbHostManager

在整个Android Framework层的子系统实现中,他们关系及架构实现基本差不多,这里就USB 涉及到知识点,分析整理下。

类功能说明

IUsbManager.aidl

这是一个AIDL (Android Interface Definition Language)文件

  • 定义了系统USB服务的跨进程通信接口

  • 包含了客户端可以调用的方法(如设置默认USB功能、授予设备权限等)

  • 作为Binder接口,允许其他进程(如SystemUI、Settings等)与USB服务交互

UsbService.java

系统服务实现类,继承自SystemService

实现了IUsbManager.Stub(即IUsbManager.aidl生成的接口)

作为USB子系统的核心服务,运行在system_server进程中

主要职责:

  • 管理USB主机和设备模式

  • 处理USB相关的权限控制

  • 广播USB相关事件

  • 协调UsbHostManager和UsbDeviceManager的工作

UsbHostManager.java

负责USB主机模式的具体实现

由UsbService创建和管理

主要职责:

  • 监控USB主机端口状态变化

  • 枚举连接的USB设备

  • 处理USB设备权限

  • 与内核通过usbd守护进程交互

三者协作关系

架构层次

[Client Apps][IUsbManager.aidl接口][UsbService.java][UsbHostManager.java]

调用流程示例

当Settings应用需要获取USB设备列表时:

  • 通过IUsbManager接口调用getDeviceList()

  • UsbService接收到调用

  • UsbService委托UsbHostManager实际执行设备枚举

  • 结果通过Binder返回给客户端

职责划分

  • IUsbManager.aidl:定义通信契约

  • UsbService.java:系统服务框架和权限控制

  • UsbHostManager.java:USB主机模式的具体实现

这种设计遵循了Android系统服务的典型模式:AIDL接口定义、SystemService实现、具体功能委托给专门的Manager类处理。

四、实现方案

  • 在三中其实对之前framework 部分架构中的一次回顾和总结,很多子模块实现方案就是如三中,这就是解决需求、方案提供的基本思路。具体实现方案修改如下:

接口扩展 IUsbManager.aidl


/** @hide */
interface IUsbManager
{
。。。。。。。。。。。
  void setUsbWhiteList(in List<String> whiteList);
	
   List<String> getUsbWhiteList();

}

接口实现-UsbService.java



/**
 * UsbService manages all USB related state, including both host and device support.
 * Host related events and calls are delegated to UsbHostManager, and device related
 * support is delegated to UsbDeviceManager.
 */
public class UsbService extends IUsbManager.Stub {

 ................

	    @Override
        public void setUsbWhiteList(List<String> whiteList){
          Slog.v(TAG," setUsbWhiteList whiteList:"+whiteList);
          mHostManager.setUsbWhiteList(whiteList);   
        };
		
		
        @Override
        public List<String> getUsbWhiteList(){
			Slog.v(TAG," getUsbWhiteList ");
            return mHostManager.getUsbWhiteList();        
        };

...............

}

源码里面的注释相当精辟:

  • 管理USB所有的状态,包括host 和 device模式
  • Host 关联的事件都是委托给UsbManager 处理的, device 也是委托给 UsbManager 处理的。

主机模式-拓展方法实现-UsbHostManager

之前我们也讲了,核心的思路就是维护一个白名单列表,这里我们还是以一个List 集合来实现,列表里面管理vid_pid 的字符串,然后过滤 匹配即可。

白名单集合定义

    private List<String> vidpid_whiteList=new ArrayList<>();
	   
       
       public void setUsbWhiteList(List<String> vidpid_whiteList){
               this.vidpid_whiteList=vidpid_whiteList;
               
       }
	   
        
       public List<String> getUsbWhiteList(){
               return this.vidpid_whiteList;
               
       }

usbDeviceAdded-过滤实现usb 白名单功能

如果白名单为空则允许所有USB添加进来,可以正常使用;如果USB白名单有数据,只允许vid/pid 在白名单内才能正常使用;否则都不可使用

 /* Called from JNI in monitorUsbHostBus() to report new USB devices
       Returns true if successful, i.e. the USB Audio device descriptors are
       correctly parsed and the unique device is added to the audio device list.
     */
    @SuppressWarnings("unused")
    private boolean usbDeviceAdded(String deviceAddress, int deviceClass, int deviceSubclass,
            byte[] descriptors) {
 

 ...................

   	   
// modify start  	   
    
	     if(this.vidpid_whiteList!=null && this.vidpid_whiteList.size()!=0){
          int vid = 0;
          int pid = 0;
           String product = "<unknown>";
          String version = "<unknown>";
          String serial = "<unknown>";
			UsbDeviceDescriptor deviceDescriptor = parser.getDeviceDescriptor();
            if (deviceDescriptor != null) {
				Slog.d(TAG,"usbDeviceAdded huoqu dangqian usb device vid  pid xinxi=====");
            vid = deviceDescriptor.getVendorID();
            pid = deviceDescriptor.getProductID();
             product = deviceDescriptor.getProductString(parser);
            version = deviceDescriptor.getDeviceReleaseString();
            serial = deviceDescriptor.getSerialString(parser);
              Slog.d(TAG," usbDeviceAdded:vid:"+vid+"   pid:"+pid);
			  if(this.vidpid_whiteList.contains(Integer.toString(vid))
				  &&this.vidpid_whiteList.contains(Integer.toString(pid))){
             
			       Slog.d(TAG," is white List  can use vidpid_whiteList:"+vidpid_whiteList);
 
                   // return true;
               }else{
				   Slog.d(TAG," buzai baimingdan cant not use ");
				   return false;
			   } 
			}        
          }   
	   
// modify end 	   
	   
	   
。。。。。
    }

五、应用端功能实现

假使4中 在 framework层功能已经实现,对外提供接口,现在就需要实际应用端验证功能。

基础-如何获取摄像头的vid-pid

在实现过程中,framework层的vid-id白名单就是把vid/pid 组成字符串,放在集合里面。 那么如何知道一款摄像头vid-pid 值? 大家可以自行网络中搜索相关基本知识,这里给出参考如下:
在这里插入图片描述
在这里插入图片描述

验证framework层-api对外接口

在 上面四中已经给出了framework 层接口,应用端直接对接就行了。 对外开放的其实是USBService,如何调用 USBService 里面提供的 白名单方法。 这里有两个思路可以参考:

获取USBService 方法

通过反射调用隐藏API(需要系统权限)
try {
    // 获取ServiceManager
    Class<?> serviceManager = Class.forName("android.os.ServiceManager");
    
    // 获取getService方法
    Method getService = serviceManager.getMethod("getService", String.class);
    
    // 获取UsbService的IBinder
    IBinder binder = (IBinder) getService.invoke(null, "usb");
    
    // 获取IUsbManager.Stub类
    Class<?> stub = Class.forName("android.hardware.usb.IUsbManager$Stub");
    
    // 获取asInterface方法
    Method asInterface = stub.getMethod("asInterface", IBinder.class);
    
    // 获取IUsbManager实例
    Object usbManagerService = asInterface.invoke(null, binder);
    

    // 调用特定方法(示例)
    Method grantDevicePermission = usbManagerService.getClass()
            .getMethod("grantDevicePermission", UsbDevice.class, int.class);
    grantDevicePermission.invoke(usbManagerService, usbDevice, uid);
    
} catch (Exception e) {
    e.printStackTrace();
}

这里反射得到USBService ->反射得到UsbService的IBinder->反射得到IUsbManager.Stub类->反射得到IUsbManager 实例,然后反射调用方法。

看似麻烦,其实都是反射相关知识。

通过AIDL接口(需要系统签名)

如果设备已root或你的应用有系统签名:

  • 找到framework中的IUsbManager.aidl文件

  • 复制到你的项目中src/main/aidl/android/hardware/usb/目录

  • 然后可以这样使用:

IUsbManager usbService = IUsbManager.Stub.asInterface(
    ServiceManager.getService(Context.USB_SERVICE));

// 调用方法
usbService.grantDevicePermission(device, uid);

具体实现

在获取USBService 方法上面,我更倾向于反射、反射、再反射来实现自己的需求,接下来我也有反射的方式进行获取和设置USB白名单的功能。

有人问,为什么不用获取系统USBService 方法来实现和调用内部方法呢? 比如如下:

UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);

// 调用公开方法
HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
if (!deviceList.isEmpty()) {
    for (UsbDevice device : deviceList.values()) {
        // 处理USB设备
    }
}

这里我都懒得解释了,自行观察和分析下吧。

设置白名单方法
viewBinding.getUsbwhitelist.setOnClickListener {
            Log.d(TAG, "getUsbwhitelist   ")

           // val usbManager = getSystemService(USB_SERVICE) as UsbManager


            // 获取ServiceManager
            val serviceManager = Class.forName("android.os.ServiceManager")
            // 获取getService方法
            val getService = serviceManager.getMethod("getService", String::class.java)
            // 获取UsbService的IBinder
            val binder = getService.invoke(null, "usb") as IBinder
            // 获取IUsbManager.Stub类
            val stub = Class.forName("android.hardware.usb.IUsbManager\$Stub")
            // 获取asInterface方法
            val asInterface = stub.getMethod("asInterface", IBinder::class.java)
            // 获取IUsbManager实例
            val usbManagerService = asInterface.invoke(null, binder)
            // 通过反射获取 getWiFiWhiteList 方法
            val method: Method = usbManagerService.javaClass.getMethod("getUsbWhiteList")
            // 调用方法并获取结果
            val result = method.invoke(usbManagerService)
            // 转换为 List<String>
            val resultData = result as? List<String>
            Log.d(TAG, " result:${resultData}")

        }
获取白名单方法
 viewBinding.setUsbwhitelist.setOnClickListener {
            Log.d(TAG, "setUsbWhiteList   ")

            // 获取ServiceManager
            val serviceManager = Class.forName("android.os.ServiceManager")
            // 获取getService方法
            val getService = serviceManager.getMethod("getService", String::class.java)
            // 获取UsbService的IBinder
            val binder = getService.invoke(null, "usb") as IBinder
            // 获取IUsbManager.Stub类
            val stub = Class.forName("android.hardware.usb.IUsbManager\$Stub")
            // 获取asInterface方法
            val asInterface = stub.getMethod("asInterface", IBinder::class.java)
            // 获取IUsbManager实例
            val usbManagerService = asInterface.invoke(null, binder)
            val whiteList: List<String> = listOf(
                "testvid_testpid","1022_1f3b"
            )
            // 通过反射获取 setUsbWhiteList 方法
            val method: Method = usbManagerService.javaClass.getMethod(
                "setUsbWhiteList",
                List::class.java
            )
            // 调用方法设置白名单
            method.invoke(usbManagerService, whiteList)


        }

实际的调试和一些日志界面如下
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实际验证功能OK的,日志也能说明问题的。

六、总结

针对这个USB白名单需求,其实就是一个基础的在framework层 新增一个USB相关的接口,对外释放,扩充功能罢了。很多子模块架构思想一致,直接新增接口、实现接口功能、对外提供方法、对framework实现业务逻辑罢了。

  • 梳理USB Host模式下,usb 摄像头白名单功能。其中UsbHostManager 源码代码量也不大,如果稍微懂一些UVC相关知识,里面很多代码和流程都是比较熟悉的面孔了。
  • 当前实验验证了白名单功能,具体来实现业务,维护的也是内部的白名单集合,存储到本地就可以了。
  • 如果UVC、USB 相关模块、源码 接触过,对于这里设计到的UsbService 、UsbHostManager 相关源码和流程 肯定比较熟悉,实现具体需求水到渠成罢了

网站公告

今日签到

点亮在社区的每一天
去签到