安卓USB服务概述

一、USB基础知识

USB(Universal Serial Bus,通用串行总线)是一种广泛应用于电子设备的接口标准,旨在实现设备间的高速数据传输、供电和通信。它具有热插拔、即插即用、统一接口等优势。

USB通信的核心是端点(Endpoint) ,它是设备与主机间的数据传输通道。每个USB设备包含一个或多个接口(Interface),每个接口又包含多个端点,通常分为输入端点(从设备到主机)和输出端点(从主机到设备),支持批量传输、中断传输、控制传输和等时传输四种传输类型。

二、UsbService概述

USBService是Android系统中负责USB设备管理与通信的核心服务,运行于system_server进程,路径为frameworks/base/services/java/com/android/server/usb/。它通过Binder IPC机制为上层应用提供USB设备枚举、权限控制、数据传输等能力,是连接应用层与USB硬件驱动的关键中间层。

USBService主要包含四大核心组件:

  • UsbSettingsManager :处理USB设备连接状态变化的Intent通知、用户权限选择,以及系统设置变更的响应。
  • UsbHostManager :负责管理设备作为 ‌USB 主机(Host)‌ 的行为,即当手机连接外部 USB 设备(如 U 盘、鼠标、键盘)时,枚举、识别并管理这些外设。监听 /dev/bus/usb/ 下的设备插拔事件(通过 inotify 机制);维护已连接 USB 设备列表(HashMap<String, UsbDevice>);仅在设备支持 FEATURE_USB_HOST 时创建 。
  • UsbDeviceManager :负责管理设备作为 ‌USB 从设备(Gadget)‌ 的行为,管理Android设备作为从设备时的功能配置(如MTP、ADB、RNDIS网卡),仅当系统路径/sys/class/android_usb存在时实例化。
  • UsbPortManager:负责管理USB-C端口的物理角色和模式‌,适用于支持 USB Power Delivery(PD)和双角色(DRP)的现代设备。控制端口角色(Host / Device / Sink / Source)、管理供电策略(如反向充电、功率协商)、在设备同时具备 Host 和 Device 能力时协调端口切换 ‌。

三、USB工作模式

在Android系统中,USB通信主要分为两种模式,USBService针对不同模式提供差异化能力:

1. 主机模式(Host Mode)

  • 核心能力 :Android设备作为USB主机,为外接设备供电并主动枚举设备,支持双向数据传输。
  • 系统要求 :Android 3.1(API Level 12)及以上版本原生支持,依赖硬件CPU的USB主机控制器。
  • 典型场景 :连接U盘、键盘、打印机、Zigbee模块等外设。

2. 设备模式(Device Mode)

  • 核心能力 :Android设备作为USB从设备,由主机(如电脑)供电并与之通信。
  • 系统要求 :全版本支持,可通过配置切换MTP、PTP、RNDIS等功能。
  • 典型场景 :手机连接电脑传输文件、共享网络。

3. 配件模式(Accessory Mode)

  • 核心能力 :外部硬件作为主机,Android设备作为配件与之通信,可通过Google API外挂库兼容至Android 2.3.4。
  • 适用场景 :适用于不具备主机能力的旧款设备,需配件遵守Android配件通信协议。

四、Android USB相关核心类与核心API说明

Android系统通过android.hardware.usb包提供了完整的USB通信API,核心类包括以下几个:

1. UsbManager

UsbManager是Android USB管理的核心类,负责枚举已连接的USB设备/配件、管理设备权限、建立设备连接等。它是应用程序与USB硬件交互的入口,所有USB操作都需通过该类启动。

获取UsbManager实例:

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

关键方法:

  • getDeviceList():获取已连接的USB设备列表,返回HashMap<String, UsbDevice>。
  • requestPermission(UsbDevice device, PendingIntent pi):向用户请求设备访问权限。
  • openDevice(UsbDevice device):打开设备,返回UsbDeviceConnection用于数据传输。

2. UsbDevice

UsbDevice代表一个已连接的USB设备,包含设备的基本信息(如设备名称、供应商ID、产品ID、设备类别等),并提供访问设备接口和端点的方法。通过UsbManager.getDeviceList()可获取当前所有已连接的UsbDevice对象。

关键参数说明:

  • mName: 这个字段代表 USB 设备的名称。它通常是系统为设备分配的一个标识符,可能与设备的序列号或特定标识相关联。通过 UsbDevice 对象的 getDeviceName() 方法可以获取到这个名称。

  • mManufacturerName: 这个字段表示 USB 设备的制造商名称。它提供了设备制造商的信息,例如 "Apple" 或 "Logitech"。如果设备没有提供制造商信息,或者无法读取该信息,则此字段可能为 null。可以通过 UsbDevice 对象的 getManufacturerName() 方法获取此信息。

  • mProductName: 这个字段表示 USB 设备的产品名称。它通常代表设备的具体型号或产品名称,例如 "iPhone" 或 "G502 Hero"。如果设备没有提供产品名称信息,或者无法读取该信息,则此字段可能为 null。可以通过 UsbDevice 对象的 getProductName() 方法获取此信息。

  • mVersion: 这个字段代表 USB 设备的版本信息。它通常表示设备的固件或硬件版本号。通过 UsbDevice 对象的 getVersion() 方法可以获取到这个版本信息。

  • UsbConfiguration[] mConfigurations: 这个字段是一个数组,包含了 USB 设备的所有配置(UsbConfiguration)信息。一个 USB 设备可以有多个配置,每个配置定义了设备在特定状态下的功能和接口集合。通过 UsbDevice 对象的 getConfigurationCount()getConfiguration(int index) 方法可以访问这些配置。

  • ‌**IUsbSerialReader mSerialNumberReader:** 这个字段是一个接口,用于读取 USB 设备的序列号。序列号是设备的唯一标识符。通过 UsbDevice 对象的 getSerialNumber() 方法可以获取到设备的序列号。

  • ‌**mVendorId:** 这个字段表示 USB 设备的厂商 ID (Vendor ID)。这是一个由 USB-IF (USB Implementers Forum) 分配的唯一标识符,用于识别设备的制造商。通过 UsbDevice 对象的 getVendorId() 方法可以获取到这个 ID。

  • mProductId: 这个字段表示 USB 设备的产品 ID (Product ID)。它与厂商 ID (VID) 一起,用于唯一标识设备的具体型号。通过 UsbDevice 对象的 getProductId() 方法可以获取到这个 ID。

  • mClass: 这个字段表示 USB 设备的设备类别 (Device Class)。它遵循 USB 2.0 规范中定义的设备类别代码。例如,0x00 表示使用接口描述符中的类别信息,0x03 表示 HID (Human Interface Device) 类别,0x07 表示打印机类别等。通过 UsbDevice 对象的 getDeviceClass() 方法可以获取到这个类别值。

  • ‌**mSubclass:** 这个字段表示 USB 设备的子类别 (Device Subclass)。它与设备类别 (Class) 和协议 (Protocol) 一起,更详细地定义了设备的功能。例如,对于 HID 类设备,子类别可以表示键盘、鼠标等。通过 UsbDevice 对象的 getDeviceSubclass() 方法可以获取到这个子类别值。

  • mProtocol: 这个字段表示 USB 设备的协议 (Device Protocol)。它与设备类别 (Class) 和子类别 (Subclass) 一起,定义了设备使用的具体协议。例如,对于 HID 类设备,协议可以指定使用的特定协议。通过 UsbDevice 对象的 getDeviceProtocol() 方法可以获取到这个协议值。

  • ‌**mHasAudioPlayback:** 这个布尔字段表示该 USB 设备是否支持音频播放功能。如果为 true,则设备可能包含音频播放相关的接口或功能。

  • mHasAudioCapture: 这个布尔字段表示该 USB 设备是否支持音频捕获功能。如果为 true,则设备可能包含音频捕获相关的接口或功能。

  • mHasMidi: 这个布尔字段表示该 USB 设备是否支持 MIDI (Musical Instrument Digital Interface) 功能。如果为 true,则设备可能包含 MIDI 相关的接口或功能。

  • ‌**mHasVideoPlayback:** 这个布尔字段表示该 USB 设备是否支持视频播放功能。如果为 true,则设备可能包含视频播放相关的接口或功能。

  • ‌**mHasVideoCapture:** 这个布尔字段表示该 USB 设备是否支持视频捕获功能。如果为 true,则设备可能包含视频捕获相关的接口或功能。

  • UsbInterface[] mInterfaces:这个字段是一个数组,包含了 USB 设备的所有接口(UsbInterface)信息。一个 USB 设备可以有多个功能不同的接口,每个接口代表设备的一个独立功能模块。例如,一个 USB 鼠标可能包含一个 HID(人机接口设备)接口用于接收按键和移动数据,以及一个可能的配置接口用于设备设置。通过 UsbDevice 对象的 getInterfaceCount()getInterface(int index) 方法可以访问这些接口,获取每个接口的详细信息,如其类别、子类别、协议以及所包含的端点(UsbEndpoint)等

备注:mClass/mSubclass/mProtocol的取值对照表见本文附录

3. UsbConfiguration

UsbDevice的配置信息。USB配置可以有一个或多个接口,每个接口提供不同的功能,与其他接口分开。一个接口将有一个或多个UsbEndpoint,它们是主机与设备传输数据的通道。

关键参数说明:

  • mId ‌: 这个字段表示 USB 配置的唯一标识符(ID)。它用于在设备的多个配置中唯一标识一个特定的配置。通过 UsbConfiguration 对象的 getId() 方法可以获取到这个 ID。

  • mName ‌: 这个字段表示 USB 配置的名称。它提供了配置的可读性标识,通常由设备制造商定义。如果设备没有提供配置名称信息,或者无法读取该信息,则此字段可能为 null。通过 UsbConfiguration 对象的 getName() 方法可以获取到这个名称。

  • **mAttributes**‌: 这个字段表示 USB 配置的属性(Configuration Attributes)。它是一个位图,描述了配置的特性。根据 USB 规范,此字段的高 8 位(Bit 7-0)定义了配置的特性:

    • Bit 4-0: 保留位(通常设为 0)
    • Bit 5: 远程唤醒(Remote Wakeup):如果为 1,表示设备支持远程唤醒功能;如果为 0,则不支持。
    • Bit 6: 自给电源(Self-Powered):如果为 1,表示设备使用自备电源;如果为 0,表示设备从总线获取电源。
    • Bit 7: 保留位(通常设为 1)
    • 通过 UsbConfiguration 对象的 getAttributes() 方法可以获取到这个属性值。
  • ‌**mMaxPower** ‌: 这个字段表示 USB 配置下的最大电源消耗(Maximum Power Consumption)。它定义了在该配置下设备从 USB 总线汲取的最大电流值,单位为 2 mA。例如,如果此值为 100,则表示设备最大消耗 200 mA 电流。通过 UsbConfiguration 对象的 getMaxPower() 方法可以获取到这个最大电源消耗值。

  • ‌**Parcelable[] mInterfaces:** 这个字段是一个数组,包含了该 USB 配置下的所有接口(UsbInterface)信息。接口是设备功能的逻辑划分,每个接口可能支持不同的功能。该数组在配置创建时可能为 null,但在配置被正确初始化后会包含所有接口的引用。通过 UsbConfiguration 对象的 getInterfaceCount()getInterface(int index) 方法可以访问这些接口,获取每个接口的详细信息,如其类别、子类别、协议以及所包含的端点(UsbEndpoint)等。

4. UsbInterface

UsbInterface代表USB设备的一个功能接口,每个设备可包含一个或多个接口,每个接口对应设备的一项特定功能(如存储、打印、音频等)。接口是设备功能的逻辑划分,应用程序需通过接口访问具体的传输端点。

关键参数说明:

  • mId ‌:这个字段表示 USB 接口的唯一标识符(ID)。它用于在设备的配置中唯一标识一个接口。通过 UsbInterface 对象的 getId() 方法可以获取到这个 ID。

  • mAlternateSetting ‌:这个字段表示 USB 接口的备用设置(Alternate Setting)。一个 USB 接口可以有多个备用设置,每个设置可能定义了不同的功能或数据传输模式。例如,一个接口可能支持多种数据传输速率或不同的数据格式。通过 UsbInterface 对象的 getAlternateSetting() 方法可以获取到当前激活的备用设置值。

  • mName ‌:这个字段表示 USB 接口的名称。它提供了接口的可读性标识,通常由设备制造商定义。如果设备没有提供接口名称信息,或者无法读取该信息,则此字段可能为 null。通过 UsbInterface 对象的 getName() 方法可以获取到这个名称。

  • mClass ‌:这个字段表示 USB 接口的类别(Interface Class)。它遵循 USB 2.0 规范中定义的接口类别代码,用于标识该接口的主要功能。例如,0x03 表示 HID (Human Interface Device) 类别,0x07 表示打印机类别等。通过 UsbInterface 对象的 getInterfaceClass() 方法可以获取到这个类别值。

  • ‌**mSubclass** ‌:这个字段表示 USB 接口的子类别(Interface Subclass)。它与接口类别(Class)一起,更详细地定义了接口的功能。例如,对于 HID 类接口,子类别可以表示键盘、鼠标等。通过 UsbInterface 对象的 getInterfaceSubclass() 方法可以获取到这个子类别值。

  • mProtocol ‌:这个字段表示 USB 接口的协议(Interface Protocol)。它与接口类别(Class)和子类别(Subclass)一起,定义了接口使用的具体协议。例如,对于 HID 类接口,协议可以指定使用的特定协议。通过 UsbInterface 对象的 getInterfaceProtocol() 方法可以获取到这个协议值。

  • Parcelable[] mEndpoints ‌:这个字段是一个数组,包含了该 USB 接口的所有端点(UsbEndpoint)信息。端点是设备与主机之间进行数据传输的通道,通常有输入(IN)和输出(OUT)端点。该数组在接口创建时可能为 null,但在接口被正确初始化后会包含所有端点的引用。通过 UsbInterface 对象的 getEndpointCount()getEndpoint(int index) 方法可以访问这些端点,获取每个端点的详细信息,如端点号、传输类型(控制、批量、中断、等时)等

5. UsbEndpoint

UsbEndpoint是USB设备的通信端点,是数据传输的实际通道。每个UsbInterface包含多个端点,分别负责输入和输出数据。端点的类型(批量、中断、控制、等时)决定了数据传输的特性。

支持四种传输类型:

  • 控制传输 :用于设备配置、命令交互,可靠但速度慢。
  • 批量传输 :用于大量数据传输(如文件),可靠且速度快。
  • 中断传输 :用于小量、实时数据(如键盘输入)。
  • 等时传输 :用于实时音频、视频传输,不保证可靠性但低延迟。

关键参数说明:

  • ‌**mAddress** ‌:这个字段表示 USB 端点的地址(Endpoint Address)。它包含了端点号和方向信息。根据 USB 规范,地址的低 4 位(Bit 0-3)表示端点号,Bit 7 表示方向:0 表示输出端点(主机到设备),1 表示输入端点(设备到主机)。通过 UsbEndpoint 对象的 getAddress() 方法可以获取到这个地址值。

  • mAttributes ‌:这个字段表示 USB 端点的属性(Endpoint Attributes)。它描述了端点的传输类型和相关特性。根据 USB 规范,属性字段的低 2 位(Bit 1-0)定义了传输类型:00 = 控制传输(Control Transfer),01 = 同步传输(Isochronous Transfer),10 = 批量传输(Bulk Transfer),11 = 中断传输(Interrupt Transfer)。通过 UsbEndpoint 对象的 getAttributes() 方法可以获取到这个属性值。

  • mMaxPacketSize ‌:这个字段表示 USB 端点的最大数据包大小(Maximum Packet Size)。它定义了在当前配置下,该端点能够接收或发送的最大数据包的字节数。对于不同类型的传输,这个值有不同的意义:对于批量传输和中断传输,此值表示每个数据包的最大字节数;对于等时传输,此值用于为每帧的数据负载预留时间。通过 UsbEndpoint 对象的 getMaxPacketSize() 方法可以获取到这个最大数据包大小。

  • mInterval ‌:这个字段表示 USB 端点的轮询间隔(Polling Interval)或传输间隔。它定义了周期性数据传输端点(如中断传输或等时传输)的时间间隙。对于中断传输,此值表示主机轮询该端点的频率(以毫秒为单位)。对于等时传输,此值通常为 1(表示每毫秒传输一次)。对于批量传输和控制传输,此值通常无意义。通过 UsbEndpoint 对象的 getInterval() 方法可以获取到这个间隔值。

针对上面的类,一个具体的UsbHostManager的打印示例如下:(插入鼠标)

复制代码
D UsbHostManager: USB device attached: vidpid 30fa:1701 mfg/product/ver/serial INSTANT/USB GAMING MOUSE  /1.00/null hasAudio/HID/Storage: false/true/false
D UsbHostManager: Added device UsbDevice[mName=/dev/bus/usb/003/010,mVendorId=12538,mProductId=5889,mClass=0,mSubclass=0,mProtocol=0,mManufacturerName=INSTANT,mProductName=USB GAMING MOUSE  ,mVersion=1.00,mSerialNumberReader=com.android.server.usb.UsbSerialReader@600a58f, mHasAudioPlayback=false, mHasAudioCapture=false, mHasMidi=false, mHasVideoCapture=false, mHasVideoPlayback=false, mConfigurations=[
D UsbHostManager: UsbConfiguration[mId=1,mName=null,mAttributes=160,mMaxPower=50,mInterfaces=[
D UsbHostManager: UsbInterface[mId=0,mAlternateSetting=0,mName=null,mClass=3,mSubclass=1,mProtocol=2,mEndpoints=[
D UsbHostManager: UsbEndpoint[mAddress=129,mAttributes=3,mMaxPacketSize=8,mInterval=10]]
D UsbHostManager: UsbInterface[mId=1,mAlternateSetting=0,mName=null,mClass=3,mSubclass=0,mProtocol=1,mEndpoints=[
D UsbHostManager: UsbEndpoint[mAddress=130,mAttributes=3,mMaxPacketSize=8,mInterval=10]]]]

从打印可以看出,该鼠标有两个UsbInterface,每个UsbInterface有一个UsbEndpoint。

UsbDevice信息:mName=/dev/bus/usb/003/010,mVendorId=12538,mProductId=5889,mClass=0,mSubclass=0,mProtocol=0,mManufacturerName=INSTANT,mProductName=USB GAMING MOUSE ,mVersion=1.00,mSerialNumberReader=com.android.server.usb.UsbSerialReader@600a58f, mHasAudioPlayback=false, mHasAudioCapture=false, mHasMidi=false, mHasVideoCapture=false, mHasVideoPlayback=false

UsbConfiguration信息:mId=1,mName=null,mAttributes=160(10100000,支持远程唤醒),mMaxPower=50(设备最大消耗2mA*50=100mA)

UsbInterface&UsbEndPoint信息:

UsbInterface[mId=0,mAlternateSetting=0,mName=null,mClass=3(HID类别),mSubclass=1(启动),mProtocol=2(鼠标),mEndpoints=[UsbEndpoint[mAddress=129,mAttributes=3(中断传输),mMaxPacketSize=8,mInterval=10(每10ms传输一次)]]

UsbInterface[mId=1,mAlternateSetting=0,mName=null,mClass=3(HID设备),mSubclass=0(无启动),mProtocol=1(键盘),mEndpoints=[UsbEndpoint[mAddress=130,mAttributes=3(终中断传输),mMaxPacketSize=8,mInterval=10(每10ms传输一次)]]

6. UsbDeviceConnection

UsbDeviceConnection代表与USB设备的物理连接。

通过usbManager.openDevice(device)获取,负责实际的数据传输,核心方法:

  1. claimInterface(UsbInterface intf, boolean force):占用指定接口,开始通信前必须调用。
  2. bulkTransfer(UsbEndpoint endpoint, byte[] buffer, int length, int timeout):批量数据传输,返回实际传输的字节数。
  3. controlTransfer(int requestType, int request, int value, int index, byte[] buffer, int length, int timeout):控制传输,用于发送命令或获取设备状态。

7. UsbAccessory

UsbAccessory代表一个USB配件,仅在配件模式下使用。它包含配件的基本信息(如制造商、型号、版本等),应用程序可通过UsbManager与配件建立连接并通信。

关键参数说明

  • mManufacturer ‌:这个字段表示 USB 配件的制造商名称。当配件连接到 Android 设备时,它会报告其制造商信息,该信息用于识别配件的来源。通过 UsbAccessory 对象的 getManufacturer() 方法可以获取到这个制造商名称。

  • mModel ‌:这个字段表示 USB 配件的型号名称。它提供了配件的具体型号信息,用于进一步识别配件的类型。通过 UsbAccessory 对象的 getModel() 方法可以获取到这个型号名称。

  • mDescription ‌:这个字段表示 USB 配件的描述信息。它是一个用户可见的描述,用于提供关于配件功能或用途的额外信息。如果配件没有提供描述信息,则此字段可能为 null。通过 UsbAccessory 对象的 getDescription() 方法可以获取到这个描述信息。

  • ‌**mVersion** ‌:这个字段表示 USB 配件的版本信息。它通常代表配件的固件或硬件版本号。如果配件没有提供版本信息,则此字段可能为 null。通过 UsbAccessory 对象的 getVersion() 方法可以获取到这个版本信息。

  • ‌**mUri** ‌:这个字段表示 USB 配件的 URI(统一资源标识符)。它通常指向配件制造商的网站或其他相关信息页面。如果配件没有提供 URI 信息,则此字段可能为 null。通过 UsbAccessory 对象的 getUri() 方法可以获取到这个 URI。

  • ‌**IUsbSerialReader mSerialNumberReader** ‌:这个字段是一个接口,用于读取 USB 配件的序列号。序列号是配件的唯一标识符。通过 UsbAccessory 对象的 getSerialNumber() 方法可以获取到配件的序列号。

8. UsbRequest

UsbRequest 类主要用于‌异步数据传输 ‌,用于从UsbDeviceConnection读取和写入数据,是实现与USB设备通信的关键组件之一。它允许应用程序提交数据传输请求,并在传输完成后通过回调机制处理结果。通常与 UsbDeviceConnectionUsbInterfaceUsbEndpoint 等类配合使用,共同完成USB设备的连接和数据交互。

UsbRequests可用于在批量和中断端点上传输数据。批量端点的请求可通过 UsbDeviceConnection.bulkTransfer 同步发送,或通过 queue 和 UsbDeviceConnection.requestWait异步发送。中断端点的请求仅以异步方式发送和接收。此类不支持对零端点的请求,如果需要可使用 UsbDeviceConnection.controlTransfer 方法处理零端点请求。

对于高并发场景,可使用UsbRequest实现异步传输:

UsbRequest request = new UsbRequest();

request.initialize(connection, inEp);

ByteBuffer buffer = ByteBuffer.allocate(64);

request.queue(buffer, buffer.capacity());

connection.requestWait(); // 等待异步请求完成

附录

USB 类/子类/协议对照表

|--------------|-------------|----------------|------------|----------------|---------------|
| Class (十六进制) | 类别名称 | Subclass (常用值) | 含义 | Protocol (常用值) | 含义 |
| 00h | 未指定(仅设备描述符) | 00h | 未指定 | 00h | 未指定 |
| 01h | 音频(Audio) | 00h | 未定义 | 00h | 通用 |
| | | 01h | 音频控制 | 01h | USB Audio 1.0 |
| | | 02h | 音频流 | 02h | USB Audio 2.0 |
| | | 03h | MIDI 流 | | |
| 02h | CDC 通信控制 | 01h | ACM(虚拟串口) | 00h | 通用 |
| | | 02h | ECM 以太网 | 01h | AT 命令 |
| | | 06h | ISDN | 20h | NCM |
| | | 07h | NCM 以太网 | 30h | EEM |
| | | 09h | RNDIS | FFh | 厂商自定义 |
| 03h | HID | 00h | 无启动 | 00h | 无 |
| | | 01h | 启动接口 | 01h | 键盘 |
| | | | | 02h | 鼠标 |
| 06h | 图像(PTP/MTP) | 01h | PTP/MTP | 01h | PTP |
| | | | | 02h | MTP |
| 07h | 打印机 | 01h | PCL5 | 00h | 被动 |
| | | 02h | PostScript | 01h | 主动 |
| 08h | 大容量存储 | 01h | SCSI 透明 | 00h | CBI 无中断 |
| | | 02h | ATAPI/CD | 01h | CBI 中断 |
| | | 04h | UFI 软盘 | 02h | Bulk-Only(常用) |
| | | 06h | SCSI 64 位 | 03h | UAS |
| 09h | 集线器 | 00h | 全速/低速 Hub | 00h | USB 2.0 |
| | | 01h | 高速 Hub | 01h | USB 3.0 |
| 0Ah | CDC 数据 | 00h | 通用 | 00h | 通用 |
| 0Bh | 智能卡 | 00h | 通用 | 01h | ISO 7816 |
| 0Eh | 视频 | 01h | 视频控制 | 00h | 通用 |
| | | 02h | 视频流 | | |
| 0Fh | 个人医疗 | 00h--FFh | 厂商定义 | 00h--FFh | 厂商定义 |
| 10h | 音视频 AV | 00h--FFh | 厂商定义 | 00h--FFh | 厂商定义 |
| 11h | Billboard | 00h | 通用 | 00h | 通用 |
| DCh | 诊断设备 | 00h--FFh | 厂商定义 | 00h--FFh | 厂商定义 |
| DFh | DFU 固件升级 | 01h | DFU | 01h | DFU 协议 |
| E0h | 无线控制器 | 01h | RF | 01h | 2.4G |
| | | 02h | 蓝牙 | 02h | 蓝牙 |
| EFh | 杂项 | 03h | IAD | 01h | IAD 协议 |
| FEh | 应用专用 | 01h | DFU | 00h--FFh | 厂商定义 |
| | | 03h | USBTMC | | |
| | | 07h | 指纹 | | |
| FFh | 厂商自定义 | 00h--FFh | 厂商定义 | 00h--FFh | 厂商定义 |

常见设备速查表:

|--------|-------|----------|----------|
| 设备 | Class | Subclass | Protocol |
| 鼠标 | 03h | 01h | 02h |
| 键盘 | 03h | 01h | 01h |
| U盘/硬盘 | 08h | 06h | 50h |
| USB 串口 | 02h | 02h | 01h |
| 打印机 | 07h | 01h | 02h |
| 摄像头 | 0Eh | 01h | 00h |
| 蓝牙适配器 | E0h | 01h | 01h |
| DFU 升级 | DFh | 01h | 01h |
| 厂商自定义 | FFh | 任意 | 任意 |

相关推荐
alexhilton10 小时前
Compose中初始加载逻辑究竟应该放在哪里?
android·kotlin·android jetpack
zh_xuan11 小时前
启动RN服务端口被占用
android·react native
Code-keys13 小时前
Android Codec2 Filter 算法模块开发指南
android·算法·音视频·视频编解码
y = xⁿ14 小时前
MySQL:count(1)与count(*)有什么区别,深分页问题
android·数据库·mysql
程序员陆业聪16 小时前
Android启动全景图:一次冷启动背后到底发生了什么
android
安卓程序员_谢伟光18 小时前
m3颜色定义
android·compose
麻辣璐璐19 小时前
EditText属性运用之适配RTL语言和LTR语言的输入习惯
android·xml·java·开发语言·安卓
北京自在科技19 小时前
谷歌 Find Hub 网页端全面升级:电脑可直接管理追踪器与耳机
android·ios·安卓·findmy
Rush-Rabbit19 小时前
魅族21Pro刷ColorOS16.0操作步骤
android