前段时间做了下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. }