回顾:前贴主要分析了Android存储系统的架构和原理图,简要的介绍了整个从Kernel-->Vold-->上层MountService之间的数据传输流程,在这样的基础上,我们开始今天的源码分析!

  【源码分析】

  1. Vold的main函数

  Vold也是通过init进程启动,它在init.rc中的定义如下:

XML/HTML代码
  1. service vold /system/bin/vold  
  2. class core  
  3. socket vold stream 0660 root mount  
  4. ioprio be 2  

  Vold服务放到了core分组,这就意味着系统启动时,它就会被init进程启动。这里定义的一个socket,主要用语Vold和Java层的MountService通信。

  Vold模块的源代码位于system/vold,我们看看入口函数main(),代码如下:

C++代码
  1. int main() {  
  2.     VolumeManager *vm;  
  3.     CommandListener *cl;  
  4.     NetlinkManager *nm;  
  5.     SLOGI("Vold 2.1 (the revenge) firing up");  
  6.       
  7.     mkdir("/dev/block/vold", 0755);                 // 创建vold目录  
  8.     klog_set_level(6);  
  9.     if (!(vm = VolumeManager::Instance())) {        // 创建VolumeManager对象  
  10.        exit(1);  
  11.    };  
  12.       
  13.    if (!(nm = NetlinkManager::Instance())) {       // 创建NetlinkManager对象  
  14.        exit(1);  
  15.    };  
  16.     cl = new CommandListener();                     // 创建CommandListener对象  
  17.    vm->setBroadcaster((SocketListener *) cl);      // 建立vm和cl的联系  
  18.    nm->setBroadcaster((SocketListener *) cl);      // 建立nm和cl的联系  
  19.     if (vm->start()) {                              // 启动VolumeManager  
  20.        exit(1);  
  21.    }  
  22.     if (process_config(vm)) {                       // 创建文件/fstab.xxx中定义的Volume对象  
  23.        SLOGE("Error reading configuration (%s)... continuing anyways", strerror(errno));  
  24.    }  
  25.     cryptfs_pfe_boot();  
  26.     if (nm->start()) {                              // 启动NetlinkManager,会调用NetlinkManager的start()方法,它创建PF_NETLINK socket,并开启线程从此socket中读取数据  
  27.        exit(1);  
  28.    }  
  29.     coldboot("/sys/block");                         // 冷启动,创建/sys/block下的节点文件  
  30.     if (cl->startListener()) {                      // 开始监听Framework的socket  
  31.        exit(1);  
  32.    }  
  33.      
  34.    while(1) {                                      // 进入循环  
  35.        sleep(1000);                                // 主线程进入休眠  
  36.    }  
  37.     SLOGI("Vold exiting");  
  38.    exit(0);  
  39. }  

  main函数的主要工作是创建3个对象:VolumeManager、NetlinkManager和CommandListener,同时将CommandListener对象分别设置到了VolumeManager对象和NetlinkManager对象中。

  从前贴的架构图中可以发现,CommandListener对象用于和Java层的NativeDaemonConnector对象进行socket通信,因此,无论是VolumeManager对象还是NetlinkManager对象都需要拥有CommandListener对象的引用。

  2. 监听驱动发出的消息—Vold的NetlinkManager对象

  NetlinkManager对象的主要工作是监听驱动发出的uevent消息。

  main()函数中调用NetlinkManager类的静态函数Instance()来创建NetlinkManager对象,代码如下:

C++代码
  1. NetlinkManager *NetlinkManager::Instance() {  
  2.       if (!sInstance)  
  3.           sInstance = new NetlinkManager();      // NetlinkManager对象通过静态变量sInstance来引用,这意味着vold进程中只有一个NetlinkManager对象。  
  4.       return sInstance;  
  5. }  

  看下NetlinkManager的构造函数,代码如下:

C++代码
  1. NetlinkManager::NetlinkManager() {  
  2.       mBroadcaster = NULL;  
  3. }  

  NetlinkManager的构造函数只是对mBroadcaster进行了初始化。我们可以发现main()函数中通过调用NetlinkManager的setBroadcaster()函数来给变量mBroadcaster重新赋值。

C++代码
  1. nm->setBroadcaster((SocketListener *) cl);  

  main()函数还调用了NetlinkManager的start()函数,我们观察一下NetlinkManager中的start()方法,代码如下:

C++代码
  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.      /*创建一个socket用于内核空间和用户空间的异步通信,监控系统的hotplug事件*/  
  11.      if ((mSock = socket(PF_NETLINK,SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {  
  12.          SLOGE("Unable to create uevent socket: %s", strerror(errno));  
  13.          return -1;  
  14.      }  
  15.      /*设置缓冲区大小为64KB*/  
  16.      if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {  
  17.          SLOGE("Unable to set uevent socket SO_RCVBUFFORCE option: %s", strerror(errno));  
  18.          goto out;  
  19.      }  
  20.      /*设置允许 SCM_CREDENTIALS 控制消息的接收*/  
  21.      if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {  
  22.          SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));  
  23.          goto out;  
  24.      }  
  25.      /*绑定 socket 地址*/  
  26.      if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {  
  27.          SLOGE("Unable to bind uevent socket: %s", strerror(errno));  
  28.          goto out;  
  29.      }  
  30.      /*利用新创建的socket实例化一个NetlinkHandler类对象用于监听socket,NetlinkHandler继承了类NetlinkListener,NetlinkListener又继承了类SocketListener*/  
  31.      mHandler = new NetlinkHandler(mSock);  
  32.       if (mHandler->start()) {                                               // 启动NetlinkHandler,调用NetlinkHandler的start()函数  
  33.           SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));  
  34.           goto out;  
  35.      }  
  36.   
  37.      return 0;  
  38.   
  39. out:  
  40.      close(mSock);  
  41.      return -1;  
  42. }  

  我们看一下NetlinkManager的家族关系,如下图:

Android存储系统—Vold与MountService分析(二)

  上面的虚线为启动时的调用流程:

  (1) class NetlinkManager(在其start函数中创建了NetlinkHandler对象,并把创建的socket作为参数)

  (2)class NetlinkHandler: public NetlinkListener(实现了onEvent)

  (3) class NetlinkListener : public SocketListener(实现了onDataAvailable)

  (4) class SocketListener(实现了runListener,在一个线程中通过select查看哪些socket有数据,通过调用onDataAvailable来读取数据)。

  总结:此贴主要分析了Vold的main()函数和NetlinkManager对象的源码,通过源码了解对象的创建时机和函数调用流程,下一贴会继续从NetlinkHandler的start()方法深入分析,继续源码的学习,很快会与大家见面,欢迎大家批评指正,我们互相学习。

本文发布:Android开发网
本文地址:http://www.jizhuomi.com/android/course/676.html
2017年5月10日
发布:鸡啄米 分类:Android开发教程 浏览: 评论:0