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。

相关推荐
千里马学框架6 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台6 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone6 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc6 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo6 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077006 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼6 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone6 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen6 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone6 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui