Android 车载 USB 开发笔记:USB Host、USB 串口、USB-CAN、HID 与系统 API
Android 车机、工控屏、T-Box 和工程机械终端中,USB 常用于连接 USB 转串口 + USB-RS232/RS485 + USB-CAN + 扫码枪/HID + USB 摄像头 + USB 网卡 + U 盘 等外设。车载 Android 中最常见的是 Android 作为 USB Host,由系统完成设备枚举,再根据 USB Device Class 或厂商协议处理数据。
典型链路:Android 应用 → Android USB API / 系统驱动 → USB Host Controller → USB Device → UART/CAN/HID/Camera/Ethernet 等外设。
USB Host
车载 Android 大多数外设场景中,Android 设备作为 USB Host,负责给外设供电、枚举设备、读取 Descriptor、选择 Interface 和 Endpoint,并主动发起数据传输。
Android USB Host 主要 API:UsbManager + UsbDevice + UsbInterface + UsbEndpoint + UsbDeviceConnection。
对应关系:UsbManager:管理 USB 设备,UsbDevice:一个物理 USB 设备,UsbInterface:设备中的一个功能接口,UsbEndpoint:实际数据通道,UsbDeviceConnection:当前 USB 连接。
常见流程:UsbManager → UsbDevice → Permission → openDevice → UsbInterface → claimInterface → UsbEndpoint → 数据收发 → releaseInterface → close。
UsbManager
UsbManager 是 Android USB Host 的主要入口,可以获取当前已经枚举的 USB Device、请求设备访问权限、打开设备连接。
获取:
ini
UsbManager usbManager =
(UsbManager) getSystemService(Context.USB_SERVICE);
常用 API:
scss
getDeviceList():获取当前 USB Device
hasPermission():检查设备访问权限
requestPermission():请求当前设备权限
openDevice():打开 UsbDevice
车载设备如果固定连接某个 USB-CAN、USB-RS485 或扫码枪,通常先通过 getDeviceList() 根据 VID/PID 或 Interface 信息找到目标设备。
UsbDevice
UsbDevice 表示一个已经被 Android USB Host 枚举出来的物理设备。
常用信息:
scss
getVendorId():VID
getProductId():PID
getDeviceClass():Device Class
getDeviceSubclass():Device Subclass
getDeviceProtocol():Device Protocol
getInterfaceCount():Interface 数量
getInterface():获取指定 Interface
getManufacturerName():厂商名称
getProductName():产品名称
getSerialNumber():设备序列号
车载项目中常通过:VID + PID + Interface Class + Serial Number 区分 USB 外设。
不能只依赖设备名称,因为多个同型号设备可能返回相同 Product Name。
VID 与 PID
USB Device Descriptor 中包含:VID(Vendor ID) + PID(Product ID)。
VID 表示厂商,PID 表示该厂商定义的产品类型。
例如车机同时连接:USB-CAN + USB-RS485 + USB 扫码枪,可以通过 VID/PID 快速区分不同设备。
但 VID/PID ≠ 唯一设备 ID。多台同型号设备通常拥有相同 VID/PID,如果需要区分具体设备,还要结合 Serial Number + USB Port + 设备自身 ID。
UsbInterface
一个 USB Device 可以包含多个 Interface。
例如 USB 转串口设备可能包含:Control Interface + Data Interface。
复合设备也可能同时包含:HID + CDC + Vendor Interface。
常用 API:
scss
getInterfaceClass()
getInterfaceSubclass()
getInterfaceProtocol()
getEndpointCount()
getEndpoint()
车载项目中不要默认 getInterface(0) 就是业务接口,应根据 Class + Subclass + Protocol + Endpoint 找到真正的数据 Interface。
UsbEndpoint
UsbEndpoint 表示 USB 数据通道。
主要关注:
scss
getDirection():IN / OUT
getType():Control / Bulk / Interrupt / Isochronous
getMaxPacketSize():Endpoint Max Packet Size
getEndpointNumber():Endpoint Number
getInterval():轮询间隔
方向始终站在 Host 角度:
USB_DIR_IN:Device → Android
USB_DIR_OUT:Android → Device
车载自定义设备、USB 串口、USB-CAN 最常见的是:
Bulk IN + Bulk OUT
HID 常见:
Interrupt IN
UsbDeviceConnection
打开 UsbDevice 后得到:
ini
UsbDeviceConnection connection =
usbManager.openDevice(device);
UsbDeviceConnection 负责当前设备的实际 USB 操作。
常用 API:
scss
claimInterface():占用 Interface
releaseInterface():释放 Interface
controlTransfer():Control Transfer
bulkTransfer():Bulk Transfer
requestWait():等待异步 UsbRequest
getRawDescriptors():读取原始 Descriptor
close():关闭连接
USB Permission
Android 应用通过 USB Host API 直接访问 UsbDevice 时,需要针对当前设备获得 USB Permission。
相关 API:
scss
UsbManager.hasPermission(device)
UsbManager.requestPermission(device, pendingIntent)
USB Permission 和普通 Android Runtime Permission 是两套机制。
即使系统已经枚举出 UsbDevice,也不代表应用可以直接调用 openDevice()。
车载定制系统中,如果应用属于系统应用,也可以通过系统策略实现固定 USB 设备授权,避免每次插拔弹出授权框。
USB_DEVICE_ATTACHED / DETACHED
USB 外设插拔时可以处理:
UsbManager.ACTION_USB_DEVICE_ATTACHED
UsbManager.ACTION_USB_DEVICE_DETACHED
车载设备中 USB-CAN、USB-RS485、扫码枪等设备发生物理掉线后,原来的 UsbDeviceConnection + UsbInterface + UsbEndpoint 都应该视为失效。
重新插入后重新执行:发现设备 → 权限 → openDevice → claimInterface → Endpoint 初始化。
Control Transfer
Control Transfer 主要用于设备配置和控制。
Android API:
scss
UsbDeviceConnection.controlTransfer()
车载外设中常见用途:USB 串口设置波特率 + USB-CAN 设置 CAN Bitrate + Vendor Command + 设置设备工作模式 + DTR/RTS 控制。
典型参数包括:
perl
requestType
request
value
index
buffer
length
timeout
其中真正的参数含义由 USB Class 规范 或 厂商 USB 协议 决定。
Bulk Transfer
车载 USB 数据设备最常见的传输方式之一是 Bulk Transfer。
Android API:
scss
UsbDeviceConnection.bulkTransfer()
常见设备:USB 串口 + USB-RS485 + USB-CAN + USB 打印机 + 厂商自定义设备。
典型模型:
Bulk OUT:Android → USB Device
Bulk IN:USB Device → Android
Bulk 保证数据正确,但不保证固定延迟。
业务层仍然需要按照设备协议处理:帧头 + 长度 + Command + Payload + CRC。
UsbRequest
持续高速收发时可以使用:
UsbRequest
相关 API:
scss
initialize()
queue()
requestWait()
cancel()
close()
相比同步 bulkTransfer(),UsbRequest 更适合持续接收、高频 USB-CAN 或大吞吐自定义 USB 设备。
普通低速 USB-RS485、USB 串口控制设备使用 bulkTransfer() 通常已经足够。
USB 转串口
车载 Android 中常见:USB-UART + USB-RS232 + USB-RS485。
常见芯片:CH340/CH341 + CP210x + FTDI + PL2303 + CDC ACM。
典型链路:Android → USB Host → USB Serial Chip → UART → RS232/RS485 → 外部设备。
Android 官方没有统一的 UsbSerialPort 系统 API。
系统只提供:
UsbManager + UsbDevice + UsbInterface + UsbEndpoint + UsbDeviceConnection
USB Serial Driver 需要额外完成:芯片初始化 + 波特率 + 数据位 + 停止位 + 校验位 + DTR/RTS + Bulk IN/OUT。
因此 USB-RS485 和板载 /dev/ttyS* 串口是两套底层实现:
板载串口:Android → /dev/ttyS* → UART → RS485
USB-RS485:Android → UsbManager → USB Serial → UART → RS485
进入协议层以后,两者最终都可以统一处理:byte[] + Modbus RTU/私有协议。
USB CDC ACM
CDC ACM 是常见的 USB 虚拟串口标准。
典型设备结构:
Communication Interface + Data Interface + Bulk IN + Bulk OUT
Android USB Host API 能发现 CDC 设备,但 Java Framework 并没有直接提供"设置 115200 8N1"的统一串口 API。
这些参数通常通过 CDC Class Control Request 配置,例如:SET_LINE_CODING + SET_CONTROL_LINE_STATE。
因此:Android 支持 USB Host ≠ Android 自带完整 USB Serial Driver。
USB-CAN
USB-CAN 在车载和工程机械开发中很常见。
常见链路:
Android → USB Host → USB-CAN Adapter → CAN Transceiver → CANH/CANL
USB-CAN 有两种实现方式。
第一种是厂商私有 USB 协议:
UsbManager → Control/Bulk Transfer → USB-CAN 厂商协议 → CAN Frame
应用需要根据厂商协议完成:设置 CAN Bitrate + 启动 CAN + 发送 CAN Frame + 接收 CAN Frame + Filter。
第二种是 Linux 已经存在对应 USB-CAN Driver,并注册为 SocketCAN:
USB-CAN → Linux Driver → can0
这种情况下 Android 应用直接使用 SocketCAN:
can0 + PF_CAN
不需要再通过 UsbManager 解析 USB Endpoint。
因此首先要确认:
USB-CAN 是普通 USB Device,还是已经被内核注册为 SocketCAN can0。
USB HID
车载设备中常见 HID:扫码枪 + 按键面板 + 方向盘控制器 + 键盘 + 鼠标 + 自定义控制器。
HID 通常通过 Interrupt Endpoint 传输数据。
但如果设备是标准 Keyboard/Mouse HID,Android Input Framework 通常会直接接管。
链路可能变成:
USB HID → Linux HID Driver → Android InputReader → KeyEvent/MotionEvent
此时业务应用一般不需要使用 UsbManager。
例如 USB 扫码枪工作在 HID Keyboard 模式时,扫码结果通常直接表现为:
KeyEvent
如果扫码枪工作在 Vendor HID 或 POS HID 模式,才可能需要直接读取 USB HID Report。
Android Input API
标准 USB HID 键盘、按键设备进入 Android Input Framework 后,应用主要使用:
KeyEvent
MotionEvent
InputDevice
InputManager
相关系统 API:
scss
InputDevice.getDeviceIds()
InputDevice.getDevice()
InputManager.getInputDevice()
因此车载按键、方向盘按键、扫码枪等设备需要先确认数据最终进入:
Android Input Framework
还是:
UsbManager
不要重复在应用层直接抢占已经被系统 Input Driver 管理的 HID Interface。
USB Camera
车载场景常见 USB 摄像头:驾驶员监控 + 倒车摄像头 + 工业摄像头 + 外置视频设备。
标准 USB 摄像头通常使用 UVC(USB Video Class)。
如果 Android 系统已经支持 External Camera,应用更适合通过:
CameraManager + CameraDevice + CameraCaptureSession
访问摄像头。
常用系统 API:
scss
CameraManager.getCameraIdList()
CameraManager.getCameraCharacteristics()
CameraManager.openCamera()
不建议业务应用自己通过 UsbManager 解析 UVC Isochronous 数据,除非系统 Camera Stack 不支持该设备且项目本身需要实现 USB Camera Driver。
USB 网卡
车机中 USB 网卡可能用于:USB Ethernet + 4G/5G USB Modem + RNDIS/ECM/NCM。
如果 Linux 内核已经识别设备并注册网络接口,例如:
eth1
usb0
Android 应用不应该再使用 UsbManager 直接操作 USB Endpoint。
这时应该使用 Android 网络 API:
ConnectivityManager
Network
NetworkCapabilities
LinkProperties
相关链路:
USB Ethernet → Linux USB Network Driver → Network Interface → Android ConnectivityService → ConnectivityManager
因此判断 USB 设备应该在哪一层处理非常重要。
USB U 盘
U 盘通常属于 USB Mass Storage Class。
系统识别后通常由:
Linux USB Storage → vold → Android Storage
接管。
业务应用应该使用:
Storage Access Framework + DocumentFile + MediaStore
而不是自己通过 UsbManager 实现 Mass Storage/SCSI 协议。
同样可以记录为:
标准 USB Class 已有系统驱动 → 优先使用对应 Android Framework API。