前段时间做了下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
2.   
3.     VolumeManager *vm;  
4.     CommandListener *cl;  
5.     NetlinkManager *nm;  
6.   
7. "Vold 2.1 (the revenge) firing up");  
8.   
9. "/dev/block/vold", 0755);

这里建立了一个/dev/block/vold目录用于放置后面建立的vold节点


1. /* Create our singleton managers */
2. if
3. "Unable to create VolumeManager");  
4.        exit(1);  
5.    };  
6.   
7. if
8. "Unable to create NetlinkManager");  
9.        exit(1);  
10.    };



这里创建了VolumeManager和NetlinkManager两个实例,VolumeManager主要负责Voluem的一些管理,NetlinkManager主要负责管理与内核之间的通信

1. cl = new

这里首先创建了CommandListener,CommandListener主要负责与FrameWork层的通信,处理从FrameWork层收到的各种命令,我们先看看他的构造函数:

1. CommandListener::CommandListener() :  
2. "vold") {  
3. new
4. new
5. new
6. new
7. new
8. new
9. new
10. }

这里注册了各种命令,注意FrameworkListener("vold"),FrameworkListener又继承了SocketListener,最终"vold"传到了SocketListener里面。

    1. vm->setBroadcaster((SocketListener *) cl);  
    2. nm->setBroadcaster((SocketListener *) cl);



    1. if
    2. "Unable to start VolumeManager (%s)", strerror(errno));  
    3.         exit(1);  
    4.     }


    设置了Broadcaster,后面给FrameWork层发送消息就跟它有关了,

    1. if
    2. "Error reading configuration (%s)... continuing anyways", strerror(errno));  
    3.     }

    解析vold.fstab,我们看下process_config函数:



    1. static int
    2. FILE
    3. int
    4. char
    5.   
    6. if (!(fp = fopen("/etc/vold.fstab", "r"))) {  
    7. return
    8.     }  
    9.   
    10. while(fgets(line, sizeof(line), fp)) {  
    11. char
    12. char
    13.   
    14.         n++;  
    15. '\0';  
    16.   
    17. if (line[0] == '#' || line[0] == '\0')  
    18. continue;  
    19.   
    20. if (!(type = strsep(&next, " \t"))) {  
    21. "Error parsing type");  
    22. goto
    23.         }  
    24. if (!(label = strsep(&next, " \t"))) {<span style="white-space:pre">            </span>//标签
    25. "Error parsing label");  
    26. goto
    27.         }  
    28. if (!(mount_point = strsep(&next, " \t"))) {<span style="white-space:pre">      </span>//挂载点
    29. "Error parsing mount point");  
    30. goto
    31.         }  
    32.   
    33. if (!strcmp(type, "dev_mount")) {<span style="white-space:pre">         </span>//挂载命令
    34.             DirectVolume *dv = NULL;  
    35. char
    36.   
    37. if (!(part = strsep(&next, " \t"))) {<span style="white-space:pre">     </span>//分区数
    38. "Error parsing partition");  
    39. goto
    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. "Partition must either be 'auto' or 1 based index instead of '%s'", part);  
    43. goto
    44.             }  
    45.   
    46. if (!strcmp(part, "auto")) {  
    47. new
    48. else
    49. new
    50.             }  
    51.   
    52. while((sysfs_path = strsep(&next, " \t"))) {  
    53. if (dv->addPath(sysfs_path)) {<span style="white-space:pre">         </span>//这里的Path在挂载的时候会用到
    54. "Failed to add devpath %s to volume %s", sysfs_path,  
    55.                          label);  
    56. goto
    57.                 }  
    58.             }  
    59. "white-space:pre">     </span>//添加到VolumeManager,由它负责统一管理
    60. else if (!strcmp(type, "map_mount")) {  
    61. else
    62. "Unknown type '%s'", type);  
    63. goto
    64.         }  
    65.     }  
    66.   
    67.     fclose(fp);  
    68. return
    69.   
    70. out_syntax:  
    71. "Syntax error on config line %d", n);  
    72.     errno = -EINVAL;  
    73. out_fail:  
    74.     fclose(fp);  
    75. return
    76. }



    解析了vold.fstab之后 ,就开始启动VolumeManager,



    1. if
    2. "Unable to start NetlinkManager (%s)", strerror(errno));  
    3.         exit(1);  
    4.     }

    我们跟进去看看:


    1. int
    2. struct
    3. int
    4. int
    5.   
    6. sizeof(nladdr));  
    7.     nladdr.nl_family = AF_NETLINK;  
    8.     nladdr.nl_pid = getpid();  
    9.     nladdr.nl_groups = 0xffffffff;  
    10.   
    11. if
    12. "white-space:pre">     </span>//注册<span style="background-color: rgb(255, 255, 255); ">UEVENT事件,用于接收内核消息</span>
    13. "Unable to create uevent socket: %s", strerror(errno));  
    14. return
    15.     }  
    16.   
    17. if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {  
    18. "Unable to set uevent socket options: %s", strerror(errno));  
    19. return
    20.     }  
    21.   
    22. if (setsockopt(mSock, SOL_SOCKET, SO_REUSEADDR,  &on, sizeof(on)) < 0) {  
    23. "Unable to set SO_REUSEADDR options: %s", strerror(errno));  
    24. return
    25.     }  
    26.       
    27. if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {  
    28. "Unable to bind uevent socket: %s", strerror(errno));  
    29. return
    30.     }  
    31.   
    32. 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. "Unable to start NetlinkHandler: %s", strerror(errno));  
    35. return
    36.     }  
    37. return
    38. }


    我们跟进mHandler->start()最终调用 SocketListener::startListener()

    1. int
    2.   
    3. if (!mSocketName && mSock == -1) { //这里<span style="background-color: rgb(255, 255, 255); ">mSock 刚赋值了</span>
    4. "Failed to start unbound listener");  
    5.         errno = EINVAL;  
    6. return
    7. else if
    8. if
    9. "Obtaining file descriptor socket '%s' failed: %s",  
    10.                  mSocketName, strerror(errno));  
    11. return
    12.         }  
    13.     }  
    14.   
    15. if
    16. "Unable to listen on socket (%s)", strerror(errno));  
    17. return
    18. else if
    19. new
    20.   
    21. if (pipe(mCtrlPipe)) {<span style="white-space:pre">        </span>//建立管道,用于后面的关闭监听循环
    22. "pipe failed (%s)", strerror(errno));  
    23. return
    24.     }  
    25.   
    26. if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {  
    27. "pthread_create (%s)", strerror(errno));  
    28. return
    29.     }  
    30.   
    31. return
    32. }

    我们再看下threadStart,最终调用runListener

    1. void
    2.   
    3. while(1) {  
    4.         SocketClientCollection::iterator it;  
    5.         fd_set read_fds;  
    6. int
    7. int
    8.   
    9.         FD_ZERO(&read_fds);  
    10.   
    11. if
    12.             max = mSock;  
    13.             FD_SET(mSock, &read_fds);  
    14.         }  
    15.   
    16. //把<span style="background-color: rgb(255, 255, 255); ">mCtrlPipe[0]也加入监听中</span>
    17. if
    18.             max = mCtrlPipe[0];  
    19.   
    20.         pthread_mutex_lock(&mClientsLock);  
    21. for
    22.             FD_SET((*it)->getSocket(), &read_fds);  
    23. if
    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. "select failed (%s)", strerror(errno));  
    30.             sleep(1);  
    31. continue;  
    32. else if
    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
    38. struct
    39. sizeof(addr);  
    40. int
    41.   
    42. if ((c = accept(mSock, &addr, &alen)) < 0) {<span style="white-space:pre">           </span>//有新的连接来了,主要是FrameWork层的,
    43. "accept failed (%s)", strerror(errno));  
    44.                 sleep(1);  
    45. continue;  
    46.             }  
    47.             pthread_mutex_lock(&mClientsLock);  
    48. 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
    55. int
    56. if
    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
    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
    72.     }  
    73. }


    这样,就开始了监听来自内核的事件

    1. coldboot("/sys/block");  
    2. "/sys/class/switch");  
    3.   
    4. /*
    5.  * Now that we're up, we can respond to commands
    6.  */
    7. if
    8. "Unable to start CommandListener (%s)", strerror(errno));  
    9.     exit(1);  
    10. }

    这里主要看cl->startListener,也跟前面 的一样,调用SocketListener::startListener(),注意这时



    1. if
    2. "Failed to start unbound listener");  
    3.     errno = EINVAL;  
    4. return
    5. } else if
    6. if
    7. "Obtaining file descriptor socket '%s' failed: %s",  
    8.              mSocketName, strerror(errno));  
    9. return
    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
    10. {  
    11. char
    12. const char
    13. int
    14.   
    15. /* build our environment variable, counting cycles like a wolf ... */
    16. #if HAVE_STRLCPY
    17. 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. sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,  
    22.         name,  
    23. sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));  
    24. sizeof(key)-1] = '\0';  
    25. #endif
    26.   
    27.     val = getenv(key);  
    28. if
    29. return
    30.   
    31.     errno = 0;  
    32.     fd = strtol(val, NULL, 10);  
    33. if
    34. return
    35.   
    36. return
    37. }


    这里面通过组合成一个环境变量名,然后获取对应的值,那么这个值是什么时候设置的呢,我们看下系统初始化的时候调用的service_start



    1. void service_start(struct service *svc, const char
    2. {  
    3.    ...  
    4. for
    5. int
    6. "stream") ? SOCK_STREAM :  
    7. "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));  
    8. int
    9.                                   si->perm, si->uid, si->gid);  
    10. if
    11.                 publish_socket(si->name, s);  
    12.             }  
    13.         }  
    14. }



    跟进publish_socket


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

    1. static void publish_socket(const char *name, int
    2. {  
    3. char
    4. char
    5.   
    6. sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,  
    7.             name,  
    8. sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));  
    9. 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. }