Android12 U盘插拔链路源码全解析(八)实战调试与案例分析

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


一、引言

前面七篇文章,我们沿着"从硬件到应用"的方向,逐层拆解了整条 U 盘插拔链路。然而在实际工作中,你很少需要关注整条链路------你需要的是 当一个具体环节出问题时,能快速定位到根因

本文是系列收官之作,聚焦实战:从调试工具链到典型案例分析,帮助你在面对 "U 盘插入没反应" 这类问题时,能像剥洋葱一样一层层定位。


二、调试工具链

2.1 全线工具全景

复制代码
┌─────────────────────────────────────────────────────────────┐
│ 调试层          工具                    观察什么              │
├─────────────────────────────────────────────────────────────┤
│ 硬件层         示波器 / USB 分析仪      VBUS 电平、枚举波形   │
│ ─────────────────────────────────────────────────────────── │
│ 内核层         dmesg / sysfs            USB 枚举日志、设备树  │
│ ─────────────────────────────────────────────────────────── │
│ Native 层      logcat -b events         uevent 日志          │
│                /dev/socket/vold         vold 通信            │
│ ─────────────────────────────────────────────────────────── │
│ Framework 层   logcat -s                服务回调日志          │
│                dumpsys usb/storage      快照服务状态          │
│ ─────────────────────────────────────────────────────────── │
│ 应用层         logcat -s MediaProvider  MediaScanner 日志    │
│                Settings → 存储          UI 展示确认          │
└─────────────────────────────────────────────────────────────┘

2.2 dmesg ------ 内核层诊断第一入口

bash 复制代码
# 插入 U 盘后立即抓取内核日志
adb shell dmesg | tail -50

# 实时监控内核日志(持续输出)
adb shell dmesg -w

# 只过滤 USB 相关日志
adb shell dmesg | grep -iE 'usb|scsi|sd[a-z]|xhci|dwc3'

正常插入 U 盘的 dmesg 输出示例(USB 3.0 U 盘):

复制代码
[  234.123456] usb 2-1: new SuperSpeed Gen 1 USB device number 3 using xhci-hcd
[  234.145678] usb 2-1: New USB device found, idVendor=0781, idProduct=5591, bcdDevice= 1.00
[  234.145690] usb 2-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  234.145698] usb 2-1: Product: Ultra USB 3.0
[  234.145705] usb 2-1: Manufacturer: SanDisk
[  234.145712] usb 2-1: SerialNumber: 4C530001260121106363
[  234.160234] usb-storage 2-1:1.0: USB Mass Storage device detected
[  234.160456] scsi host0: usb-storage 2-1:1.0
[  235.180123] scsi 0:0:0:0: Direct-Access     SanDisk  Ultra USB 3.0    1.00 PQ: 0 ANSI: 6
[  235.181234] sd 0:0:0:0: [sda] 60088320 512-byte logical blocks: (30.8 GB/28.6 GiB)
[  235.181567] sd 0:0:0:0: [sda] Write Protect is off
[  235.181578] sd 0:0:0:0: [sda] Mode Sense: 43 00 00 00
[  235.182345]  sda: sda1
[  235.184567] sd 0:0:0:0: [sda] Attached SCSI removable disk

关键信息解读:

日志行 含义 对应阶段
new SuperSpeed Gen 1 USB device USB 3.0 设备被检测到 Hub 端口检测
idVendor=0781, idProduct=5591 识别为 SanDisk 设备 枚举完成
usb-storage ...: USB Mass Storage device detected usb-storage 驱动绑定成功 驱动匹配
scsi 0:0:0:0: Direct-Access SCSI 设备注册成功 SCSI 层
sd 0:0:0:0: [sda] 60088320 512-byte... 块设备创建,30.8GB 块设备层
sda: sda1 分区 sda1 被识别 分区表解析

2.3 logcat ------ Framework 层诊断

bash 复制代码
# 观察 vold 日志
adb logcat -s vold

# 观察 UsbHostManager 日志
adb logcat -s UsbHostManager

# 观察 StorageManagerService 日志
adb logcat -s StorageManagerService

# 观察 MediaScanner 日志
adb logcat -s MediaScanner

# 一键抓取全线日志
adb logcat -s vold UsbHostManager StorageManagerService MediaScanner SystemUI | tee usb_debug.log

正常插入 U 盘的 logcat 输出示例:

复制代码
--------- beginning of main
D/UsbHostManager: usbDeviceAttached: /dev/bus/usb/001/002
D/UsbHostManager: device: SanDisk Ultra USB 3.0, vid=0x0781, pid=0x5591
I/UsbHostManager: Added device /dev/bus/usb/001/002 (SanDisk Ultra USB 3.0)

--------- vold ---------
D/vold: handleBlockEvent(): devpath=/devices/.../block/sda, devtype=disk
D/vold: handleDiskAdded(): /dev/block/vold/sda
D/vold: readPartitions(): /dev/block/vold/sda, major=8, minor=0
D/vold: sda1: partition found, type=0x0B (FAT32)
D/vold: PublicVolume created: public:8,1

--------- StorageManagerService ---------
D/StorageManagerService: onDiskCreated: disk:8,0 flags=[SD]
D/StorageManagerService: onVolumeCreated: public:8,1 type=PUBLIC
D/StorageManagerService: onVolumeStateChanged: public:8,1 UNMOUNTED -> CHECKING
D/StorageManagerService: onVolumeStateChanged: public:8,1 CHECKING -> MOUNTED
I/StorageManagerService: Volume public:8,1 mounted at /mnt/media_rw/XXXX

--------- SystemUI ---------
D/StorageNotification: onMediaMounted: /mnt/media_rw/XXXX
D/StorageNotification: Showing notification for public:8,1

--------- MediaProvider ---------
D/MediaScannerReceiver: action: MEDIA_MOUNTED, uri: file:///mnt/media_rw/XXXX
I/MediaScannerService: Starting scan of /mnt/media_rw/XXXX
I/MediaScanner: Scanned 42 files, 3 directories in 1.2s
D/MediaScannerService: Scan complete, stopping service.

2.4 dumpsys ------ 快照当前状态

bash 复制代码
# 查看 USB 设备状态
adb shell dumpsys usb

# 查看存储卷状态
adb shell dumpsys diskstats

# 查看所有存储信息
adb shell dumpsys mount

# 查看当前挂载点
adb shell dumpsys storaged --list

dumpsys usb 输出示例:

复制代码
USB Manager State:
  USB Device State:
    Current Functions: mtp,adb
    Default Functions: mtp
  USB Host State:
    Connected Devices:
      /dev/bus/usb/001/003:
        SanDisk Ultra USB 3.0
        Class: 0
        Subclass: 0
        Protocol: 0
        Vendor ID: 0781
        Product ID: 5591
        Has 1 interfaces:
          Interface 0:
            Class: 8 (Mass Storage)
            Subclass: 6 (SCSI)
            Protocol: 80 (Bulk-Only)
            Endpoints:
              Endpoint 0: Address=0x81, Attributes=0x02 (Bulk/IN)
              Endpoint 1: Address=0x02, Attributes=0x02 (Bulk/OUT)

2.5 sysfs ------ 内核态状态探针

bash 复制代码
# 查看当前连接的 USB 设备
adb shell ls /sys/bus/usb/devices/

# 查看特定设备的信息
adb shell cat /sys/bus/usb/devices/2-1/idVendor
# → 0781

adb shell cat /sys/bus/usb/devices/2-1/idProduct
# → 5591

adb shell cat /sys/bus/usb/devices/2-1/product
# → Ultra USB 3.0

# 查看设备速度
adb shell cat /sys/bus/usb/devices/2-1/speed
# → 5000 (SuperSpeed / USB 3.0)
# → 480  (High Speed / USB 2.0)

# 查看块设备大小
adb shell cat /sys/block/sda/size
# → 60088320 (扇区数 × 512 = 字节数)

三、手动触发 uevent 与挂载

3.1 手动模拟 uevent

bash 复制代码
# 模拟块设备插入
adb shell
echo "add" > /sys/block/sda/uevent

# 模拟分区插入
echo "add" > /sys/block/sda/sda1/uevent

# 模拟拔出
echo "remove" > /sys/block/sda/uevent

3.2 vold 命令行调试

bash 复制代码
# 通过 vdc(Volume Daemon Command)与 vold 交互
adb shell vdc volume list

# 列出所有磁盘
adb shell vdc disk list

# 挂载指定卷
adb shell vdc volume mount public:8,1

# 卸载
adb shell vdc volume unmount public:8,1

四、典型案例分析

案例 1:U 盘插入后通知栏无反应

现象: 插入 U 盘,指示灯亮,但通知栏没有任何提示。

排查过程:

复制代码
步骤 1:确认硬件层正常
┌─────────────────────────────────────────────────────────────┐
│ $ adb shell dmesg | grep -iE 'usb|sd[a-z]'                 │
│                                                             │
│ [良好] 看到 "New USB device found" → 硬件层正常               │
│ [不良] 看不到 → 检查供电/接触/USB模式(可能处于 Device 模式)   │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
步骤 2:确认块设备创建
┌─────────────────────────────────────────────────────────────┐
│ $ adb shell ls /dev/block/sd*                               │
│                                                             │
│ [良好] 看到 sda, sda1 → 块设备创建正常                         │
│ [不良] 只有 sda 没有 sda1 → 可能是无分区的整盘 FAT(exFAT),   │
│         或分区表异常。用 fdisk -l /dev/block/sda 检查          │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
步骤 3:确认 vold 是否处理
┌─────────────────────────────────────────────────────────────┐
│ $ adb logcat -s vold                                        │
│                                                             │
│ [良好] 看到 "handleDiskAdded" + "handlePartitionAdded"        │
│ [不良] 看到 "handleDiskAdded" 但没有 "handlePartitionAdded"    │
│        → 分区表解析失败,可能是 exFAT/NTFS 格式未被识别         │
│ [不良] 完全没有 vold 日志 → uevent 丢失或过滤掉了             │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
步骤 4:确认 StorageManagerService 状态
┌─────────────────────────────────────────────────────────────┐
│ $ adb shell dumpsys mount                                    │
│                                                             │
│ [良好] 看到 Volume public:8,1 状态为 MOUNTED                  │
│ [不良] 状态为 UNMOUNTABLE → 文件系统不支持(如 exFAT/NTFS)     │
│        → AOSP 默认不支持 exFAT,需 OEM 自行集成驱动            │
│ [不良] 状态停留 CHECKING → fsck 卡住了                       │
└─────────────────────────────────────────────────────────────┘

常见根因与修复:

根因 检测方法 修复
U 盘文件系统是 exFAT dmesg 中看到 "unknown filesystem type 'exfat'" 集成 exfatprogs / 内核 exfat 驱动
U 盘文件系统是 NTFS dmesg 中看到 "unknown filesystem type 'ntfs'" 集成 ntfs-3g 或内核 NTFS 驱动
分区表为非标准格式 vold 日志显示 readPartitions() 返回错误 用 fdisk 重建标准 MBR/GPT
USB 模式处于 Device dumpsys usb 显示 Current Functions 包含 mtp/ptp 切换或配置 OTG 自动切换
SELinux 权限不足 dmesg 中看到 "avc: denied" 修改 sepolicy
vold 未启动 `ps -A grep vold` 无结果

案例 2:U 盘插入后卡在"正在检查"(CHECKING)

现象: 通知栏显示 "正在检查 U 盘",长时间不变化,最终可能显示 "U 盘已损坏"。

排查过程:

bash 复制代码
# 1. 确认 vold 状态
adb logcat -s vold | grep -i check
# [错误] "fsck timed out" 或 "fsck failed"

# 2. 手动检查文件系统
adb shell fsck_msdos /dev/block/vold/public:8,1

# 3. 如果 fsck 失败,可能是文件系统损坏
# → Windows 下用 chkdsk 修复,或直接格式化

# 4. 如果 fsck 成功但超时,增大超时阈值
# frameworks/native/cmds/vold/fs/Vfat.cpp
# static const int kFsckTimeout = 10;  // 从 5 秒调整到 10 秒

vold fsck 超时源码:

cpp 复制代码
// system/vold/fs/Vfat.cpp
static const int kFsckTimeout = 5;  // ★ 默认 5 秒超时

int Check(const std::string& source, const std::string& target) {
    // ...
    // 运行 fsck_msdos
    int rc = ForkExecvpTimeout(
        argv, nullptr, sFsckUntrustedContext, kFsckTimeout);
    if (rc != 0) {
        LOG(ERROR) << "fsck failed with rc=" << rc;
        return -1;
    }
    // ...
}

经验: 大容量 U 盘(≥64GB)的 FAT32 fsck 可能超过 5 秒。如果量产软件遇到此类问题,建议将 kFsckTimeout 调整为 15-20 秒。

案例 3:U 盘反复断开重连

现象: U 盘插入后,通知栏频繁弹出 "U 盘已移除" → "正在检查 U 盘" → "U 盘已移除",循环不断。

排查过程:

bash 复制代码
# 1. 观察 dmesg------是否有反复的 disconnect/connect
adb shell dmesg -w | grep -iE 'disconnect|reset|enumerate'

# 典型日志:
# usb 2-1: reset SuperSpeed Gen 1 USB device
# usb 2-1: USB disconnect, device number 3
# usb 2-1: new SuperSpeed Gen 1 USB device number 4
# ↑ 明显异常

# 2. 检查供电
adb shell cat /sys/bus/usb/devices/2-1/power/runtime_status
# → active / suspended

# 3. 检查是否有硬件层错误
adb shell dmesg | grep -i 'error\|fail\|-110\|-71'

常见根因:

根因 症状 修复
供电不足 设备枚举成功但读写失败,反复重置 使用带外部供电的 Hub;检查 Type-C 接口供电能力
信号完整性差 高速模式不稳定,降级到全速 缩短线缆;检查 PCB layout
U 盘固件 bug 特定命令后设备无响应,触发超时重置 更换 U 盘品牌 / 更新固件
DWC3 驱动兼容性 特定 SoC 与特定 U 盘主控不兼容
相关推荐
我命由我123451 小时前
Android 开发问题:View 的 getWidth、getHeight 方法返回的值都为 0
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
JohnnyDeng9411 小时前
【Android】Hilt 依赖注入:原理与最佳实践
android·kotlin·mvvm·hilt
星间都市山脉14 小时前
Android STS(Security Test Suite)完整介绍与测试流程
android·java·linux·windows·ubuntu·android studio·androidx
Yeyu15 小时前
你真的了解AIDL吗? 附:AIDL 与 Binder 交互全解析
android
dualven_in_csdn17 小时前
一键起飞调用示例
android·java·javascript
故渊at17 小时前
第十板块:Android 系统稳定性与调试 | 第二十五篇:Watchdog 与 ANR 的系统级监控
android·watchdog·系统稳定性·anr·超时监控
故渊at18 小时前
第十板块:Android 系统稳定性与调试 | 第二十六篇:Systrace 与 Perfetto 的系统级性能分析
android·perfetto·性能分析·systrace·系统稳定性
吕工-老船长199818 小时前
20260610----S905Y5(Android14)-----连接网络自动更新时间,时间设置为24小时
android