Android5.0 vold-启动过程

作者: Hly_Coder | 来源:发表于2016-07-21 19:36 被阅读956次

    转载请标明出处:http://www.jianshu.com/users/183339cdc7ae/latest_articles

    概述

    该篇文章主要讲解vold是如何启动的,以及内部组件间的关系

    相关文章

    Android5.0 vold-整体架构
    Android5.0 vold-注册过程(上)
    Android5.0 vold-注册过程(下)

    启动流程

    vold整体架构可以知道, vold是个native程序,并且有三部分组成,首先来看下这个程序的入口

    程序入口

    android系统的启动会先去解析init.rc文件,所以首先来看看init.rc

    service vold /system/bin/vold
        class core
        socket vold stream 0660 root mount
        ioprio be 2
    

    从init.rc (/system/core/rootdir/init.rc)里面可以看出,vold可执行文件位置在手机系统的/system/bin/vold.
    那/system/bin/vold这个可执行程序是由哪些c文件编译而成的,让我们再来看看它的mk文件,位于/system/vold/Android.mk

    LOCAL_SRC_FILES := \
        main.cpp \
        $(common_src_files)
    LOCAL_MODULE := libvold
    

    这样就根据init.rc和Android.mk文件找到vold的入口是在源码目录system/vold/main.cpp里面

    对象实例化

    首先来看看main.cpp的main函数

    int main() {
       ...   
      /* Create our singleton managers */   
      if (!(vm = VolumeManager::Instance())) {       
          SLOGE("Unable to create VolumeManager");     
          exit(1);   
      };
        
      if (!(nm = NetlinkManager::Instance())) {       
         SLOGE("Unable to create NetlinkManager");       
         exit(1);    
      };
    
      cl = new CommandListener();
      vm->setBroadcaster((SocketListener *) cl);    
      nm->setBroadcaster((SocketListener *) cl);
       
      if (vm->start()) {
           SLOGE("Unable to start VolumeManager (%s)", strerror(errno));       
           exit(1);   
      }
        
      if (process_config(vm)) {       
          SLOGE( "Error reading configuration (%s)... continuing anyways",strerror(errno));    
      }
      ...  
      if (nm->start()) {       
          SLOGE("Unable to start NetlinkManager (%s)", strerror(errno));
          exit(1);   
      }
      ... 
      if (cl->startListener()) {       
        SLOGE("Unable to start CommandListener (%s)", strerror(errno));       
        exit(1);   
      }
    }
    

    看Instance方法名就可以得知,vm和nm使用了单例模式实例化了对象,跳过他们,来看看new CommandListener做了些什么事情.
    在new CommandListener的时候,这里会先调用父类FrameworkListener的构造方法,然后在注册需要监听的命令(registerCmd),如果没有注册,systemserver发过来的命令是无法获取的

    CommandListener::CommandListener():FrameworkListener("vold", true) {    
        registerCmd(new DumpCmd());    
        ...  
        registerCmd(new FstrimCmd());
    };
    

    因为FrameworkListener又是继承自SocketListener,再来看看SocketListener的构造方法

    FrameworkListener::FrameworkListener(constchar*socketName, boolwithSeq) : SocketListener(socketName, true, withSeq) {    
           init(socketName, withSeq);}
    
    SocketListener::SocketListener(constchar*socketName, boollisten{    
           init(socketName, -1, listen, false);
    }
    

    init函数并没有做实际的事情,只是实例化了一些对象以备后面使用
    接着往后看,查看源码可以发现,vm->start()并没有做什么事情,而是直接返回了0.
    那我们来看看process_config做了什么事情

    加载配置

    process_config函数如下

    #define FSTAB_PREFIX "/fstab."
    static int process_config(VolumeManager *vm) {  
        ...    
        property_get("ro.hardware", propbuf, "");    
        snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);    
        fstab = fs_mgr_read_fstab(fstab_filename);  
          ... 
        /* Loop through entries looking for ones that vold manages */    
        for(i = 0; i < fstab->num_entries; i++) {       
              if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {           
                 DirectVolume *dv = NULL;           
                   ...            
                  vm->addVolume(dv);        
              }    
        }
    }
    

    通过getprop命令可以知道ro.hardware的值为qcom,所以这里fstab_filename为fstab.qcom(注:这里可能根据不同的厂商会有不同的fstab文件)。
    通过调用fs_mgr_read_fstab函数,得到一个fatab的结构体。然后遍历fstab的每一行,把每一个挂载分区实例化一个DirectVolume对象 然后加入到VolumeManager的管理中去。
    来看看fstab长什么样子

    # Android fstab file.
    #<src>                                                  <mnt_point>         <type>    <mnt_flags and options>                              <fs_mgr_flags>
    # The filesystem that contains the filesystem checker binary (typically /system) cannot
    # specify MF_CHECK, and must come before any filesystems that do specify MF_CHECK
    /dev/block/mtdblock0                                    /system             ext4      ro,barrier=1                                         wait
    /dev/block/mtdblock1                                    /data               ext4      noatime,nosuid,nodev,barrier=1,nomblk_io_submit      wait,check
    /dev/block/mtdblock2                                    /cache              ext4      noatime,nosuid,nodev  wait,check
    /devices/platform/goldfish_mmc.0                        auto                vfat      defaults                                             voldmanaged=sdcard:auto
    

    开始监听

    VolumeManager

    经过前面一系列的操作,该实例化的对象已经实例化好了,需要做的准备工作也已经完成了,现在是万事俱备只欠东风了。
    我们来看下开启整个系统运作的按钮cl->startListener, startListener的实现是在父类SocketListener里面

    int SocketListener::startListener(intbacklog) {   
         ... 
        if ((mSock = android_get_control_socket(mSocketName)) < 0) {    
              ...    
              if (mListen && listen(mSock, backlog) < 0) {   
                   ...    
                   if(pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {   
                            ...
                   }
             }
       }
    }
    

    这里mSocketName的值为vold,也就是前面FrameworkListener中传进来的参数通过调用android_get_control_socket函数产生一个socket文件,并且调用listen方法监听,这里是基本的socket通信的写法。 然后启用了一个线程pthread_create,并且执行了threadStart方法,threadStart方法也只是执行了runListener方法而已

    void SocketListener::runListener() {    
        while(1) {
              ...        
              int fd = (*it)->getSocket();       
              ...
              if((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0 {            
                    ...            
                   sleep(1);           
                     continue;        
              } else if (!rc)        ...          
                   c = accept(mSock, &addr, &alen);        
                   ...
                   mClients->push_back(newSocketClient(c, true,mUseCmdNum));       
             }        
                    ...          
                    SocketClient* c = *it;       
                    ...
                    if(!onDataAvailable(c)) {
                        release(c, false);          
                    }
    }
    

    这里就是等待socket的写端写入数据,然后读出相应的数据(eg 之前通过registerCmd注册的一些命令)做相应的操作这个方法很简单,当写入端有数据写入的时候,accept方法会得到写入的数据,封装为一个SocketClient对象然后调用onDataAvailable方法来处理得到的数据值得一提的是为了达到节省CPU的效果,这里使用了select方法,该方法会使线程阻塞住,直到read_fds有数据的时候才唤醒.

    onDataAvailable的实现是在子类FrameworkListener中,最终会调用dispatchCommand方法
    该方法又最终会调用之前注册的命令的runCommand方法这里
    vold的VolumeManager大致流程)已经讲完了

    NetlinkManager

    NetlinkManager和VolumeManager十分相似,都只是做了一个监听的动作,我们来看看实现,从它的start方法看起还是使用了socket方法建立一个socket,bind一个地址,在实例化一个NetlinkHandler对象

    int NetlinkManager::start() {    
          ... 
           if((mSock = socket(PF_NETLINK, SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0){    
            ...    
              if (setsockopt (mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {    ...    
              if (setsockopt (mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {    ...    
              if (bind (mSock, (structsockaddr *) &nladdr, sizeof(nladdr)) < 0) {   
                   ...
                  mHandler = new NetlinkHandler(mSock);   
                   if(mHandler->start()) {   
                   ...
    }
    

    查看代码可以发现NetlinkHandler继承自NetlinkHandler,而NetlinkHandler又是继承自SocketListener的。这和VolumeManager的结构十分相似

    NetlinkHandler::NetlinkHandler(intlistenerSocket) : NetlinkListener(listenerSocket){
    }
    NetlinkListener::NetlinkListener(intsocket) : SocketListener(socket, false) {    
          mFormat = NETLINK_FORMAT_ASCII;
    }
    

    NetlinkHandler的start方法最终会调用到SocketListener的startListener方法
    这个方法在之前已经做过介绍,这里不在讲解,主要作用就是监听socket端口,当有信息的时候调用onDataAvailable方法
    这里会将mBuffer的值封装为一个NetlinkEvent对象,然后调用onEvent
    onEvent最终会调用到VolumeManager的handleBlockEvent方法

    bool NetlinkListener::onDataAvailable(SocketClient *cli){   
         ...
         count =TEMP_FAILURE_RETRY(
                          uevent_kernel_multicast_uid_recv(  socket, mBuffer, sizeof(mBuffer), &uid));    
        ...    
        NetlinkEvent *evt = newNetlinkEvent();    
        if (evt->decode(mBuffer, count, mFormat)){       
               onEvent(evt);   
         }   
         ...
    }
    
    voidNetlinkHandler::onEvent(NetlinkEvent *evt) {   
         VolumeManager *vm = VolumeManager::Instance();    
          ...   
         vm->handleBlockEvent(evt);
    }
    

    我们来看看VolumeManager的handleBlockEvent方法
    这里遍历了mVolumes,分别调用每个volume对象的handleBlockEvent方法
    前面已经讲过process_config方法会解析fstab.qcom文件,并调用VolumeManager的addVolume添加volume
    每一个volume都是DirectVolume,所以最后调用到DirectVolume的handleBlockEvent方法

    static int process_config (VolumeManager *vm){ 
         ...  
         DirectVolume *dv = NULL;  
         ...  
         vm->addVolume(dv);
    }
    void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {   
         ... 
         for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {       
              if(!(*it)->handleBlockEvent(evt)) {   
                  ..
              }
          }
    }
    

    handleBlockEvent会根据kernel传递过来的NetlinkEvent中的action做出相应的动作然后调用sendBroadcast通知上层kernel发出的信号

    int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {
        ...
        int action = evt->getAction();
        ...
        if (action == NetlinkEvent::NlActionAdd) {
              ...
        if (!strcmp(devtype, "disk")) {
            handleDiskAdded(dp, evt);
        } else {
            handlePartitionAdded(dp, evt);
        }s
        mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,msg, false);
          ...
        } else if (action == NetlinkEvent::NlActionRemove) {
            ...
        }else  if (action == NetlinkEvent::NlActionChange) {
        ...
       }
    }
    

    流程图

    一图胜千言,上文中有关键的代码流程,可以结合流程图来看才能有一个整体的概念


    start_brief.jpeg

    相关文章

      网友评论

        本文标题:Android5.0 vold-启动过程

        本文链接:https://www.haomeiwen.com/subject/gxbbjttx.html