zoukankan      html  css  js  c++  java
  • android usb挂载分析----vold启动

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

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

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

    vold启动在init.rc中:

    system/core/rootdir/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(init.mt8127.rc),我们看下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] = '';  
    16.   
    17.         if (line[0] == '#' || line[0] == '')  
    18.             continue;  
    19.   
    20.         if (!(type = strsep(&next, "  "))) {  
    21.             SLOGE("Error parsing type");  
    22.             goto out_syntax;  
    23.         }  
    24.         if (!(label = strsep(&next, "  "))) {          //标签  
    25.             SLOGE("Error parsing label");  
    26.             goto out_syntax;  
    27.         }  
    28.         if (!(mount_point = strsep(&next, "  "))) {        //挂载点  
    29.             SLOGE("Error parsing mount point");  
    30.             goto out_syntax;  
    31.         }  
    32.   
    33.         if (!strcmp(type, "dev_mount")) {           //挂载命令  
    34.             DirectVolume *dv = NULL;  
    35.             char *part, *sysfs_path;  
    36.   
    37.             if (!(part = strsep(&next, "  "))) {       //分区数  
    38.                 SLOGE("Error parsing partition");  
    39.                 goto out_syntax;  
    40.             }  
    41.             if (strcmp(part, "auto") && atoi(part) == 0) {      //auto则表示只有1个子分区  
    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, "  "))) {  
    53.                 if (dv->addPath(sysfs_path)) {       //这里的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);//添加到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) {//注册UEVENT事件,用于接收内核消息  
    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);//NetlinkHandler用于对接收到的内核消息进行处理  
    33.     if (mHandler->start()) {//开始监听内核消息  
    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) { //这里mSock 刚赋值了  
    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)) {//建立管道,用于后面的关闭监听循环  
    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);  //把mCtrlPipe[0]也加入监听中  
    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) {//阻塞直到有数据到来  
    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))//mCtrlPipe[0]有数据,则结循环,注意是在stopListener的时候 往mCtrlPipe[1]写数据  
    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) {//有新的连接来了,主要是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));//加到监听的列表  
    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)) {//处理消息  
    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(/system/core/include/cutils/sockets.h),我们看下这个函数

    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] = '';  
    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(system/core/init/init.c)

    
    
    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的消息的。。。。

  • 相关阅读:
    老罗锤子手机发布会,我感到深深地愧疚!
    微价值:专访《甜心爱消除》的个人开发者Lee,日入千元
    [个人开发者赚钱二]从自己最熟悉的方面入手,获取小利
    [个人开发者赚钱一]改变思维,从心开始
    个人开发者赚钱一、改变思维,从心开始
    OC中的点语法,成员变量的作用域
    OC self super isa指针
    OC面向对象多态笔记
    OC面向对象继承关系和组合关系笔记
    OC面向对象封装
  • 原文地址:https://www.cnblogs.com/senior-engineer/p/4847647.html
Copyright © 2011-2022 走看看