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