android usb挂载分析----vold启动

前段时间做了下usb挂载的,现在出了几个bug,又要把流程给梳理下,顺便也把相关的知识总结下,以免下次又需要,上次弄的时候由于刚开始弄android i不久,所以只是保证了能够通过vold模块把u盘等挂载上去,具体应用能不能看到里面的东东的话就呵呵,没有保证了,现在出的几个bug也就这样,唉……

学习了罗老师的,先慢慢的把流程图画出来:



vold启动在init.rc中:

  1. service vold /system/bin/vold  
  2.     socket vold stream 0660 root mount  
  3.     ioprio be 2  
注意这里创建了一个socket,用于vold和FrameWork层通信

vold代码在system/vold目录下面,

函数入口main函数:

  1. int main() {  
  2.   
  3.     VolumeManager *vm;  
  4.     CommandListener *cl;  
  5.     NetlinkManager *nm;  
  6.   
  7.     SLOGI("Vold 2.1 (the revenge) firing up");  
  8.   
  9.     mkdir("/dev/block/vold", 0755);  
这里建立了一个/dev/block/vold目录用于放置后面建立的vold节点
  1. /* Create our singleton managers */  
  2.    if (!(vm = VolumeManager::Instance())) {  
  3.        SLOGE("Unable to create VolumeManager");  
  4.        exit(1);  
  5.    };  
  6.   
  7.    if (!(nm = NetlinkManager::Instance())) {  
  8.        SLOGE("Unable to create NetlinkManager");  
  9.        exit(1);  
  10.    };  

这里创建了VolumeManager和NetlinkManager两个实例,VolumeManager主要负责Voluem的一些管理,NetlinkManager主要负责管理与内核之间的通信
  1. cl = new CommandListener();  
这里首先创建了CommandListener,CommandListener主要负责与FrameWork层的通信,处理从FrameWork层收到的各种命令,我们先看看他的构造函数:
  1. CommandListener::CommandListener() :  
  2.                  FrameworkListener("vold") {  
  3.     registerCmd(new DumpCmd());  
  4.     registerCmd(new VolumeCmd());  
  5.     registerCmd(new AsecCmd());  
  6.     registerCmd(new ObbCmd());  
  7.     registerCmd(new ShareCmd());  
  8.     registerCmd(new StorageCmd());  
  9.     registerCmd(new XwarpCmd());  
  10. }  
这里注册了各种命令,注意FrameworkListener("vold"),FrameworkListener又继承了SocketListener,最终"vold"传到了SocketListener里面。
  1. vm->setBroadcaster((SocketListener *) cl);  
  2. nm->setBroadcaster((SocketListener *) cl);  
  1.     if (vm->start()) {  
  2.         SLOGE("Unable to start VolumeManager (%s)", strerror(errno));  
  3.         exit(1);  
  4.     }  

设置了Broadcaster,后面给FrameWork层发送消息就跟它有关了,
  1. if (process_config(vm)) {  
  2.         SLOGE("Error reading configuration (%s)... continuing anyways", strerror(errno));  
  3.     }  
解析vold.fstab,我们看下process_config函数:
  1. static int process_config(VolumeManager *vm){  
  2.     FILE *fp;  
  3.     int n = 0;  
  4.     char line[255];  
  5.   
  6.     if (!(fp = fopen("/etc/vold.fstab""r"))) {  
  7.         return -1;  
  8.     }  
  9.   
  10.     while(fgets(line, sizeof(line), fp)) {  
  11.         char *next = line;  
  12.         char *type, *label, *mount_point;  
  13.   
  14.         n++;  
  15.         line[strlen(line)-1] = '\0';  
  16.   
  17.         if (line[0] == '#' || line[0] == '\0')  
  18.             continue;  
  19.   
  20.         if (!(type = strsep(&next, " \t"))) {  
  21.             SLOGE("Error parsing type");  
  22.             goto out_syntax;  
  23.         }  
  24.         if (!(label = strsep(&next, " \t"))) {<span style="white-space:pre">            </span>//标签  
  25.             SLOGE("Error parsing label");  
  26.             goto out_syntax;  
  27.         }  
  28.         if (!(mount_point = strsep(&next, " \t"))) {<span style="white-space:pre">      </span>//挂载点  
  29.             SLOGE("Error parsing mount point");  
  30.             goto out_syntax;  
  31.         }  
  32.   
  33.         if (!strcmp(type, "dev_mount")) {<span style="white-space:pre">         </span>//挂载命令  
  34.             DirectVolume *dv = NULL;  
  35.             char *part, *sysfs_path;  
  36.   
  37.             if (!(part = strsep(&next, " \t"))) {<span style="white-space:pre">     </span>//分区数  
  38.                 SLOGE("Error parsing partition");  
  39.                 goto out_syntax;  
  40.             }  
  41.             if (strcmp(part, "auto") && atoi(part) == 0) {<span style="white-space:pre">        </span>//<span style="color: rgb(51, 51, 51); font-family: Arial; font-size: 18px; line-height: 26px; text-align: left; ">auto则表示只有1个子分区</span>  
  42.                 SLOGE("Partition must either be 'auto' or 1 based index instead of '%s'", part);  
  43.                 goto out_syntax;  
  44.             }  
  45.   
  46.             if (!strcmp(part, "auto")) {  
  47.                 dv = new DirectVolume(vm, label, mount_point, -1);  
  48.             } else {  
  49.                 dv = new DirectVolume(vm, label, mount_point, atoi(part));  
  50.             }  
  51.   
  52.             while((sysfs_path = strsep(&next, " \t"))) {  
  53.                 if (dv->addPath(sysfs_path)) {<span style="white-space:pre">         </span>//这里的Path在挂载的时候会用到  
  54.                     SLOGE("Failed to add devpath %s to volume %s", sysfs_path,  
  55.                          label);  
  56.                     goto out_fail;  
  57.                 }  
  58.             }  
  59.             vm->addVolume(dv);<span style="white-space:pre">     </span>//添加到VolumeManager,由它负责统一管理  
  60.         } else if (!strcmp(type, "map_mount")) {  
  61.         } else {  
  62.             SLOGE("Unknown type '%s'", type);  
  63.             goto out_syntax;  
  64.         }  
  65.     }  
  66.   
  67.     fclose(fp);  
  68.     return 0;  
  69.   
  70. out_syntax:  
  71.     SLOGE("Syntax error on config line %d", n);  
  72.     errno = -EINVAL;  
  73. out_fail:  
  74.     fclose(fp);  
  75.     return -1;     
  76. }  

解析了vold.fstab之后 ,就开始启动VolumeManager,
  1. if (nm->start()) {  
  2.         SLOGE("Unable to start NetlinkManager (%s)", strerror(errno));  
  3.         exit(1);  
  4.     }  
我们跟进去看看:
  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.     if ((mSock = socket(PF_NETLINK,  
  12.                         SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {<span style="white-space:pre">     </span>//注册<span style="background-color: rgb(255, 255, 255); ">UEVENT事件,用于接收内核消息</span>  
  13.         SLOGE("Unable to create uevent socket: %s", strerror(errno));  
  14.         return -1;  
  15.     }  
  16.   
  17.     if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {  
  18.         SLOGE("Unable to set uevent socket options: %s", strerror(errno));  
  19.         return -1;  
  20.     }  
  21.   
  22.     if (setsockopt(mSock, SOL_SOCKET, SO_REUSEADDR,  &on, sizeof(on)) < 0) {  
  23.         LOGE("Unable to set SO_REUSEADDR options: %s", strerror(errno));  
  24.         return -1;  
  25.     }  
  26.       
  27.     if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {  
  28.         SLOGE("Unable to bind uevent socket: %s", strerror(errno));  
  29.         return -1;  
  30.     }  
  31.   
  32.     mHandler = new NetlinkHandler(mSock);<span style="white-space:pre">     </span>//<span style="background-color: rgb(255, 255, 255); ">NetlinkHandler用于对接收到的内核消息进行处理</span>  
  33.     if (mHandler->start()) {<span style="white-space:pre">               </span>//开始监听内核消息  
  34.         SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));  
  35.         return -1;  
  36.     }  
  37.     return 0;  
  38. }  

我们跟进mHandler->start()最终调用 SocketListener::startListener()
  1. int SocketListener::startListener() {  
  2.   
  3.     if (!mSocketName && mSock == -1) { //这里<span style="background-color: rgb(255, 255, 255); ">mSock 刚赋值了</span>  
  4.         SLOGE("Failed to start unbound listener");  
  5.         errno = EINVAL;  
  6.         return -1;  
  7.     } else if (mSocketName) {  
  8.         if ((mSock = android_get_control_socket(mSocketName)) < 0) {  
  9.             SLOGE("Obtaining file descriptor socket '%s' failed: %s",  
  10.                  mSocketName, strerror(errno));  
  11.             return -1;  
  12.         }  
  13.     }  
  14.   
  15.     if (mListen && listen(mSock, 4) < 0) {  
  16.         SLOGE("Unable to listen on socket (%s)", strerror(errno));  
  17.         return -1;  
  18.     } else if (!mListen)  
  19.         mClients->push_back(new SocketClient(mSock));  
  20.   
  21.     if (pipe(mCtrlPipe)) {<span style="white-space:pre">        </span>//建立管道,用于后面的关闭监听循环  
  22.         SLOGE("pipe failed (%s)", strerror(errno));  
  23.         return -1;  
  24.     }  
  25.   
  26.     if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {  
  27.         SLOGE("pthread_create (%s)", strerror(errno));  
  28.         return -1;  
  29.     }  
  30.   
  31.     return 0;  
  32. }  
我们再看下threadStart,最终调用runListener
  1. void SocketListener::runListener() {  
  2.   
  3.     while(1) {  
  4.         SocketClientCollection::iterator it;  
  5.         fd_set read_fds;  
  6.         int rc = 0;  
  7.         int max = 0;  
  8.   
  9.         FD_ZERO(&read_fds);  
  10.   
  11.         if (mListen) {  
  12.             max = mSock;  
  13.             FD_SET(mSock, &read_fds);  
  14.         }  
  15.   
  16.         FD_SET(mCtrlPipe[0], &read_fds);  //把<span style="background-color: rgb(255, 255, 255); ">mCtrlPipe[0]也加入监听中</span>  
  17.         if (mCtrlPipe[0] > max)  
  18.             max = mCtrlPipe[0];  
  19.   
  20.         pthread_mutex_lock(&mClientsLock);  
  21.         for (it = mClients->begin(); it != mClients->end(); ++it) {  
  22.             FD_SET((*it)->getSocket(), &read_fds);  
  23.             if ((*it)->getSocket() > max)  
  24.                 max = (*it)->getSocket();  
  25.         }  
  26.         pthread_mutex_unlock(&mClientsLock);  
  27.   
  28.         if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {<span style="white-space:pre">     </span>//阻塞直到有数据到来  
  29.             SLOGE("select failed (%s)", strerror(errno));  
  30.             sleep(1);  
  31.             continue;  
  32.         } else if (!rc)  
  33.             continue;  
  34.   
  35.         if (FD_ISSET(mCtrlPipe[0], &read_fds))<span style="white-space:pre">                </span>//<span style="background-color: rgb(255, 255, 255); ">mCtrlPipe[0]有数据,则结循环,注意是在stopListener的时候 往mCtrlPipe[1]写数据</span>  
  36.             break;  
  37.         if (mListen && FD_ISSET(mSock, &read_fds)) {  
  38.             struct sockaddr addr;  
  39.             socklen_t alen = sizeof(addr);  
  40.             int c;  
  41.   
  42.             if ((c = accept(mSock, &addr, &alen)) < 0) {<span style="white-space:pre">           </span>//有新的连接来了,主要是FrameWork层的,  
  43.                 SLOGE("accept failed (%s)", strerror(errno));  
  44.                 sleep(1);  
  45.                 continue;  
  46.             }  
  47.             pthread_mutex_lock(&mClientsLock);  
  48.             mClients->push_back(new SocketClient(c));<span style="white-space:pre">              </span>//加到监听的列表  
  49.             pthread_mutex_unlock(&mClientsLock);  
  50.         }  
  51.   
  52.         do {  
  53.             pthread_mutex_lock(&mClientsLock);  
  54.             for (it = mClients->begin(); it != mClients->end(); ++it) {  
  55.                 int fd = (*it)->getSocket();  
  56.                 if (FD_ISSET(fd, &read_fds)) {  
  57.                     pthread_mutex_unlock(&mClientsLock);  
  58.                     if (!onDataAvailable(*it)) {<span style="white-space:pre">              </span>//处理消息  
  59.                         close(fd);  
  60.                         pthread_mutex_lock(&mClientsLock);  
  61.                         delete *it;  
  62.                         it = mClients->erase(it);  
  63.                         pthread_mutex_unlock(&mClientsLock);  
  64.                     }  
  65.                     FD_CLR(fd, &read_fds);  
  66.                     pthread_mutex_lock(&mClientsLock);  
  67.                     continue;  
  68.                 }  
  69.             }  
  70.             pthread_mutex_unlock(&mClientsLock);  
  71.         } while (0);  
  72.     }  
  73. }  

这样,就开始了监听来自内核的事件
  1. coldboot("/sys/block");  
  2.   coldboot("/sys/class/switch");  
  3.   
  4. /* 
  5.  * Now that we're up, we can respond to commands 
  6.  */  
  7. if (cl->startListener()) {  
  8.     SLOGE("Unable to start CommandListener (%s)", strerror(errno));  
  9.     exit(1);  
  10. }  
这里主要看cl->startListener,也跟前面 的一样,调用SocketListener::startListener(),注意这时
  1. if (!mSocketName && mSock == -1) {  
  2.     SLOGE("Failed to start unbound listener");  
  3.     errno = EINVAL;  
  4.     return -1;  
  5. else if (mSocketName) {  
  6.     if ((mSock = android_get_control_socket(mSocketName)) < 0) {  
  7.         SLOGE("Obtaining file descriptor socket '%s' failed: %s",  
  8.              mSocketName, strerror(errno));  
  9.         return -1;  
  10.     }  
  11. }  

这里mSocketName 为"vold",mSock = -1,所以会调用android_get_control_socket,我们看下这个函数
  1. /* 
  2.  * android_get_control_socket - simple helper function to get the file 
  3.  * descriptor of our init-managed Unix domain socket. `name' is the name of the 
  4.  * socket, as given in init.rc. Returns -1 on error. 
  5.  * 
  6.  * This is inline and not in libcutils proper because we want to use this in 
  7.  * third-party daemons with minimal modification. 
  8.  */  
  9. static inline int android_get_control_socket(const char *name)  
  10. {  
  11.     char key[64] = ANDROID_SOCKET_ENV_PREFIX;  
  12.     const char *val;  
  13.     int fd;  
  14.   
  15.     /* build our environment variable, counting cycles like a wolf ... */  
  16. #if HAVE_STRLCPY  
  17.     strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,  
  18.         name,  
  19.         sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));  
  20. #else   /* for the host, which may lack the almightly strncpy ... */  
  21.     strncpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,  
  22.         name,  
  23.         sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));  
  24.     key[sizeof(key)-1] = '\0';  
  25. #endif  
  26.   
  27.     val = getenv(key);  
  28.     if (!val)  
  29.         return -1;  
  30.   
  31.     errno = 0;  
  32.     fd = strtol(val, NULL, 10);  
  33.     if (errno)  
  34.         return -1;  
  35.   
  36.     return fd;  
  37. }  

这里面通过组合成一个环境变量名,然后获取对应的值,那么这个值是什么时候设置的呢,我们看下系统初始化的时候调用的service_start
  1. void service_start(struct service *svc, const char *dynamic_args)  
  2. {  
  3.    ...  
  4.    for (si = svc->sockets; si; si = si->next) {  
  5.             int socket_type = (  
  6.                     !strcmp(si->type, "stream") ? SOCK_STREAM :  
  7.                         (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));  
  8.             int s = create_socket(si->name, socket_type,  
  9.                                   si->perm, si->uid, si->gid);  
  10.             if (s >= 0) {  
  11.                 publish_socket(si->name, s);  
  12.             }  
  13.         }  
  14. }  

跟进publish_socket
  1. static void publish_socket(const char *name, int fd)  
  2. {  
  3.     char key[64] = ANDROID_SOCKET_ENV_PREFIX;  
  4.     char val[64];  
  5.   
  6.     strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,  
  7.             name,  
  8.             sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));  
  9.     snprintf(val, sizeof(val), "%d", fd);  
  10.     add_environment(key, val);  
  11.   
  12.     /* make sure we don't close-on-exec */  
  13.     fcntl(fd, F_SETFD, 0);  
  14. }  

没错,就是这里设置了这个环境变量的值。Ok,到这里,vold基本就启动起来了,基本的通信环境也已经搭建好了,就等着u盘插入后kernel的消息的。。。。



转自:http://blog.csdn.net/new_abc/article/details/7396733


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值