Android 的 USB 连接可同时服务三类完全不同的使用场景:开发者通过 ADB 调试应用、普通用户通过 MTP 传输照片、配件厂商通过 USB 主机模式接入游戏手柄。每一类场景都使用软件栈中独立的模块,该软件栈覆盖从用户空间 Java 服务,一直到 Linux 内核的 USB 小工具(gadget)与主机控制器驱动。本章追踪 USB 线路上每一字节数据的流向,依次经过 HAL 层、框架层服务,最终抵达应用层,全文会引用真实的 AOSP 源码路径。
39.1 USB 框架概述
39.1.1 整体架构概览
Android USB 子系统划分为 4 个垂直层级:公开 SDK API(UsbManager)、系统服务(UsbService 及其子管理器)、硬件抽象层(AIDL HAL 接口 IUsb、IUsbGadget)、Linux 内核 USB 子系统(gadget 驱动、主机控制器驱动、configfs、functionfs)。

39.1.2 核心组件
| UsbManager | SDK API | frameworks/base/core/java/android/hardware/usb/UsbManager.java | 应用使用的公开 API | ||||
| UsbService | 系统服务 | frameworks/base/services/usb/…/UsbService.java | 核心协调器 | ||||
| UsbDeviceManager | 内部管理器 | frameworks/base/services/usb/…/UsbDeviceManager.java | Gadget 模式状态机 | ||||
| UsbHostManager | 内部管理器 | frameworks/base/services/usb/…/UsbHostManager.java | 主机模式设备枚举 | ||||
| UsbPortManager | 内部管理器 | frameworks/base/services/usb/…/UsbPortManager.java | Type‑C 端口管理 | ||||
| UsbPermissionManager | 内部管理器 | frameworks/base/services/usb/…/UsbPermissionManager.java | 按用户跟踪权限 | ||||
| IUsb | AIDL HAL | hardware/interfaces/usb/aidl/…/IUsb.aidl | 端口状态、角色切换 | ||||
| IUsbGadget | AIDL HAL | hardware/interfaces/usb/gadget/aidl/…/IUsbGadget.aidl | Gadget 功能配置 | ||||
| adbd | 原生守护进程 | packages/modules/adb/daemon/main.cpp | ADB 守护进程 | ||||
| MTP Native | 原生库 | frameworks/av/media/mtp/ | MTP 协议实现 | MTP Service | Java 服务 | packages/services/Mtp/ | MTP 文档提供者 |
39.1.3 双模式架构:Gadget 模式与主机模式
同一个 USB Type‑C 端口可工作在两种完全不同的模式,模式由 USB 供电协议协商得到的数据角色决定:
设备 / Gadget 模式(UFP):Android 设备作为外设接入主机(通常是 PC)。支持 MTP 文件传输、ADB 调试、PTP 照片传输、RNDIS 网络共享、MIDI、USB 配件 AOA。内核 USB gadget 框架(configfs)对外提供复合 USB 功能。
主机模式(DFP):Android 设备充当 USB 主机。会枚举接入的 USB 外设(键盘、鼠标、存储、音频设备),并通过 UsbManager API 向应用提供访问。
UsbPortManager 通过 IUsb HAL 监听端口状态变更,协调两种模式之间的切换。
39.1.4 UsbManager —— 公开 API
UsbManager(源码:frameworks/base/core/java/android/hardware/usb/UsbManager.java)带有@SystemService注解,是应用与 USB 交互的入口。它提供:
设备 (gadget) 模式操作:
- 查询与设置当前 USB 功能(MTP、PTP 等)
- 获取 USB 配件信息
- 打开 USB 配件连接
主机模式操作:
- 枚举已连接 USB 设备(getDeviceList())
- 请求设备通信权限
- 打开设备连接(openDevice())
功能常量定义可用的 gadget 配置:
// 摘自UsbManager.java —— 功能位掩码
public static final long FUNCTION_NONE = 0;
public static final long FUNCTION_MTP = GadgetFunction.MTP; // 1 << 2
public static final long FUNCTION_PTP = GadgetFunction.PTP; // 1 << 4
public static final long FUNCTION_RNDIS = GadgetFunction.RNDIS; // 1 << 5
public static final long FUNCTION_MIDI = GadgetFunction.MIDI; // 1 << 3
public static final long FUNCTION_ACCESSORY = GadgetFunction.ACCESSORY; // 1 << 1
public static final long FUNCTION_AUDIO_SOURCE = GadgetFunction.AUDIO_SOURCE; // 1 << 6
public static final long FUNCTION_ADB = GadgetFunction.ADB; // 1
public static final long FUNCTION_NCM = GadgetFunction.NCM; // 1 << 10
public static final long FUNCTION_UVC = GadgetFunction.UVC; // 1 << 7
这些常量直接映射 AIDL 可序列化对象 GadgetFunction,定义位置:hardware/interfaces/usb/gadget/aidl/android/hardware/usb/gadget/GadgetFunction.aidl。
39.1.5 UsbService —— 核心协调器
UsbService(源码:frameworks/base/services/usb/java/com/android/server/usb/UsbService.java)实现 IUsbManager,运行在 system_server 进程。它是所有 USB 操作的 Binder 服务端点,将工作委派给各个专用子管理器:

UsbAuthManager 仅在enableUsbHostAuthorization标记开启时才会实例化(参考 UsbService.java 中mAuthManager = new UsbAuthManager(…)附近代码);它对接独立进程 Rust 守护进程,详见 39.10 节。
服务生命周期遵循标准 SystemService 模式:
39.1.6 系统属性与 Sysfs 路径
UsbDeviceManager 通过多个内核接口与系统属性监控、控制 USB 状态:
| USB 状态 sysfs | /sys/class/android_usb/android0/state | 旧版 gadget 状态 | ||||||
| USB 功能 sysfs | /sys/class/android_usb/android0/functions | 旧版功能配置 | ||||||
| UDC 控制器 | sys.usb.controller(系统属性) | ConfigFS UDC 名称 | ||||||
| USB 配置 | persist.sys.usb.config(系统属性) | 持久化 USB 配置 | RNDIS 地址 | /sys/class/android_usb/android0/f_rndis/ethaddr | 网络共享 MAC 地址 | MIDI ALSA | /sys/class/android_usb/android0/f_midi/alsa | MIDI 设备信息 |
| UEvent 匹配 | DEVPATH=/devices/virtual/android_usb/android0 | 旧版状态变更 | ||||||
| UEvent 匹配 | SUBSYSTEM=udc | 现代 UDC 状态变更 | ||||||
| FunctionFS | /dev/usb‑ffs/adb/ | ADB FunctionFS 端点 |
39.2 UsbDeviceManager:Gadget 模式状态机
39.2.1 概述
UsbDeviceManager(源码:frameworks/base/services/usb/java/com/android/server/usb/UsbDeviceManager.java)是 USB 框架中最复杂的组件。它管理 Android 设备作为 USB 外设的行为,处理功能切换(MTP、PTP、RNDIS、配件、MIDI、ADB)、线缆事件触发的状态迁移,同时协调锁屏状态、用户偏好、内核层 USB 配置。
该类实现ActivityTaskManagerInternal.ScreenObserver,用于响应锁屏状态变更。关键点:MTP 访问用户存储数据要求设备屏幕处于解锁状态。
39.2.2 架构

39.2.3 双 Handler 策略
UsbDeviceManager 在构造时选择两种具体 Handler 实现之一:
// 摘自UsbDeviceManager构造函数
if (mUsbGadgetHal == null) {
// 初始化传统UsbHandler
mHandler = new UsbHandlerLegacy(FgThread.get().getLooper(),
mContext, this, alsaManager, permissionManager);
} else {
// 初始化基于HAL的UsbHandler
mHandler = new UsbHandlerHal(FgThread.get().getLooper(),
mContext, this, alsaManager, permissionManager);
}
- UsbHandlerHal:现代设备使用,设备具备 IUsbGadget AIDL HAL。调用 HAL 的setCurrentUsbFunctions()请求配置变更,HAL 内部完成内核 ConfigFS 操作。
- UsbHandlerLegacy:旧设备无 gadget HAL 时的回退方案。直接写 sysfs 文件与系统属性切换 USB 功能。
39.2.4 基于消息的状态机
UsbHandler 通过 Android Handler 消息队列处理 USB 状态迁移。所有状态变更串行在前台线程执行,避免竞态条件。
| 0 | MSG_UPDATE_STATE | 内核上报连接 / 断开 / 配置完成 |
| 1 | MSG_ENABLE_ADB | 开发者选项开关 ADB |
| 2 | MSG_SET_CURRENT_FUNCTIONS | 应用请求切换功能 |
| 3 | MSG_SYSTEM_READY | system server 就绪 |
| 4 | MSG_BOOT_COMPLETED | 开机完成广播 |
| 5 | MSG_USER_SWITCHED | 切换当前用户 |
| 6 | MSG_UPDATE_USER_RESTRICTIONS | 用户策略变更 |
| 7 | MSG_UPDATE_PORT_STATE | Type‑C 端口状态变更 |
| 8 | MSG_ACCESSORY_MODE_ENTER_TIMEOUT | 配件协商 10 秒超时 |
| 9 | MSG_UPDATE_CHARGING_STATE | 电池充电状态变更 |
| 10 | MSG_UPDATE_HOST_STATE | 主机模式设备插拔 |
| 11 | MSG_LOCALE_CHANGED | 语言变更(更新通知) |
| 12 | MSG_SET_SCREEN_UNLOCKED_FUNCTIONS | 屏幕解锁时功能偏好 |
| 13 | MSG_UPDATE_SCREEN_LOCK | 锁屏显示 / 隐藏 |
| 14 | MSG_SET_CHARGING_FUNCTIONS | 切换至仅充电模式 |
| 15 | MSG_SET_FUNCTIONS_TIMEOUT | 功能切换超时 |
| 16 | MSG_GET_CURRENT_USB_FUNCTIONS | 查询当前 gadget 功能 |
| 17 | MSG_FUNCTION_SWITCH_TIMEOUT | gadget 重新枚举超时 |
| 18 | MSG_GADGET_HAL_REGISTERED | HAL 服务就绪 |
| 19 | MSG_RESET_USB_GADGET | 重置 gadget 硬件 |
| 20 | MSG_ACCESSORY_HANDSHAKE_TIMEOUT | AOA 握手超时 |
| 21 | MSG_INCREASE_SENDSTRING_COUNT | 收到 AOA 字符串描述符 |
| 22 | MSG_UPDATE_USB_SPEED | USB 速率协商完成 |
| 23 | MSG_UPDATE_HAL_VERSION | HAL 版本信息更新 |
| 24 | MSG_USER_UNLOCKED_AFTER_BOOT | 开机后首次解锁 |
39.2.5 USB 状态迁移
内核通过 UEvent 消息上报 USB 状态变更。UsbUEventObserver 接收消息并转换为 Handler 消息。

UsbHandler 的updateState()将内核状态字符串映射为内部状态:
// 摘自UsbHandler.updateState()
if (\”DISCONNECTED\”.equals(state)) {
connected = 0; configured = 0;
} else if (\”CONNECTED\”.equals(state)) {
connected = 1; configured = 0;
} else if (\”CONFIGURED\”.equals(state)) {
connected = 1; configured = 1;
}
39.2.6 功能切换
用户或系统请求切换 USB 功能时,状态机执行多步流程:

39.2.7 防抖与超时
功能切换会带来短暂 USB 断开。状态机会做防抖处理,避免虚假断开事件干扰切换流程。
// UsbDeviceManager中防抖延时
private static final int DEVICE_STATE_UPDATE_DELAY_EXT = 3000; // 3秒
private static final int DEVICE_STATE_UPDATE_DELAY = 1000; // 1秒
private static final int HOST_STATE_UPDATE_DELAY = 1000; // 1秒
private static final int ACCESSORY_REQUEST_TIMEOUT = 10 * 1000; // 10秒
private static final int ACCESSORY_HANDSHAKE_TIMEOUT = 10 * 1000; // 10秒
调用resetUsbGadget()之后,通过mResetUsbGadgetDisableDebounce临时关闭防抖,保证 gadget 重置后的第一次断开事件立即处理。
39.2.8 与锁屏交互
MTP 需要访问用户存储,锁屏时必须做保护。UsbDeviceManager 与锁屏模块协同工作:
39.2.9 接口黑名单
出于安全考虑,当设备作为 USB 主机时,部分 USB 接口类禁止应用访问:
// 摘自UsbDeviceManager静态代码块
sDenyInterfaces.add(UsbConstants.USB_CLASS_AUDIO);
sDenyInterfaces.add(UsbConstants.USB_CLASS_COMM);
sDenyInterfaces.add(UsbConstants.USB_CLASS_HID);
sDenyInterfaces.add(UsbConstants.USB_CLASS_PRINTER);
sDenyInterfaces.add(UsbConstants.USB_CLASS_MASS_STORAGE);
sDenyInterfaces.add(UsbConstants.USB_CLASS_HUB);
sDenyInterfaces.add(UsbConstants.USB_CLASS_CDC_DATA);
sDenyInterfaces.add(UsbConstants.USB_CLASS_CSCID);
sDenyInterfaces.add(UsbConstants.USB_CLASS_CONTENT_SEC);
sDenyInterfaces.add(UsbConstants.USB_CLASS_VIDEO);
sDenyInterfaces.add(UsbConstants.USB_CLASS_WIRELESS_CONTROLLER);
39.2.10 MTP 服务绑定
MTP/PTP 功能激活时,Handler 绑定 MTP 服务:
// UsbHandler常量
protected static final String MTP_PACKAGE_NAME = \”com.android.mtp\”;
protected static final String MTP_SERVICE_CLASS_NAME = \”com.android.mtp.MtpService\”;
ServiceConnection 在 MTP 会话整个生命周期保持绑定;切换离开 MTP/PTP 时解除绑定。该绑定除了启动服务外还有关键作用:阻止 ActivityManager 冻结 MTP 进程。如果没有绑定,系统可能为回收资源冻结 MTP 服务进程,打断正在进行的 USB 传输。

39.2.11 MIDI 功能探测
MIDI gadget 功能启用后,UsbDeviceManager 需要探测合成 MIDI 设备对应的 ALSA 卡号与设备号,有两种实现方式。
现代方案(基于 sysfs 解析):
// 遍历UDC控制器下sysfs目录
File soundDir = new File(\”/sys/class/udc/\” + controllerName + \”/gadget/sound\”);
File[] cardDirs = FileUtils.listFilesOrEmpty(soundDir,
(dir, file) -> file.startsWith(\”card\”));
File[] midis = FileUtils.listFilesOrEmpty(cardDirs[0],
(dir, file) -> file.startsWith(\”midi\”));
// 从\”midiC<card>D<device>\”解析卡号设备号
Pattern pattern = Pattern.compile(\”midiC(\\\\d+)D(\\\\d+)\”);
Matcher matcher = pattern.matcher(midis[0].getName());
if (matcher.matches()) {
mMidiCard = Integer.parseInt(matcher.group(1));
mMidiDevice = Integer.parseInt(matcher.group(2));
}
传统方案(读取 ALSA 文件):
// 读取旧版sysfs路径
Scanner scanner = new Scanner(new File(MIDI_ALSA_PATH));
mMidiCard = scanner.nextInt();
mMidiDevice = scanner.nextInt();
探测得到的卡号、设备号传给 UsbAlsaManager,向 Android MIDI 服务注册外设 MIDI 设备。
39.2.12 USB 状态广播
Handler 向所有接收者广播 USB 状态变更:
protected void updateUsbStateBroadcastIfNeeded(long functions) {
Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
| Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(UsbManager.USB_CONNECTED, mConnected);
intent.putExtra(UsbManager.USB_HOST_CONNECTED, mHostConnected);
intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
intent.putExtra(UsbManager.USB_DATA_UNLOCKED,
isUsbTransferAllowed() && isUsbDataTransferActive(mCurrentFunctions));
// 添加激活功能标记
long remainingFunctions = functions;
while (remainingFunctions != 0) {
intent.putExtra(UsbManager.usbFunctionsToString(
Long.highestOneBit(remainingFunctions)), true);
remainingFunctions -= Long.highestOneBit(remainingFunctions);
}
// 仅状态真正变化才广播
if (!isUsbStateChanged(intent)) return;
sendStickyBroadcast(intent);
}
ACTION_USB_STATE是粘性广播:晚注册的接收者会立刻收到上一次广播状态。Intent 携带各个激活功能的布尔值,接收方可以单独检查某一个功能状态。
39.2.13 用户限制执行
企业管控设备可通过UserManager.DISALLOW_USB_FILE_TRANSFER限制 USB 文件传输:
protected boolean isUsbTransferAllowed() {
UserManager userManager = (UserManager) mContext.getSystemService(
Context.USER_SERVICE);
return !userManager.hasUserRestriction(
UserManager.DISALLOW_USB_FILE_TRANSFER);
}
该限制生效时:
- MTP、PTP 功能被屏蔽
- USB 通知显示 “仅充电”
- 应用无法切换至数据传输功能
39.2.14 AOA 配件握手跟踪
Handler 记录 AOA 握手过程详细时序信息,用于调试与统计:
private long mAccessoryConnectionStartTime = 0L; // 收到GET_PROTOCOL时刻
private int mSendStringCount = 0; // SEND_STRING uevent计数
private boolean mStartAccessory = false; // 是否收到START
// 广播握手详情用于调试
private void broadcastUsbAccessoryHandshake() {
Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_HANDSHAKE)
.putExtra(UsbManager.EXTRA_ACCESSORY_UEVENT_TIME,
mAccessoryConnectionStartTime)
.putExtra(UsbManager.EXTRA_ACCESSORY_STRING_COUNT,
mSendStringCount)
.putExtra(UsbManager.EXTRA_ACCESSORY_START,
mStartAccessory)
.putExtra(UsbManager.EXTRA_ACCESSORY_HANDSHAKE_END,
SystemClock.elapsedRealtime());
sendStickyBroadcast(intent);
}
39.2.15 RNDIS 网络共享集成
RNDIS(USB 网络共享)激活时:
// 首字节设0x02,表示本地管理地址
address[0] = 0x02;
String serial = SystemProperties.get(\”ro.serialno\”, \”1234567890ABCDEF\”);
// USB序列号异或填充剩余5字节
for (int i = 0; i < serialLength; i++) {
address[i % (ETH_ALEN – 1) + 1] ^= (int) serial.charAt(i);
}
网硕互联帮助中心



评论前必须登录!
注册