AOSP 12 U盘插拔链路源码全解析(三):Native层 —— vold与NetlinkManager

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


一、引言

上一篇文章我们分析了 Linux 内核如何完成 USB 枚举、绑定 usb-storage 驱动、创建 /dev/sda 节点,最后通过 netlink 发送 uevent。

本篇聚焦 vold(Volume Daemon)------用户态第一个感知 U 盘插入的系统进程。它的任务链是:

复制代码
接收 uevent → 解析设备信息 → 创建 Disk 对象
  → 读取分区表 → 创建 PublicVolume 对象
    → 通知 Java 层 → 响应挂载请求 → 执行 mount(2)

vold 是整个存储子系统的 Native 中枢,稳定性和健壮性直接影响用户是否能正常使用 U 盘。


二、vold 架构全景

2.1 进程模型

vold 是一个 单进程多模块 的 C++ 守护进程,由 init 启动:

init 复制代码
# system/vold/vold.rc
service vold /system/bin/vold \
        --blkid_context=u:r:blkid:s0 --blkid_untrusted_context=u:r:blkid_untrusted:s0 \
        --blkid_trusted_context=u:r:blkid:s0 \
        --fsck_context=u:r:fsck:s0 --fsck_untrusted_context=u:r:fsck_untrusted:s0 \
        --fsck_trusted_context=u:r:fsck:s0
    class core
    socket vold stream 0660 root mount
    socket cryptd stream 0660 root mount
    socket vold_unsolicited stream 0660 root mount
    ioprio be 2
    writepid /dev/cpuset/foreground/tasks

2.2 五大核心模块

复制代码
┌─────────────────────────────────────────────────────────────┐
│                      vold (Volume Daemon)                    │
│                                                             │
│  ┌─────────────────┐    ┌──────────────────────────────┐    │
│  │  NetlinkManager  │    │       VolumeManager          │    │
│  │                  │    │                              │    │
│  │ - 创建 netlink   │    │ - handleBlockEvent()         │    │
│  │   socket         │    │ - mountVolume()              │    │
│  │ - 接收 uevent    │───►│ - unmountVolume()            │    │
│  │ - 分发给 Handler  │    │ - formatVolume()             │    │
│  └─────────────────┘    │ - 管理 Disk/Volume 集合       │    │
│                          └──────────────┬───────────────┘    │
│                                         │                    │
│  ┌──────────────────────┐  ┌───────────┴───────────────┐    │
│  │   CommandListener    │  │    Model Objects           │    │
│  │                      │  │                            │    │
│  │ - 监听 /dev/socket/  │  │  Disk                      │    │
│  │   vold  socket       │  │  ├── PublicVolume          │    │
│  │ - 处理来自 Java 层的 │  │  ├── PrivateVolume         │    │
│  │   Binder 命令         │  │  └── EmulatedVolume        │    │
│  └──────────────────────┘  └────────────────────────────┘    │
│                                                             │
│  ┌──────────────────────────────────────────────────────┐   │
│  │                   Utils Layer                          │   │
│  │  - blkid / fsck / mkfs / mount / fstrim              │   │
│  │  - SELinux context 切换                                │   │
│  └──────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘
模块 功能
NetlinkManager 监听内核 netlink socket,将 uevent 分发给 NetlinkHandler
NetlinkHandler 解析 uevent 文本,按 SUBSYSTEM 路由到 VolumeManager
VolumeManager 创建和管理 Disk/Volume 对象,响应挂载/卸载等操作
CommandListener 通过 socket 监听来自 Java 层(StorageManagerService)的命令
Model (Disk/Volume) 抽象物理磁盘和逻辑卷,封装分区表解析、文件系统检测等

三、vold 启动全流程

3.1 main() 入口

源码路径system/vold/main.cpp

cpp 复制代码
int main(int argc, char** argv) {
    // 1. 解析命令行参数(blkid/fsck 的 SELinux context)
    // ...

    // 2. 创建 tmpfs(非关键)
    // ...

    // 3. ★ 创建 VolumeManager 单例
    VolumeManager* vm = VolumeManager::Instance();

    // 4. ★ 创建 NetlinkManager 单例
    NetlinkManager* nm = NetlinkManager::Instance();

    // 5. 创建 CommandListener(监听来自 Java 层的 Binder 命令)
    CommandListener* cl = new CommandListener();

    // 6. 初始化并启动各模块
    nm->start();  // ★ 创建 netlink socket 并开始监听

    // 7. 进入事件循环,等待命令
    while (true) {
        // 处理来自 CommandListener 的命令
    }
}

源码路径system/vold/NetlinkManager.cpp

cpp 复制代码
int NetlinkManager::start() {
    struct sockaddr_nl nladdr;
    int sz = 64 * 1024;  // 接收缓冲区 64KB
    int on = 1;

    memset(&nladdr, 0, sizeof(nladdr));
    nladdr.nl_family = AF_NETLINK;
    nladdr.nl_pid = getpid();     // 绑定当前进程 PID
    nladdr.nl_groups = 0xffffffff; // 监听所有 multicast group

    // ★ 创建 netlink socket
    if ((mSock = socket(PF_NETLINK,
                        SOCK_DGRAM | SOCK_CLOEXEC,
                        NETLINK_KOBJECT_UEVENT)) < 0) {
        PLOG(ERROR) << "Unable to create uevent socket";
        return -1;
    }

    // 设置接收缓冲区大小
    if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
        PLOG(ERROR) << "Unable to set uevent socket SO_RCVBUFFORCE";
    }

    // 绑定到本进程
    if (bind(mSock, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0) {
        PLOG(ERROR) << "Unable to bind uevent socket";
        return -1;
    }

    // ★ 创建 NetlinkHandler 并开始监听
    mHandler = new NetlinkHandler(mSock);
    if (mHandler->start()) {
        PLOG(ERROR) << "Unable to start NetlinkHandler";
        return -1;
    }

    return 0;
}

三个关键参数解读:

参数 含义
socket() 首个参数 PF_NETLINK 协议族
第三个参数 NETLINK_KOBJECT_UEVENT netlink 协议类型,专用于内核对象事件
nl_groups 0xffffffff 监听所有 multicast group,不遗漏任何子系统的 uevent

3.3 NetlinkHandler ------ 继承自 NetlinkListener

源码路径system/vold/NetlinkHandler.cpp

cpp 复制代码
// NetlinkListener → NetlinkHandler 的继承链
class NetlinkListener {
    int mSock;
    void onDataAvailable();  // 从 socket 读取原始字节
    virtual void onEvent(NetlinkEvent *evt) = 0;  // 纯虚函数
};

class NetlinkHandler : public NetlinkListener {
    void onEvent(NetlinkEvent *evt) override;  // 实现 uevent 处理
};

四、uevent 接收与解析

4.1 NetlinkListener::onDataAvailable() ------ 接收原始数据

源码路径system/core/libsysutils/src/NetlinkListener.cpp(AOSP 12 移至 system/core

cpp 复制代码
void NetlinkListener::onDataAvailable() {
    char buffer[UEVENT_MSG_LEN + 2];  // 通常 64KB
    int count;

    // 从 netlink socket 读取数据
    count = TEMP_FAILURE_RETRY(
        recv(mSock, buffer, sizeof(buffer), MSG_DONTWAIT));

    if (count < 0) return;

    // ★ 解析 uevent 消息
    // uevent 格式:多段以 \0 结尾的 key=value,最后以空串结束
    NetlinkEvent* evt = new NetlinkEvent();
    if (evt->decode(buffer, count)) {
        // ★ 回调子类 onEvent()
        onEvent(evt);
    }
    delete evt;
}

4.2 NetlinkEvent::decode() ------ 解析 uevent 文本

cpp 复制代码
// system/core/libsysutils/src/NetlinkEvent.cpp
bool NetlinkEvent::decode(char* buffer, int size) {
    char* s = buffer;
    char* end = buffer + size;

    while (s < end) {
        if (*s == '\0') break;  // 空串表示消息结束

        // 解析 key=value
        char* eq = strchr(s, '=');
        if (!eq) break;

        // 提取并存储参数
        mParams.add(String8(s, eq - s), String8(eq + 1));
        s = eq + strlen(eq) + 1;
    }

    // ★ 通过 ACTION 字段判断事件类型
    const char* action = mParams.findCString("ACTION");
    if (!strcmp(action, "add"))       mAction = NlActionAdd;
    else if (!strcmp(action, "remove"))  mAction = NlActionRemove;
    else if (!strcmp(action, "change"))  mAction = NlActionChange;

    // ★ 提取关键路径
    mSubsystem = mParams.findCString("SUBSYSTEM");
    mPath = mParams.findCString("DEVPATH");

    return true;
}

4.3 实际 uevent 消息示例

内核发来的原始消息(64KB buffer 中的文本):

复制代码
add@/devices/platform/soc/a600000.usb/.../host0/target0:0:0/0:0:0:0/block/sda\0
ACTION=add\0
DEVPATH=/devices/.../block/sda\0
SUBSYSTEM=block\0
MAJOR=8\0
MINOR=0\0
DEVNAME=sda\0
DEVTYPE=disk\0
SEQNUM=2847\0
\0

解析后 NetlinkEvent 包含:

  • mAction = NlActionAdd
  • mSubsystem = "block"
  • mParams 映射了所有 key=value

五、NetlinkHandler::onEvent() ------ 路由到 VolumeManager

源码路径system/vold/NetlinkHandler.cpp

cpp 复制代码
void NetlinkHandler::onEvent(NetlinkEvent* evt) {
    VolumeManager* vm = VolumeManager::Instance();
    const char* subsystem = evt->getSubsystem();

    // ★ 只处理 block 子系统的 uevent
    if (!subsystem || strcmp(subsystem, "block"))
        return;  // 忽略其他子系统(net、usb 等)

    // ★ 交给 VolumeManager 处理
    vm->handleBlockEvent(evt);
}

注意 :vold 只关心 SUBSYSTEM=block 的 uevent。USB 设备的感知(SUBSYSTEM=usb)由 UsbHostManager 的 JNI 层单独处理。


六、VolumeManager::handleBlockEvent() ------ 设备生命周期管理

源码路径system/vold/VolumeManager.cpp

cpp 复制代码
void VolumeManager::handleBlockEvent(NetlinkEvent* evt) {
    const char* devpath = evt->findParam("DEVPATH");
    const char* devtype = evt->findParam("DEVTYPE");
    const char* devname = evt->findParam("DEVNAME");
    int major = atoi(evt->findParam("MAJOR"));
    int minor = atoi(evt->findParam("MINOR"));

    switch (evt->getAction()) {

    case NetlinkEvent::NlActionAdd:
        if (!strcmp(devtype, "disk")) {
            // ★ U 盘整盘设备(/dev/sda)
            handleDiskAdded(devpath, devname, major, minor);
        } else if (!strcmp(devtype, "partition")) {
            // ★ U 盘分区设备(/dev/sda1)
            handlePartitionAdded(devpath, devname, major, minor);
        }
        break;

    case NetlinkEvent::NlActionRemove:
        if (!strcmp(devtype, "disk")) {
            handleDiskRemoved(major, minor);
        } else if (!strcmp(devtype, "partition")) {
            handlePartitionRemoved(major, minor);
        }
        break;

    case NetlinkEvent::NlActionChange:
        // 介质变化(如 SD 卡写保护开关)
        handleDiskChanged(major, minor);
        break;
    }
}

6.1 handleDiskAdded()

cpp 复制代码
void VolumeManager::handleDiskAdded(const std::string& devpath,
                                     const std::string& devname,
                                     int major, int minor) {
    // 1. 生成唯一 eventId(原子递增)
    // 2. 创建 Disk 对象
    auto disk = std::shared_ptr<Disk>(
        new Disk(evt, devname, devpath, eventId));

    // 3. ★ 读取分区表
    disk->readPartitions();

    // 4. 加入 mDisks 集合
    mDisks[disk->getId()] = disk;

    // 5. ★ 通知 Java 层:onDiskCreated()
    for (auto& listener : mListeners) {
        listener->onDiskCreated(disk->getId(), disk->getFlags());
    }

    // 6. 为每个分区创建 Volume 并通知
    for (auto& vol : disk->getVolumes()) {
        mVolumes[vol->getId()] = vol;
        for (auto& listener : mListeners) {
            listener->onVolumeCreated(
                vol->getId(), vol->getType(),
                disk->getId(), vol->getPartGuid());
        }
    }
}

七、Disk 与分区表解析

7.1 Disk::readPartitions()

源码路径system/vold/model/Disk.cpp

cpp 复制代码
status_t Disk::readPartitions() {
    // 构建设备路径
    std::string path = StringPrintf("/dev/block/vold/%s", mDevName.c_str());
    // 实际指向 /dev/block/sda

    // ★ 打开设备,读取分区表
    android::base::unique_fd fd(open(path.c_str(), O_RDONLY | O_CLOEXEC));

    // 读取前 4096 字节(足够覆盖 MBR + GPT header)
    uint8_t buffer[4096];
    read(fd, buffer, sizeof(buffer));

    // ★ 判断分区表类型
    if (isGpt(buffer)) {
        return readGptPartitions(fd, buffer);
    } else {
        return readMbrPartitions(fd, buffer);
    }
}

7.2 MBR 分区表解析

cpp 复制代码
status_t Disk::readMbrPartitions(int fd, uint8_t* buffer) {
    // MBR 分区表位于扇区 0 偏移 446(0x1BE)处
    // 每个分区表项 16 字节,共 4 个主分区

    struct MbrPartition {
        uint8_t  bootIndicator;   // 0x80=活动, 0x00=非活动
        uint8_t  startHead;
        uint8_t  startSector;
        uint8_t  startCylinder;
        uint8_t  partitionType;   // ★ 0x0B=FAT32, 0x07=NTFS/exFAT, 0x83=Linux
        uint8_t  endHead;
        uint8_t  endSector;
        uint8_t  endCylinder;
        uint32_t startLba;        // ★ 分区起始 LBA
        uint32_t sizeLba;         // ★ 分区大小(扇区数)
    };

    for (int i = 0; i < 4; i++) {
        MbrPartition* p = (MbrPartition*)(buffer + 446 + i * 16);

        if (p->partitionType == 0) continue;  // 空表项

        // ★ 为每个分区创建一个 PublicVolume
        auto vol = std::shared_ptr<PublicVolume>(
            new Public
相关推荐
AFinalStone3 小时前
Android12 U盘插拔链路源码全解析(一)全景图与调用链路概览
frameworks
AFinalStone3 小时前
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