深入理解android卷1 第8章:深入理解Vold和Rild

核心主题:存储管理守护进程(Vold)和电话守护进程(Rild)


关键知识点速查 - Vold篇

1. Vold概述

全称:Volume Daemon(卷管理守护进程)

核心职责:

  • 监听内核设备插拔事件(uevent)
  • 管理存储设备(SD卡、USB、OTG)
  • 挂载/卸载文件系统
  • 加密存储管理

架构位置:

应用层(StorageManager)
  ↓ Binder
MountService(Java服务)
  ↓ Socket
Vold(Native守护进程)
  ↓ Netlink
Kernel(uevent)
  ↓
存储设备(SD卡、USB)

2. Vold启动流程

init.rc配置:

service vold /system/bin/vold \
    --blkid_context=u:r:blkid:s0 \
    --blkid_untrusted_context=u:r:blkid_untrusted:s0 \
    --fsck_context=u:r:fsck:s0 \
    --fsck_untrusted_context=u:r:fsck_untrusted:s0
    class core
    ioprio be 2
    socket vold stream 0660 root mount
    socket cryptd stream 0660 root mount

main函数流程:

// system/vold/main.cpp
int main(int argc, char** argv) {
    // 1. 创建VolumeManager单例
    VolumeManager* vm = VolumeManager::Instance();

    // 2. 创建NetlinkManager(监听内核事件)
    NetlinkManager* nm = NetlinkManager::Instance();

    // 3. 启动Netlink监听
    nm->start();

    // 4. 创建CommandListener(监听MountService命令)
    CommandListener* cl = new CommandListener();

    // 5. 启动Socket服务
    if (cl->startListener()) {
        exit(1);
    }

    // 6. 进入事件循环
    while (1) {
        sleep(1000);
    }
}

3. Netlink事件监听

Netlink机制:

  • 内核与用户空间通信的Socket机制
  • 用于传递设备热插拔事件(uevent)

uevent格式:

ACTION=add
DEVPATH=/devices/platform/soc/7864900.sdhci/mmc_host/mmc0/mmc0:0001
SUBSYSTEM=block
DEVNAME=mmcblk0
DEVTYPE=disk
MAJOR=179
MINOR=0

监听流程:

void NetlinkManager::onEvent(NetlinkEvent* evt) {
    const char* subsys = evt->getSubsystem();

    if (!strcmp(subsys, "block")) {
        // 块设备事件(SD卡、USB)
        VolumeManager::Instance()->handleBlockEvent(evt);
    } else if (!strcmp(subsys, "usb")) {
        // USB设备事件
    }
}

4. Volume管理

Volume类型:

class VolumeBase {
    enum Type {
        kPublic = 0,    // 公共存储(SD卡)
        kPrivate = 1,   // 私有存储(adoptable storage)
        kEmulated = 2,  // 模拟存储(内部存储的分区)
        kAsec = 3,      // 加密容器
        kObb = 4,       // OBB文件(游戏数据包)
    };
};

Volume状态机:

unmounted(未挂载)
    ↓ mount()
checking(检查文件系统)
    ↓ fsck
mounted(已挂载)
    ↓ unmount()
ejecting(弹出中)
    ↓
unmounted

挂载流程:

// VolumeManager::handleBlockEvent()
void VolumeManager::handleBlockEvent(NetlinkEvent* evt) {
    // 1. 解析设备路径
    const char* devpath = evt->findParam("DEVPATH");

    // 2. 创建PublicVolume对象
    auto vol = std::make_shared<PublicVolume>(device);
    mDisks[device] = vol;

    // 3. 创建挂载点
    // /mnt/media_rw/xxxx-xxxx

    // 4. 检查文件系统
    // fsck -a /dev/block/vold/public:179,0

    // 5. 挂载
    // mount -t vfat /dev/block/vold/xxx /mnt/media_rw/xxx

    // 6. 通知MountService
    sendBroadcast(VolumeStateChanged);
}

5. Vold命令协议

Socket通信:

MountService                     Vold
     │                            │
     ├─ "volume mount xxx" ───────>│
     │                            │ 挂载处理
     │<─ "200 volume mounted" ────┤
     │                            │
     ├─ "volume unmount xxx" ─────>│
     │                            │ 卸载处理
     │<─ "200 volume unmounted" ──┤

命令格式:

// 客户端发送
"volume mount <volume_id>"

// 服务端响应
"200 volume <volume_id> state mounted"

// 错误响应
"400 Command failed"

6. 存储加密(FDE/FBE)

FDE(Full Disk Encryption):

  • 全盘加密(Android 4.4-6.0)
  • 启动时需要输入密码解密
  • 解密后整个/data分区可访问

FBE(File-Based Encryption):

  • 基于文件的加密(Android 7.0+)
  • 用户数据分为DE(Device Encrypted)和CE(Credential Encrypted)
  • DE:设备启动后即可访问(闹钟、电话)
  • CE:用户解锁后才能访问(应用数据)

加密流程:

// cryptfs.c
int cryptfs_enable(int type) {
    // 1. 生成加密密钥
    create_crypto_blk_dev();

    // 2. 格式化加密分区
    format_encrypted_partition();

    // 3. 挂载加密分区
    mount_encrypted_partition();

    // 4. 保存密钥(加密后存储)
    put_crypt_ftr_and_key();
}

关键知识点速查 - Rild篇

1. Rild概述

全称:Radio Interface Layer Daemon(无线接口层守护进程)

核心职责:

  • 管理Modem通信(电话、短信、数据网络)
  • 与RIL库交互(厂商实现)
  • 向上层提供电话服务接口

架构位置:

应用层(TelephonyManager)
  ↓
Phone进程(Java)
  ↓
RILJ(Java Binder客户端)
  ↓ Socket
Rild(Native守护进程)
  ↓
libril-xxx.so(厂商RIL库)
  ↓ AT命令/QMI协议
Modem(基带处理器)

2. RIL架构

三层结构:

┌────────────────────────────┐
│   Java层(RILJ)            │
│   frameworks/opt/telephony  │
└──────────┬─────────────────┘
           ↓ Socket(rild)
┌────────────────────────────┐
│   Rild(守护进程)          │
│   hardware/ril/rild         │
└──────────┬─────────────────┘
           ↓ 函数调用
┌────────────────────────────┐
│   RIL库(厂商实现)         │
│   libril-xxx.so            │
└──────────┬─────────────────┘
           ↓ AT命令
┌────────────────────────────┐
│   Modem(基带)             │
└────────────────────────────┘

3. Rild启动流程

init.rc配置:

service ril-daemon /vendor/bin/hw/rild
    class main
    user radio
    group radio cache inet misc audio log readproc wakelock
    socket rild stream 660 root radio
    socket rild-debug stream 660 radio system

main函数:

// hardware/ril/rild/rild.c
int main(int argc, char** argv) {
    // 1. 加载RIL库
    rilLibPath = "/system/lib/libril-xxx.so";
    dlHandle = dlopen(rilLibPath, RTLD_NOW);

    // 2. 获取RIL_Init函数
    rilInit = (const RIL_RadioFunctions*)dlsym(dlHandle, "RIL_Init");

    // 3. 初始化RIL库
    funcs = rilInit(&s_rilEnv, argc, rilArgv);

    // 4. 创建Socket监听
    s_fdListen = socket_local_server("rild", ...);

    // 5. 等待RILJ连接
    while (1) {
        s_fdCommand = accept(s_fdListen, ...);

        // 6. 创建事件循环
        ril_event_loop();
    }
}

4. RIL请求处理

请求格式(Parcel):

┌────────────────┐
│ Request ID     │ 4字节
├────────────────┤
│ Token          │ 4字节(用于匹配响应)
├────────────────┤
│ Data Length    │ 4字节
├────────────────┤
│ Data           │ 变长
└────────────────┘

处理流程:

// 1. RILJ发送请求
RIL_REQUEST_DIAL: {
    dialAddress: "10086",
    clir: 0
}

// 2. Rild接收并分发
processCommandBuffer() {
    request = parcel.readInt32(); // RIL_REQUEST_DIAL
    token = parcel.readInt32();

    // 调用RIL库函数
    funcs->onRequest(request, data, datalen, token);
}

// 3. RIL库发送AT命令
ATD10086;

// 4. Modem响应
OK

// 5. RIL库回调
RIL_onRequestComplete(token, RIL_E_SUCCESS, NULL, 0);

// 6. Rild返回响应给RILJ

5. 主动上报(Unsolicited Response)

场景:

  • 来电:RING
  • 短信:+CMT
  • 信号强度变化:+CSQ
  • 网络注册状态:+CREG

处理流程:

// RIL库监听Modem主动上报
void onUnsolicited(const char* s) {
    if (strStartsWith(s, "RING")) {
        // 来电
        RIL_onUnsolicitedResponse(
            RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
            NULL, 0
        );
    } else if (strStartsWith(s, "+CMT")) {
        // 短信
        RIL_onUnsolicitedResponse(
            RIL_UNSOL_RESPONSE_NEW_SMS,
            sms, sizeof(sms)
        );
    }
}

// Rild转发给RILJ
sendResponse(p); // 发送到Socket

// RILJ处理
processUnsolicited(p) {
    switch (response) {
        case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
            mCallStateRegistrants.notifyRegistrants();
            break;
    }
}

6. AT命令示例

拨号:

AT: ATD10086;
Modem: OK

挂断:

AT: ATH
Modem: OK

发短信:

AT: AT+CMGS="13800138000"
Modem: >
AT: Hello World<Ctrl+Z>
Modem: +CMGS: 123
       OK

查询信号强度:

AT: AT+CSQ
Modem: +CSQ: 25,99
       OK

7. RIL命令分类

类别命令示例说明
通话RIL_REQUEST_DIAL拨号
RIL_REQUEST_HANGUP挂断
RIL_REQUEST_ANSWER接听
短信RIL_REQUEST_SEND_SMS发送短信
RIL_REQUEST_SMS_ACKNOWLEDGE短信应答
网络RIL_REQUEST_SIGNAL_STRENGTH信号强度
RIL_REQUEST_OPERATOR运营商信息
SIM卡RIL_REQUEST_GET_IMSI获取IMSI
RIL_REQUEST_SIM_IOSIM卡IO操作
数据RIL_REQUEST_SETUP_DATA_CALL建立数据连接
RIL_REQUEST_DEACTIVATE_DATA_CALL断开数据连接

架构图

Vold架构

┌─────────────────────────────────────┐
│   MountService(Java)               │
│   frameworks/base/.../MountService   │
└──────────────┬──────────────────────┘
               ↓ Socket(/dev/socket/vold)
┌─────────────────────────────────────┐
│   Vold(Native守护进程)             │
│  ┌────────────┐  ┌────────────────┐ │
│  │CommandList-│  │ NetlinkManager │ │
│  │  ener      │  │                │ │
│  │(Socket)  │  │  (Netlink)   │ │
│  └────────────┘  └────────┬───────┘ │
│         ↓                  ↓         │
│  ┌──────────────────────────────┐   │
│  │     VolumeManager            │   │
│  │  - handleBlockEvent()        │   │
│  │  - mount/unmount             │   │
│  └──────────────┬───────────────┘   │
└─────────────────┼───────────────────┘
                  ↓
┌─────────────────────────────────────┐
│   Kernel(uevent)                   │
│   /sys/devices/.../uevent            │
└─────────────────────────────────────┘

Rild架构

┌─────────────────────────────────────┐
│   RILJ(Java层)                     │
│   frameworks/opt/telephony/RIL.java  │
└──────────────┬──────────────────────┘
               ↓ Socket(rild)
┌─────────────────────────────────────┐
│   Rild(守护进程)                   │
│  - processCommandBuffer()            │
│  - sendResponse()                    │
└──────────────┬──────────────────────┘
               ↓ 函数调用
┌─────────────────────────────────────┐
│   RIL库(厂商实现)                  │
│   libril-xxx.so                      │
│  - onRequest()                       │
│  - onUnsolicited()                   │
│  - RIL_onRequestComplete()           │
└──────────────┬──────────────────────┘
               ↓ AT命令/QMI协议
┌─────────────────────────────────────┐
│   Modem(基带处理器)                │
└─────────────────────────────────────┘

重要概念

Vold部分

挂载点:

  • /mnt/media_rw/:Vold挂载的原始位置
  • /storage/emulated/0/:模拟存储(内部存储)
  • /storage/xxxx-xxxx/:外部存储(SD卡、USB)

文件系统支持:

  • vfat(FAT32):兼容性最好
  • exfat:支持大文件
  • ext4:Linux文件系统
  • f2fs:Flash友好文件系统

Rild部分

Modem类型:

  • GSM/WCDMA:使用AT命令
  • CDMA:使用QMI协议
  • LTE:使用RRC协议

RIL库:

  • reference-ril:参考实现(AT命令)
  • 厂商RIL:高通、MTK、三星等

快速回忆检查点

Vold部分:

  • Vold的核心职责是什么?(存储设备管理)
  • Netlink用于什么?(监听内核uevent事件)
  • SD卡插入后的处理流程?(uevent → Vold → mount → 通知MountService)
  • FDE和FBE的区别?(全盘加密 vs 基于文件加密)

Rild部分:

  • Rild的核心职责是什么?(管理Modem通信)
  • RIL架构的三层是什么?(RILJ → Rild → RIL库)
  • AT命令是什么?(与Modem通信的文本协议)
  • Unsolicited Response的作用?(Modem主动上报事件)

与T87A0项目的关联

Vold相关:

  • T87A0支持TF卡扩展存储
  • 录像文件存储在SD卡
  • 需要监听SD卡挂载/卸载事件

调试命令:

# 查看挂载信息
adb shell mount | grep /storage

# Vold日志
adb logcat -s Vold:V

# 手动挂载SD卡
adb shell sm list-disks
adb shell sm mount <disk_id>

# 查看存储状态
adb shell dumpsys mount

Rild相关:

  • T87A0可能支持4G模块(选配)
  • 用于远程告警(发短信、拨号)

注意事项:

  • SD卡热插拔时停止录像
  • 检查SD卡剩余空间
  • 处理SD卡损坏场景(fsck失败)

关联章节:

  • 无直接关联章节(Vold和Rild较独立)

实践建议:

  1. 分析T87A0的存储管理策略(SD卡优先级)
  2. 跟踪录像文件存储路径
  3. 模拟SD卡拔出场景测试

核心要点:

  • Vold管理存储设备的热插拔和挂载
  • Netlink是内核事件通知机制
  • Rild是应用层与Modem通信的桥梁
  • RIL库封装厂商特定的Modem协议

更多推荐