Android 2.1 Vold 分析

    技术2026-06-20  1

     

    Android VoldVolume Daemon 

    负责大容量存储设备挂载和删除的守护进程。

    服务在init.rc中被开启:

     

    service vold /system/bin/vold socket vold stream 0660 root mount

     

     

    本文主要分为两个部分:

     

    ·Vold 的架构分析

    ·Vold的功能总结

     

    1.Vold的架构分析

     

    Android Vold ,一方面负责接受内核发送的关于外部存储设备加载和删除的信息,然后将信息发送给framework层的MountService;另一方面负责执行MountService发送的命令。

    这些cmdmes的传递主要是通过Socket通信来实现(Socket的通信的具体细节这里不再赘述)。

    下面从代码的角度简要分析这一过程的实现:

    1.1在vold.c中,首先建立和framework层的通信:

    if ((door_sock = android_get_control_socket(VOLD_SOCKET)) < 0) { LOGE("Obtaining file descriptor socket '%s' failed: %s", VOLD_SOCKET, strerror(errno)); exit(1); } if (listen(door_sock, 4) < 0) { LOGE("Unable to listen on fd '%d' for socket '%s': %s", door_sock, VOLD_SOCKET, strerror(errno)); exit(1); } 

    其中,VOLD_SOCKETinit进程中创建,android_get_control_socket()主要是获取VOLD_SOCKET的文件描述符。

    Listern()主要用于监听来自其他framework层的Socket连接请求。

     

    framewok层,MountService开启之后,会创建一个新的线程。在class MountService 的构造方法中:

     

    if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { Thread thread = new Thread(mListener, MountListener.class.getName()); thread.start(); }

     

     

    class MountListener 实现了Runnable接口,在它继承的run()方法中创建了一个无限循环:

    while (true) { listenToSocket(); } 

     

    listenToSocket()方法中:

     

    socket = new LocalSocket(); LocalSocketAddress address = new LocalSocketAddress(VOLD_SOCKET, LocalSocketAddress.Namespace.RESERVED); socket.connect(address); InputStream inputStream = socket.getInputStream(); mOutputStream = socket.getOutputStream(); ···································· while (true) { int count = inputStream.read(buffer); if (count < 0) break; int start = 0; for (int i = 0; i < count; i++) { if (buffer[i] == 0) { String event = new String(buffer, start, i - start); handleEvent(event); start = i + 1; } } }   

    首先,实例化一个本地的LocalSocket 用于与Vold的通信,其次建立与VOLD_SOCKET的连接。然后再建立一个文件输入流,用于保存Vold传来的mesbuff中。最后,在一个无线循环中读取buff的内容,并执行handleEvent()

    handleEvent()中通过if else语句对传来的事件做相应处理

     

    if (event.equals(VOLD_EVT_UMS_ENABLED)) { ................ } else if (event.equals(VOLD_EVT_UMS_DISABLED)) { ................ } else if (event.equals(VOLD_EVT_EXTERNAL_UMS_CONNECTED)) { ............... mService.notifyUmsConnected(path); ..................... } else if (event.equals(VOLD_EVT_UMS_CONNECTED)) { ........................... mService.notifyUmsConnected(path); } else if (event.equals(VOLD_EVT_EXTERNAL_UMS_DISCONNECTED)) { .........................

     

    对于其中一个事件的处理,例如.notifyUmsConnected():

     

    最后,将处理之后需要执行的命令发送给vold

     

    到现在为止,我们就建立了vold MountService之间的通信。

     

    1.2建立与内核的socket通信

    .................... Intent intent = new Intent(Intent.ACTION_UMS_CONNECTED); mContext.sendBroadcast(intent); ....................   

    if ((uevent_sock = socket(PF_NETLINK, SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) { ........ } if (setsockopt(uevent_sock, SOL_SOCKET, SO_RCVBUFFORCE, &uevent_sz, sizeof(uevent_sz)) < 0) { ....... } if (bind(uevent_sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) { ...... } 

    创建一个uevent_sock,建立与内核的通信。setsockopt()函数主要用于设置uevent_sock的选项,bind()用于将内核的socketuevent_sock进行地址的绑定。

     

    1.3挂载现有存储设备

     

    volmgr_bootstrap()函数首先解析配置文件vold.conf

    最后会将需要挂载的设备信息放在一个全局变量的链表中val_root

    static volume_t *vol_root = NULL;

    1.4挂载mmc/sdcard

    volmgr_bootstrap(); simulate_uevent()确定uevent的action是'add','remove'还是'change'; if ((rc = volmgr_readconfig("/system/etc/vold.conf")) < 0) { LOGE("Unable to process config"); return rc; } 

    mmc_bootstrap()

     

    dipatch_uevent():根据uevent->subsystem确定uevent处理的句柄。

     

     

    struct uevent { const char *action; const char *path; const char *subsystem; const char *firmware; int major; int minor; };

     

     

    最终的挂载操作在MountService开启之后实现

    1.5 usb大容量存储的处理ums_bootstrap()

     

    1.6 switch_bootstrap()

     

    1.7主服务(死循环)

     

    struct uevent_dispatch { char *subsystem; int (* dispatch) (struct uevent *); };

     

    while(1) { ········ FD_ZERO(&read_fds);//初始化文件描述集合 FD_SET(door_sock, &read_fds);//将door_sock加入文件描述集 if (door_sock > max) max = door_sock; FD_SET(uevent_sock, &read_fds);//将event_sock加入文件描述集 if (uevent_sock > max) max = uevent_sock; if (fw_sock != -1) { FD_SET(fw_sock, &read_fds);//将fw_sock加入文件描述集 if (fw_sock > max) max = fw_sock; } //当所有的文件描述符都没改变时,阻塞线程 if ((rc = select(max + 1, &read_fds, NULL, NULL, &to)) < 0) { LOGE("select() failed (%s)", strerror(errno)); sleep(1); continue; } if (!rc) { continue; } //检测如果是door_sock,检测与framework的连接,并发送msg if (FD_ISSET(door_sock, &read_fds)) { struct sockaddr addr; socklen_t alen; alen = sizeof(addr); if (fw_sock != -1) { LOGE("Dropping duplicate framework connection"); int tmp = accept(door_sock, &addr, &alen); close(tmp); continue; } if ((fw_sock = accept(door_sock, &addr, &alen)) < 0) { LOGE("Unable to accept framework connection (%s)", strerror(errno)); } LOG_VOL("Accepted connection from framework"); /* for iNand */ volmgr_usb_bootstrap(); if ((rc = volmgr_send_states()) < 0) { LOGE("Unable to send volmgr status to framework (%d)", rc); } } //如果是fw_sock,执行framework传来的命令 if (FD_ISSET(fw_sock, &read_fds)) { if ((rc = process_framework_command(fw_sock)) < 0) { if (rc == -ECONNRESET) { LOGE("Framework disconnected"); close(fw_sock); fw_sock = -1; } else { LOGE("Error processing framework command (%s)", strerror(errno)); } } } //如果是uevent_sock,产生一个uevent事件 if (FD_ISSET(uevent_sock, &read_fds)) { if ((rc = process_uevent_message(uevent_sock)) < 0) { LOGE("Error processing uevent msg (%s)", strerror(errno)); } } } // while  

     

    2.Vold的功能总结

    1)创建连接:     在vold作为一个守护进程,一方面接受驱动的信息,并把信息传给应用层;另一方面接受上层的命令并完成相应操作。     所以这里的连接一共有两条:       ·vold socket: 负责vold与应用层的信息传递;       ·访问udevsocket: 负责vold与底层的信息传递;     这两个连接都是在进程的一开始完成创建的。

     

         2)引导:     这里主要是在vold启动时,对现有外设存储设备的处理。

    ·首先,要加载并解析vold.conf,并检查挂载点是否已经被挂载;

    ·其次,执行MMC卡挂载; 

    ·最后,处理USB大容量存储。

     

         3)事件处理:     这里通过对两个连接的监听,完成对动态事件的处理,以及对上层应用操作的响应。

    补充:

    Telechips比较google原生Android 针对Vold的移植主要在以下两方面:

    1.Telchips支持多种存储设备,例如nand,sata,scsi,mmc/sd;从代码角度而言,主要增加了对这些设备事件的处理句柄;

    2.Telchips加入了对ntfs的支持,主要增加了三个处理函数:ntfs_check(),ntfs_identify()和ntfs_mount();

    最新回复(0)