Android12 U盘插拔链路源码全解析(一)全景图与调用链路概览

系列目录第一篇:全景图与调用链路概览 | 第二篇:内核层---USB驱动与uevent | 第三篇:Native层---vold与NetlinkManager | 第四篇:Framework层(上)---UsbHostManager | 第五篇:Framework层(下)---StorageManagerService | 第六篇:广播分发与SystemUI响应 | 第七篇:应用层---MediaScanner与SAF | 第八篇:实战调试与案例分析


一、为什么写这个系列

在 Android ROM 定制和系统开发中,U盘/OTG 问题是排查频率最高的场景之一:

  • 插入 U 盘没反应,logcat 一片寂静?
  • 能识别设备但无法挂载?
  • 挂载成功,第三方应用却读不到文件?
  • 多分区 U 盘只能识别第一个?

要精准定位这些问题,靠百度出来的零散博客是远远不够的------你必须理解从物理插入到 Toast 弹出的整条调用链

本系列将以 AOSP 12(Android 12) 源码为基础,从 Kernel → Native → Framework → Application 逐层拆解,最终让你具备"看日志就能定位问题"的能力。


二、分层架构总览

Android 系统拿到一个 U 盘,需要经过 四层协作

复制代码
┌──────────────────────────────────────────────────────────┐
│  Application Layer (应用层)                               │
│  ┌──────────┐  ┌──────────────┐  ┌──────────────────┐   │
│  │ Settings │  │ DocumentsUI  │  │ 第三方文件管理器 │   │
│  └────┬─────┘  └──────┬───────┘  └────────┬─────────┘   │
│       │               │                   │              │
│       │   MediaStore / SAF / StorageManager API          │
├───────┼───────────────┼───────────────────┼──────────────┤
│  Framework Layer (Java框架层)                             │
│  ┌────┴────────────────┴───────────────────┴──────────┐  │
│  │          StorageManagerService                      │  │
│  │  ┌──────────────────┐  ┌──────────────────────┐    │  │
│  │  │  UsbHostManager  │  │  MountService(Vold)  │    │  │
│  │  └────────┬─────────┘  └──────────┬───────────┘    │  │
│  └───────────┼───────────────────────┼────────────────┘  │
│              │ JNI                   │ AIDL(Binder)      │
├──────────────┼───────────────────────┼────────────────────┤
│  Native Layer (C++原生层)                                 │
│  ┌───────────┴───────────┐  ┌───────┴──────────────────┐ │
│  │ com_android_server_   │  │  vold (Volume Daemon)    │ │
│  │ UsbHostManager.cpp    │  │  ┌───────────────────┐   │ │
│  │                       │  │  │  NetlinkManager   │   │ │
│  │  monitorUsbHostBus()  │  │  │  VolumeManager    │   │ │
│  └───────────┬───────────┘  │  │  Disk / Volume    │   │ │
│              │              │  └───────────────────┘   │ │
│              │              └───────┬──────────────────┘ │
│              │   sysfs/uevent     │ netlink socket      │
├──────────────┼────────────────────┼──────────────────────┤
│  Kernel Layer (内核层)                                    │
│  ┌───────────┴────────────────────┴──────────────────┐   │
│  │  USB Core  →  USB Storage Driver  →  Block Layer  │   │
│  │                  ↓ uevent (KOBJ_ADD)              │   │
│  └───────────────────────────────────────────────────┘   │
└──────────────────────────────────────────────────────────┘

各层核心组件速查表

层级 核心组件 源码路径(基于 AOSP 12) 职责
Kernel USB Core / usb-storage drivers/usb/core/hub.c 硬件枚举、驱动绑定、uevent 生成
Native vold + NetlinkManager system/vold/ 监听 uevent、分区解析、文件系统挂载
Native UsbHostManager JNI frameworks/base/services/.../jni/ USB 设备信息采集、JNI 回调
Framework UsbHostManager frameworks/.../usb/UsbHostManager.java UsbDevice 构建、USB_DEVICE_ATTACHED 广播
Framework UsbService frameworks/.../usb/UsbService.java USB 服务生命周期管理
Framework StorageManagerService frameworks/.../StorageManagerService.java 存储卷管理、与 vold Binder 通信
Application MediaProvider packages/providers/MediaProvider/ 媒体文件扫描、MediaStore 写入
Application ExternalStorageProvider packages/providers/.../ExternalStorageProvider/ SAF 框架暴露 U 盘文件

三、完整时序图:从插入到可用

下面用一张 ASCII 时序图 展示整个链路。建议你把它收藏起来,后续每一篇都会频繁引用。

复制代码
  时间 ──────────────────────────────────────────────────────────────►

  物理层     Kernel            vold          UsbHostManager   StorageMgr   App层
  ──────     ──────            ────          ──────────────   ──────────   ────

  U盘插入
    │
    ├──[1]──► VBUS检测
    │         hub_events()
    │         hub_port_connect_change()
    │
    ├──[2]──► USB枚举
    │         (获取设备/配置/接口
    │          描述符, 绑定驱动)
    │
    ├──[3]──► usb-storage驱动绑定
    │         /dev/sda 节点创建
    │
    ├──[4]──► kobject_uevent_env(KOBJ_ADD)
    │         ──netlink──►
    │                      [5] NetlinkHandler::onEvent()
    │                          解析 DEVPATH/SUBSYSTEM
    │
    │                      [6] VolumeManager::handleBlockEvent()
    │                          Disk::create()
    │                          Disk::readPartitions()
    │                            (MBR/GPT解析)
    │
    │                      [7] PublicVolume::create()
    │                          检测文件系统类型
    │
    │                          ──binder──►  [8] onDiskCreated()
    │                                        onVolumeCreated()
    │
    │                                        [9] StorageManagerService
    │                                            mountVolume()
    │                                            ──binder──►
    │                      [10] VolumeManager::mountVolume()
    │                           mount(2) 系统调用
    │                           (挂载到 /mnt/media_rw/XXXX)
    │
    │                          ◄──binder──
    │                                        [11] 发送广播
    │                                            ACTION_MEDIA_MOUNTED
    │
    │              ┌──────────────────────────────────────────┐
    │              │  ★ 与此同时,另一条并行的 USB 感知链路:    │
    │              │                                          │
    │              │  vold 处理 block 事件时                  │
    │              │  UsbHostManager 也同时在工作              │
    │              └──────────┬───────────────────────────────┘
    │                         │
    │                         │ JNI: monitorUsbHostBus()
    │                         │ 读取/sys/class/android_usb/...
    │                         │
    │                         ▼
    │              [12] UsbHostManager.usbDeviceAttached()
    │                   创建 UsbDevice 对象树
    │                   (接口、端点信息)
    │
    │              [13] 发送广播
    │                   ACTION_USB_DEVICE_ATTACHED
    │                                              ──► 应用接收
    │                                                   注册USB设备
    │
    │                                            ──► MediaScanner
    │                                                MediaScannerReceiver
    │                                                扫描挂载点
    │                                                MediaStore写入
    │
    │                                            ──► SystemUI
    │                                                通知栏"U盘已插入"
    │                                                Settings刷新
    │
    ▼
  U盘可用

关键观察 :USB 设备感知(UsbHostManager)和存储挂载(StorageManagerService)是 两条并行的链路。前者告诉你"插了个什么设备",后者告诉你"这个设备的存储可以用了"。


四、两大并行链路的详细拆解

为了让你建立起清晰的思维模型,我把整条链路拆成 两条主线 来理解:

链路 A:USB 设备感知链(偏"识别")

复制代码
Kernel USB枚举
  → uevent(KOBJ_ADD到android_usb子系统)
    → JNI monitorUsbHostBus() 监听/sys
      → UsbHostManager.usbDeviceAttached()
        → 构建 UsbDevice 对象树
          → 发送 ACTION_USB_DEVICE_ATTACHED 广播
            → App 通过 BroadcastReceiver 接收

核心数据结构

java 复制代码
// UsbDevice:代表一个物理USB设备
public class UsbDevice {
    String mName;              // 设备名称,如 "/dev/bus/usb/001/002"
    int mVendorId;             // 厂商ID,如 0x0781 (SanDisk)
    int mProductId;            // 产品ID
    int mClass;                // 设备类,如 0x08 = Mass Storage
    int mSubclass;
    int mProtocol;
    String mManufacturerName;  // 制造商字符串
    String mProductName;       // 产品名称字符串
    String mSerialNumber;      // 序列号
    Parcelable[] mConfigurations; // UsbConfiguration数组
    UsbInterface[] mInterfaces;   // UsbInterface数组
}

// UsbInterface:设备的一个功能接口
public class UsbInterface {
    int mId;
    int mClass;               // 如 0x08 = Mass Storage
    UsbEndpoint[] mEndpoints; // 通信端点
}

// UsbEndpoint:数据传输端点
public class UsbEndpoint {
    int mAddress;             // 端点地址(含方向)
    int mType;                // CONTROL/BULK/INTERRUPT/ISOCHRONOUS
    int mMaxPacketSize;       // 最大包大小
}

链路 B:存储挂载链(偏"可用")

复制代码
Kernel block设备创建(/dev/sda)
  → uevent(KOBJ_ADD, SUBSYSTEM=block)
    → vold NetlinkHandler 捕获
      → Disk::create() + readPartitions()
        → PublicVolume::create()
          → StorageManagerService.mountVolume()
            → vold mount(2) 到 /mnt/media_rw/XXXX
              → 发送 ACTION_MEDIA_MOUNTED 广播
                → MediaScanner 扫描
                  → SAF 暴露文件系统

核心数据结构

java 复制代码
// DiskInfo:代表一个物理磁盘(在Java层)
public class DiskInfo {
    public String id;          // "disk:179,0"
    public int flags;
    public long size;
    public String label;
    public int volumeCount;
}

// VolumeInfo:代表磁盘上的一个卷/分区
public class VolumeInfo {
    public String id;          // "public:179,1"
    public int type;           // TYPE_PUBLIC / TYPE_PRIVATE / TYPE_EMULATED
    public String diskId;
    public String partGuid;
    public int mountFlags;
    public int state;          // STATE_UNMOUNTED → STATE_MOUNTED
    public String fsType;      // "vfat", "exfat", "ntfs", "ext4"...
    public String path;        // 挂载点: "/mnt/media_rw/XXXX"
}

五、链路中的关键广播汇总

这条链路中,系统会依次发出多个广播。理解它们的顺序和携带的数据,是排查问题的关键。

广播 Action 发送者 触发时机 携带关键Extra 备注
android.hardware.usb.action.USB_DEVICE_ATTACHED UsbHostManager USB设备枚举完成 EXTRA_DEVICE (UsbDevice) FLAG_RECEIVER_FOREGROUND
android.hardware.usb.action.USB_DEVICE_DETACHED UsbHostManager USB设备拔出 EXTRA_DEVICE (UsbDevice) FLAG_RECEIVER_FOREGROUND
android.intent.action.MEDIA_UNMOUNTED StorageManagerService 卷开始卸载 EXTRA_VOLUME_STATE
android.intent.action.MEDIA_CHECKING StorageManagerService 卷正在检查 EXTRA_VOLUME_STATE
android.intent.action.MEDIA_MOUNTED StorageManagerService 卷挂载完成 EXTRA_VOLUME_STATE, path 最重要
android.intent.action.MEDIA_EJECT StorageManagerService 用户操作弹出 EXTRA_VOLUME_STATE
android.intent.action.MEDIA_BAD_REMOVAL StorageManagerService 未安全弹出就拔出 EXTRA_VOLUME_STATE
android.intent.action.MEDIA_SCANNER_STARTED MediaScannerReceiver 开始扫描文件 volume path
android.intent.action.MEDIA_SCANNER_FINISHED MediaScannerReceiver 扫描完成 volume path 之后文件才可在MediaStore查到

实战提示 :调试时在 logcat 中 grep 这些 action 字符串,可以快速判断卡在哪一步。如果 MEDIA_MOUNTED 没出现,问题在存储挂载链;如果出现了但 MEDIA_SCANNER_FINISHED 没出现,问题在媒体扫描。


六、源码阅读准备

在开始深入分析之前,需要准备好以下环境:

6.1 源码下载

bash 复制代码
# 下载 AOSP 12 源码(建议只下载必要分支)
repo init -u https://android.googlesource.com/platform/manifest -b android-12.0.0_r1
repo sync -j8

# 如果只需要本地索引阅读,推荐使用
# Android Code Search: https://cs.android.com
# 或本地镜像: https://android.googlesource.com

6.2 关键源码目录

复制代码
frameworks/base/services/
├── usb/java/com/android/server/usb/
│   ├── UsbService.java              # USB服务入口
│   ├── UsbHostManager.java          # ★ Host模式核心
│   ├── UsbDeviceManager.java        # Device模式(手机当U盘)
│   ├── UsbAlsaManager.java          # USB音频管理
│   └── UsbSettingsManager.java      # USB设置管理
│
├── core/java/com/android/server/
│   └── StorageManagerService.java   # ★ 存储挂载核心
│
system/vold/
├── NetlinkManager.cpp               # ★ uevent监听
├── NetlinkHandler.cpp               # uevent处理
├── VolumeManager.cpp                # ★ 卷管理
├── model/
│   ├── Disk.cpp                     # 磁盘模型
│   ├── PublicVolume.cpp             # ★ 公共卷(U盘)
│   ├── PrivateVolume.cpp            # 私有卷(adoptable storage)
│   └── EmulatedVolume.cpp           # 模拟卷(内部存储)
│
frameworks/native/libs/binder/
└── ...                              # Binder IPC 通信

七、小结

本文作为系列开篇,为你建立了 U盘插拔全链路的知识框架

  1. 四层协作模型:Kernel → Native(vold/JNI) → Framework(UsbHostManager/StorageManagerService) → Application
  2. 两条并行主线:USB 设备识别链 + 存储卷挂载链
  3. 关键广播序列 :从 USB_DEVICE_ATTACHEDMEDIA_MOUNTEDMEDIA_SCANNER_FINISHED
  4. 核心数据结构:UsbDevice / UsbInterface / UsbEndpoint 和 Disk / Volume

理解了这些,你已经可以对 80% 的 U 盘问题做出初步判断:

  • 日志中没有 USB_DEVICE_ATTACHED?→ 硬件/内核层出问题,第二篇见
  • 有 `USB_DEV
相关推荐
AFinalStone2 小时前
Android12 U盘插拔链路源码全解析(二):内核层USB驱动与uevent机制
frameworks
天才少年曾牛1 天前
Android新增服务添加selinux权限
android·java·frameworks
天才少年曾牛19 天前
Android14 新增系统服务后,应用调用出现 “hidden api” 警告的原因与解决方案
android·frameworks
天才少年曾牛5 个月前
【无标题】
android·frameworks
AFinalStone1 年前
Android 16系统源码_窗口动画(一)窗口过渡动画层级图分析
android·动画·frameworks
AFinalStone1 年前
Android 12系统源码_系统启动(三)SystemServer进程
android·frameworks
AFinalStone2 年前
Android 12系统源码_RRO机制(一)Runtime Resource Overlay机制实践
android·frameworks
AFinalStone2 年前
Android 12系统源码_应用加载流程(一)资源加载
android·frameworks
AFinalStone2 年前
Android 12系统源码_屏幕设备(二)DisplayAdapter和DisplayDevice的创建
android·frameworks