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

时间:2023-03-08 23:29:35
android usb挂载分析----vold启动

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

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

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

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

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. VolumeManager *vm;
  3. CommandListener *cl;
  4. NetlinkManager *nm;
  5. SLOGI("Vold 2.1 (the revenge) firing up");
  6. 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. if (!(nm = NetlinkManager::Instance())) {
  7. SLOGE("Unable to create NetlinkManager");
  8. exit(1);
  9. };

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

解析了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. memset(&nladdr, 0, sizeof(nladdr));
  6. nladdr.nl_family = AF_NETLINK;
  7. nladdr.nl_pid = getpid();
  8. nladdr.nl_groups = 0xffffffff;
  9. if ((mSock = socket(PF_NETLINK,
  10. SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {//注册UEVENT事件,用于接收内核消息
  11. SLOGE("Unable to create uevent socket: %s", strerror(errno));
  12. return -1;
  13. }
  14. if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
  15. SLOGE("Unable to set uevent socket options: %s", strerror(errno));
  16. return -1;
  17. }
  18. if (setsockopt(mSock, SOL_SOCKET, SO_REUSEADDR,  &on, sizeof(on)) < 0) {
  19. LOGE("Unable to set SO_REUSEADDR options: %s", strerror(errno));
  20. return -1;
  21. }
  22. if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
  23. SLOGE("Unable to bind uevent socket: %s", strerror(errno));
  24. return -1;
  25. }
  26. mHandler = new NetlinkHandler(mSock);//NetlinkHandler用于对接收到的内核消息进行处理
  27. if (mHandler->start()) {//开始监听内核消息
  28. SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));
  29. return -1;
  30. }
  31. return 0;
  32. }

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

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

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

  1. void SocketListener::runListener() {
  2. while(1) {
  3. SocketClientCollection::iterator it;
  4. fd_set read_fds;
  5. int rc = 0;
  6. int max = 0;
  7. FD_ZERO(&read_fds);
  8. if (mListen) {
  9. max = mSock;
  10. FD_SET(mSock, &read_fds);
  11. }
  12. FD_SET(mCtrlPipe[0], &read_fds);  //把mCtrlPipe[0]也加入监听中
  13. if (mCtrlPipe[0] > max)
  14. max = mCtrlPipe[0];
  15. pthread_mutex_lock(&mClientsLock);
  16. for (it = mClients->begin(); it != mClients->end(); ++it) {
  17. FD_SET((*it)->getSocket(), &read_fds);
  18. if ((*it)->getSocket() > max)
  19. max = (*it)->getSocket();
  20. }
  21. pthread_mutex_unlock(&mClientsLock);
  22. if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {//阻塞直到有数据到来
  23. SLOGE("select failed (%s)", strerror(errno));
  24. sleep(1);
  25. continue;
  26. } else if (!rc)
  27. continue;
  28. if (FD_ISSET(mCtrlPipe[0], &read_fds))//mCtrlPipe[0]有数据,则结循环,注意是在stopListener的时候 往mCtrlPipe[1]写数据
  29. break;
  30. if (mListen && FD_ISSET(mSock, &read_fds)) {
  31. struct sockaddr addr;
  32. socklen_t alen = sizeof(addr);
  33. int c;
  34. if ((c = accept(mSock, &addr, &alen)) < 0) {//有新的连接来了,主要是FrameWork层的,
  35. SLOGE("accept failed (%s)", strerror(errno));
  36. sleep(1);
  37. continue;
  38. }
  39. pthread_mutex_lock(&mClientsLock);
  40. mClients->push_back(new SocketClient(c));//加到监听的列表
  41. pthread_mutex_unlock(&mClientsLock);
  42. }
  43. do {
  44. pthread_mutex_lock(&mClientsLock);
  45. for (it = mClients->begin(); it != mClients->end(); ++it) {
  46. int fd = (*it)->getSocket();
  47. if (FD_ISSET(fd, &read_fds)) {
  48. pthread_mutex_unlock(&mClientsLock);
  49. if (!onDataAvailable(*it)) {//处理消息
  50. close(fd);
  51. pthread_mutex_lock(&mClientsLock);
  52. delete *it;
  53. it = mClients->erase(it);
  54. pthread_mutex_unlock(&mClientsLock);
  55. }
  56. FD_CLR(fd, &read_fds);
  57. pthread_mutex_lock(&mClientsLock);
  58. continue;
  59. }
  60. }
  61. pthread_mutex_unlock(&mClientsLock);
  62. } while (0);
  63. }
  64. }

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

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

这里主要看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. /* build our environment variable, counting cycles like a wolf ... */
  15. #if HAVE_STRLCPY
  16. strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
  17. name,
  18. sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
  19. #else   /* for the host, which may lack the almightly strncpy ... */
  20. strncpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
  21. name,
  22. sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
  23. key[sizeof(key)-1] = '\0';
  24. #endif
  25. val = getenv(key);
  26. if (!val)
  27. return -1;
  28. errno = 0;
  29. fd = strtol(val, NULL, 10);
  30. if (errno)
  31. return -1;
  32. return fd;
  33. }

这里面通过组合成一个环境变量名,然后获取对应的值,那么这个值是什么时候设置的呢,我们看下系统初始化的时候调用的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. strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
  6. name,
  7. sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
  8. snprintf(val, sizeof(val), "%d", fd);
  9. add_environment(key, val);
  10. /* make sure we don't close-on-exec */
  11. fcntl(fd, F_SETFD, 0);
  12. }

没错,就是这里设置了这个环境变量的值。


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