Android -- Vold机制简要分析

Vold是用于管理和控制Android外部存储介质的后台进程,这里说的管控,主要包括SD卡的插拔、挂载/卸载和格式化等;它是Android平台外部存储系统的管控枢纽。
Vold的整个控制模块主要由三个类模块构成:NetlinkManager、VolumeManager和CommandListener,它们的功能划分大概是:

  1. NetlinkManager:用于从kernel中获取SD卡插拔的Uevnet消息
  2. VolumeManager:管理模块,对NetlinkManager转发的消息做一些处理,并通过CommandListener发送给framework(MountService.java);接着framework会通过套接字下发命令,指引VolumeManager对存储设备做下一步的操作,如挂载/卸载等
  3. CommandListener:通过socket,实现MountService.java与Vold之间的消息交换
NetLink是Linux下用户进程和kernel进行信息交互的一种机制,借助这种机制,用户进程(如Vold/Netd)可以接收来自kernel的一些消息,同时也可以向kernel发送一些控制命令。NetlinkManager就是基于此设计的。Uevent也跟Linux系统有关,它与Linux 的设备文件系统有一定关系;这里,我们可以简单的认为,Uevent就是一个字符串,它描述了外部存储设备插入/拔出、挂载/卸载的状态信息。Vold通过Netlink机制,可以得到这些信息,并进行外部存储设备的管理、控制。
由上述介绍,我们可以得到如下的Vold框架图描述:


有了Vold的架构描述,接下来就开始分析Vold进程的整体流程及实现了。

一、Vold进程的声明与创建

Vold进程的声明与创建过程跟zygote一样,在init.rc中声明,在init进程创建:
[java]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. service vold /system/bin/vold \  
  2.         --blkid_context=u:r:blkid:s0 --blkid_untrusted_context=u:r:blkid_untrusted:s0 \  
  3.         --fsck_context=u:r:fsck:s0 --fsck_untrusted_context=u:r:fsck_untrusted:s0  
  4.     class core  
  5.     socket vold stream 0660 root mount  
  6.     socket cryptd stream 0660 root mount  
  7.     ioprio be 2  
在创建Vold进程时,会为它创建两个socket,用于与framework进行信息交互。其他的细节,参考之前zygote进程创建的介绍。

二、进入Vold主程序

Vold的主程序在/system/vold目录中,直接看main.cpp::main()函数:
[cpp]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. int main(int argc, char** argv) {  
  2.     setenv("ANDROID_LOG_TAGS""*:v", 1);  
  3.     android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));  
  4.   
  5.     LOG(INFO) << "Vold 3.0 (the awakening) firing up";  
  6.   
  7.     LOG(VERBOSE) << "Detected support for:"  
  8.             << (android::vold::IsFilesystemSupported("ext4") ? " ext4" : "")  
  9.             << (android::vold::IsFilesystemSupported("f2fs") ? " f2fs" : "")  
  10.             << (android::vold::IsFilesystemSupported("vfat") ? " vfat" : "");  
  11.   
  12.     VolumeManager *vm;  
  13.     CommandListener *cl;  
  14.     CryptCommandListener *ccl;  
  15.     NetlinkManager *nm;  
  16.   
  17.     parse_args(argc, argv);  
  18.   
  19.     sehandle = selinux_android_file_context_handle();  
  20.     if (sehandle) {  
  21.         selinux_android_set_sehandle(sehandle);  
  22.     }  
  23.   
  24.     // Quickly throw a CLOEXEC on the socket we just inherited from init  
  25.     fcntl(android_get_control_socket("vold"), F_SETFD, FD_CLOEXEC);//拿到init进程创建的名为vold的socket句柄,并为它设置FD_CLOEXEC标志位  
  26.     fcntl(android_get_control_socket("cryptd"), F_SETFD, FD_CLOEXEC);//同上  
  27.   
  28.     mkdir("/dev/block/vold", 0755);//创建/dev/block/vold目录,存放所有subdisk和sdcard的挂载点信息  
  29.   
  30.     /* For when cryptfs checks and mounts an encrypted filesystem */  
  31.     klog_set_level(6);  
  32.   
  33.     /* Create our singleton managers */  
  34.     //1、创建VolumeManager  
  35.     if (!(vm = VolumeManager::Instance())) {  
  36.         LOG(ERROR) << "Unable to create VolumeManager";  
  37.         exit(1);  
  38.     }  
  39.       
  40.     //2、创建NetlinkManager  
  41.     if (!(nm = NetlinkManager::Instance())) {  
  42.         LOG(ERROR) << "Unable to create NetlinkManager";  
  43.         exit(1);  
  44.     }  
  45.   
  46.     if (property_get_bool("vold.debug"false)) {  
  47.         vm->setDebug(true);  
  48.     }  
  49.       
  50.     //3、创建CommandListener、CryptCommandListener  
  51.     cl = new CommandListener();  
  52.     ccl = new CryptCommandListener();  
  53.     vm->setBroadcaster((SocketListener *) cl);  
  54.     nm->setBroadcaster((SocketListener *) cl);  
  55.   
  56.     //4、启动VolumeManager  
  57.     if (vm->start()) {  
  58.         PLOG(ERROR) << "Unable to start VolumeManager";  
  59.         exit(1);  
  60.     }  
  61.   
  62.     if (process_config(vm)) {  
  63.         PLOG(ERROR) << "Error reading configuration... continuing anyways";  
  64.     }  
  65.   
  66.     //6、启动NetlinkManager,处理来自kernel的usb/sdcard插拔消息  
  67.     if (nm->start()) {  
  68.         PLOG(ERROR) << "Unable to start NetlinkManager";  
  69.         exit(1);  
  70.     }  
  71.     //7、应用层往/sys/block目录下的uevent文件写"add\n"指令,触发kernel向上发送Uevent消息,获取设备的当前信息  
  72.     coldboot("/sys/block");  
  73. //    coldboot("/sys/class/switch");  
  74.   
  75.     /* 
  76.      * Now that we're up, we can respond to commands 
  77.      */  
  78.     //8、启动CommandListener  
  79.     if (cl->startListener()) {  
  80.         PLOG(ERROR) << "Unable to start CommandListener";  
  81.         exit(1);  
  82.     }  
  83.       
  84.     //9、启动CryptCommandListener  
  85.     if (ccl->startListener()) {  
  86.         PLOG(ERROR) << "Unable to start CryptCommandListener";  
  87.         exit(1);  
  88.     }  
  89.   
  90.     // Eventually we'll become the monitoring thread  
  91.     while(1) {  
  92.         sleep(1000);  
  93.     }  
  94.   
  95.     LOG(ERROR) << "Vold exiting";  
  96.     exit(0);  
  97. }  
从代码中的注释可知,Vold主要创了三个对象:NetlinkManager、VolumeManager和CommandListener。根据Vold的架构图,现分别对它们的创建及启动过程进行分析。
(1)、NetlinkManager
主要的处理过程:
  1. nm = NetlinkManager::Instance()
  2. nm->setBroadcaster((SocketListener *) cl)
  3. nm->start()
现按步骤进行分析。
1、NetlinkManager::Instance():
[cpp]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. NetlinkManager *NetlinkManager::Instance() {  
  2.     if (!sInstance)  
  3.         sInstance = new NetlinkManager();  
  4.     return sInstance;  
  5. }  
  6.   
  7. NetlinkManager::NetlinkManager() {  
  8.     mBroadcaster = NULL; //type:SocketListener*,用来进行socket通信  
  9. }  
这里使用了单例模式来构建NetlinkManager对象,构造函数中只是简单地初始化了成员变量。
2、NetlinkManager::setBroadcaster():
[cpp]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. cl = new CommandListener();  
  2. nm->setBroadcaster((SocketListener *) cl);  
  3. void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }  
setBroadcaster()函数也很简单,为mBroadcast进行赋值。
3、NetlinkManager::start():
[cpp]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. int NetlinkManager::start() {  
  2.     struct sockaddr_nl nladdr;  
  3.     int sz = 64 * 1024;  
  4.     int on = 1;  
  5.   
  6.     memset(&nladdr, 0, sizeof(nladdr));  
  7.     nladdr.nl_family = AF_NETLINK;  
  8.     nladdr.nl_pid = getpid();  
  9.     nladdr.nl_groups = 0xffffffff;  
  10.   
  11.     //创建地址族为PF_NETLINK的socket,与Kernel进行通信;也可以为AF_NETLINK.参照Linux Netlink机制资料  
  12.     if ((mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC,  
  13.             NETLINK_KOBJECT_UEVENT)) < 0) { //NETLINK_KOBJECT_UEVENT协议:Kernel messages to userspace  
  14.         SLOGE("Unable to create uevent socket: %s", strerror(errno));  
  15.         return -1;  
  16.     }  
  17.   
  18.     //设置套接字  
  19.     if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {  
  20.         SLOGE("Unable to set uevent socket SO_RCVBUFFORCE option: %s", strerror(errno));  
  21.         goto out;  
  22.     }  
  23.   
  24.     if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {  
  25.         SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));  
  26.         goto out;  
  27.     }  
  28.   
  29.     //为套接字绑定地址  
  30.     if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {  
  31.         SLOGE("Unable to bind uevent socket: %s", strerror(errno));  
  32.         goto out;  
  33.     }  
  34.   
  35.     mHandler = new NetlinkHandler(mSock);//mHandler、mSock都是成员变量.mHandler对象主要保存了套接字的文件描述符,供后续使用  
  36.     if (mHandler->start()) { //startListener通过父类方法,在mSock上监听连接请求  
  37.         SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));  
  38.         goto out;  
  39.     }  
  40.   
  41.     return 0;  
  42.   
  43. out:  
  44.     close(mSock);  
  45.     return -1;  
  46. }  
start()方法中创建了一个句柄值为mSock的套接字,用来和kernel通信;而实际具体的socket信息交互是由NetlinkHandler处理的。
NetlinkHandler的实现有一套继承机制,其实际继承关系如图所示:

按照继承关系,分析它的构建过程:
[cpp]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. mHandler = new NetlinkHandler(mSock);  
  2. NetlinkHandler::NetlinkHandler(int listenerSocket) :  
  3.                 NetlinkListener(listenerSocket) {  
  4. }  
[cpp]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. /* temporary version until we can get Motorola to update their 
  2.  * ril.so.  Their prebuilt ril.so is using this private class 
  3.  * so changing the NetlinkListener() constructor breaks their ril. 
  4.  */  
  5. NetlinkListener::NetlinkListener(int socket) :  
  6.                             SocketListener(socket, false) {  
  7.     mFormat = NETLINK_FORMAT_ASCII;  
  8. }  
[cpp]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. SocketListener::SocketListener(const char *socketName, bool listen) {  
  2.     init(socketName, -1, listen, false);  
  3. }  
  4. void SocketListener::init(const char *socketName, int socketFd, bool listen, 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值