2. Android USB架构概览

说实话,Android的USB子系统,我第一次接触时也觉得挺复杂的。它不像Linux桌面那样简单——插个设备,驱动一挂就完事。Android的USB,既要当主机(Host),又要当设备(Device),还得考虑充电、OTG、配件通信……嗯,今天我们就把它一层层剥开看看。

2.1 Android USB协议栈分层

我个人习惯把Android USB协议栈分成四层来看。从顶到底分别是:应用层、框架层、HAL层、内核层。每一层各司其职,又互相配合。

核心要点:Android USB协议栈是典型的“分层解耦”设计。上层不关心底层怎么收发数据,底层也不关心上层在做什么业务。

应用层 (Application Layer) USB Manager API / USB Host API / Accessory API 框架层 (Framework Layer) UsbService / UsbDeviceManager / UsbHostManager HAL层 (Hardware Abstraction Layer) usb@1.0-service / usb@1.3-service / Gadget HAL 内核层 (Kernel Layer) USB Core / Gadget Framework / DWC3 / EHCI / xHCI

2.2 各层职责详解

2.2.1 应用层

这一层是开发者最常接触的。说白了,就是你在写App时调用的那些API。比如你想枚举USB设备、打开通信端点、收发数据,都是通过android.hardware.usb包下的类完成的。

  • UsbManager:获取设备列表、请求权限、管理连接
  • UsbDevice:描述一个USB设备的接口、端点信息
  • UsbDeviceConnection:真正的数据传输通道
  • UsbAccessory:AOA模式下的配件通信接口

我的经验:很多新手在应用层直接做同步I/O,结果UI线程卡死。记住,USB的bulk传输一定要放到子线程里跑。我曾经有个项目,就是因为没注意这个,导致扫码枪数据一多就ANR。

2.2.2 框架层

框架层在SystemServer进程里运行。它负责管理USB设备的插拔事件、权限仲裁、角色切换(Host/Device)。你想想看,当用户插一个U盘时,是谁弹出通知问你要不要打开?就是这一层干的。

核心组件包括:

  • UsbDeviceManager:处理USB状态机,比如从Host切到Device
  • UsbHostManager:枚举USB设备、绑定驱动
  • UsbService:对外提供Binder接口,供应用层调用

2.2.3 HAL层

HAL层是Google为了屏蔽厂商差异搞出来的。不同芯片厂(高通、MTK、展锐)的USB控制器实现不一样,但HAL接口是统一的。Android 8.0之后,HAL用Treble架构重写了,变成了hidl服务。

// USB HAL接口示例 (Android 10+)
// hardware/interfaces/usb/1.3/IUsb.hal
interface IUsb {
    // 切换USB角色
    switchRole(string role) generates (Status status);
    // 获取当前角色
    getRole() generates (string role);
    // 控制Gadget
    enableGadget() generates (Status status);
};

注意:HAL层的实现是厂商私有的。你拿一台小米手机和一台三星手机,底层的USB HAL代码完全不同。但上层框架看到的接口是一样的——这就是HAL存在的意义。

2.2.4 内核层

内核层是真正跟硬件打交道的地方。Android内核基于Linux,USB子系统自然也继承自Linux内核。但Android加了一些自己的东西,比如Gadget框架的定制。

内核层主要包含:

  • USB Core:USB协议栈的核心,处理枚举、配置、传输
  • HCD (Host Controller Driver):DWC3、EHCI、xHCI等控制器驱动
  • Gadget Framework:让Android设备模拟成其他USB设备
  • Class Driver:比如usb-storage、usbhid、cdc_acm等

2.3 USB Gadget框架

Gadget框架是Android USB开发中最有意思的部分。它让手机不再只是“主机”,还能扮演“设备”的角色。说白了,就是让你的手机插到电脑上时,电脑以为它是个U盘、是个网卡、是个串口……

Gadget框架的核心是ConfigFSFunctionFS。在Android中,我们通过/config/usb_gadget/这个虚拟文件系统来配置Gadget。

# 配置一个MSC(大容量存储)Gadget的典型流程
# 需要root权限
echo "0x18d1" > /config/usb_gadget/g1/idVendor
echo "0x4e26" > /config/usb_gadget/g1/idProduct
mkdir /config/usb_gadget/g1/strings/0x409
echo "Google" > /config/usb_gadget/g1/strings/0x409/manufacturer
echo "MyPhone" > /config/usb_gadget/g1/strings/0x409/product
mkdir /config/usb_gadget/g1/functions/mass_storage.usb0
echo /dev/block/mmcblk0p1 > /config/usb_gadget/g1/functions/mass_storage.usb0/lun.0/file
mkdir /config/usb_gadget/g1/configs/c.1
ln -s /config/usb_gadget/g1/functions/mass_storage.usb0 /config/usb_gadget/g1/configs/c.1/
echo "ci_hdrc.0" > /config/usb_gadget/g1/UDC

关键理解:Gadget框架的本质是“角色反转”。手机作为Device时,它通过Gadget驱动模拟出各种USB设备类,让Host端(电脑)识别并加载对应的驱动。

2.4 USB设备类

不同的USB设备类,对应不同的应用场景。我挑几个Android开发中最常用的来讲。

设备类 Class Code 典型用途 Android支持情况
HID 0x03 键盘、鼠标、游戏手柄 Host模式原生支持,Device模式需Gadget
MSC 0x08 U盘、移动硬盘 Host/Device均支持,最成熟
CDC 0x02 串口、以太网、Modem CDC ACM(串口)支持较好
AOA 自定义 Android配件通信(Arduino等) Android专属协议,需配件侧支持
Audio 0x01 USB耳机、声卡 Android 10+ 原生支持UAC

2.4.1 HID(人机交互设备)

HID设备的特点是延迟低、无需额外驱动。Android作为Host时,可以识别USB键盘鼠标。但如果你想用手机模拟成键盘(比如做自动化输入工具),那就得用Gadget的HID功能。

避坑指南:我曾经做一个POS机项目,需要用手机模拟键盘向电脑输入金额。HID Gadget的report descriptor一定要写对。少一个字节,电脑就不认。建议直接用Linux内核自带的hid_gadget_test工具先验证。

2.4.2 MSC(大容量存储)

这个最简单。手机插电脑上,选择“传输文件”,其实就是MSC Gadget在工作。它把手机的一个分区(或镜像文件)暴露给电脑,电脑把它当成普通U盘。

但要注意,MSC模式下,手机和电脑不能同时访问存储。所以现在Android默认用MTP而不是MSC——MTP允许双方同时访问。

2.4.3 CDC(通信设备类)

CDC下面有好几个子类。最常用的是CDC ACM,也就是虚拟串口。很多嵌入式开发板、4G模块、GPS模块都用它。Android通过/dev/ttyACM*来访问。

// 在Android App中打开USB串口
UsbDeviceConnection connection = usbManager.openDevice(device);
UsbInterface intf = device.getInterface(0);
connection.claimInterface(intf, true);
// CDC ACM的端点通常是:
// 端点0:控制(用于设置波特率等)
// 端点IN:读取数据
// 端点OUT:发送数据
UsbEndpoint inEp = intf.getEndpoint(0);  // 注意实际索引需根据描述符
UsbEndpoint outEp = intf.getEndpoint(1);

2.4.4 AOA(Android Open Accessory)

AOA是Google搞的专属协议。它让Android设备作为Device,但配件(比如Arduino板)作为Host。配件通过AOA协议与手机通信,不需要手机有Host能力。

AOA 2.0之后还支持音频和HID回传,挺强大的。不过说实话,AOA在实际产品中用得不多,主要是开发板和DIY项目在用。

2.5 小结

Android USB架构,说白了就是四层结构:应用层调API,框架层管状态,HAL层做适配,内核层干苦力。Gadget框架让手机能“变身”成各种USB设备。不同的设备类(HID、MSC、CDC、AOA)对应不同的应用场景。

嗯,这一章的内容就到这里。下一章我们会深入USB枚举过程,看看设备插上去之后,系统里到底发生了什么。

公众号:蓝海资料掘金营,微信deep3321