Android 车载 USB 开发笔记:USB Host、USB 串口、USB-CAN、HID 与系统 API

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

相关推荐
律宏阔1 小时前
Android 车载串口开发笔记:UART、RS232、RS485、串口配置与数据通信
android
YF02112 小时前
遥控器APP端自动重连方案
android
执明wa3 小时前
Android Studio 打包 APK
android·ide·android studio
waiting9711184 小时前
Ubuntu 26.04 + Android14安装与编译教程
android·linux·ubuntu
hunterandroid4 小时前
Android 测试全景:从单元测试到 UI 自动化的完整实践
android·前端
蜡台4 小时前
Kotlin 五大作用域函数详解|let/run/apply/also/with 选型指南+实战避坑
android·java·kotlin
2401_833269305 小时前
Android registerForActivityResult详解
android
Carson带你学Android5 小时前
9月 Android Drop:Gemini 终于不只是聊天助手了
android·ai编程
Sagittarius_A*5 小时前
【LitCTF2026】lit_ezsql
android·java·数据库