Vold工作流程分析學習

一 Vold工作機制分析

         vold進程:管理和控制Android平台外部存儲設備,包括SD插撥、掛載、卸載、格式化等;

         vold進程接收來自內核的外部設備消息。

Vold框架圖如下:

    Vold工作流程分析學習_第1张图片

 

         Vold接收來自內核的事件,通過netlink機制。

         Netlink 是一種特殊的 socket;

         Netlink 是一種在內核與用戶應用間進行雙向數據傳輸的非常好的方式,用戶態應用使用標准的socket API 就可以使用 netlink 提供的強大功能;

         Netlink是一種異步通信機制,在內核與用戶態應用之間傳遞的消息保存在socket緩存隊列中;

內核通過Netlink發送uEvent格式消息给用戶空間程序;外部設備發生變化,Kernel發送uevent消息。

二 Vold進程启動過程

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

vold進程執行過程:

         \system\vold\main.cpp

int main() 
{
        VolumeManager *vm;
        CommandListener *cl;
        NetlinkManager *nm;
        //創建vold設備文件夾
        mkdir("/dev/block/vold", 0755);
        
        //初始化Vold相關的類實例 single
        vm = VolumeManager::Instance();
        nm = NetlinkManager::Instance();
        
        //CommandListener 創建vold socket監聽上層消息
        cl = new CommandListener();
        vm->setBroadcaster((SocketListener *) cl);
        nm->setBroadcaster((SocketListener *) cl);
        
        //启動VolumeManager 
        vm->start();
        
        //根據配置文件/etc/vold.fstab 初始化VolumeManager 
        process_config(vm);
        
        //启動NetlinkManager socket監聽內核發送uevent
        nm->start();
        
        //向/sys/block/目錄下所有設備uevent文件寫入“add\n”,
        //觸發內核sysfs發送uevent消息
        coldboot("/sys/block");
        
        //启動CommandListener監聽vold socket
        cl->startListener();
        
        // Eventually we'll become the monitoring thread
        while(1) {
            sleep(1000);
        }
        
        exit(0);
} 

process_config解析vold.fstab文件:

static int process_config(VolumeManager *vm) {
        //打開vold.fstab的配置文件
        fp = fopen("/etc/vold.fstab", "r")
        //解析vold.fstab 配置存儲設備的掛載點
    while(fgets(line, sizeof(line), fp)) {
        const char *delim = " \t";
        char *type, *label, *mount_point, *part, *mount_flags, *sysfs_path;

        type = strtok_r(line, delim, &save_ptr)
        label = strtok_r(NULL, delim, &save_ptr)
        mount_point = strtok_r(NULL, delim, &save_ptr)
              //判斷分區 auto沒有分區
        part = strtok_r(NULL, delim, &save_ptr)
        if (!strcmp(part, "auto")) {
             //創建DirectVolume對象 相關的掛載點設備的操作
           dv = new DirectVolume(vm, label, mount_point, -1);
        } else {
           dv = new DirectVolume(vm, label, mount_point, atoi(part));
        }
                //添加掛載點設備路徑
        while ((sysfs_path = strtok_r(NULL, delim, &save_ptr))) {
            dv->addPath(sysfs_path)
        }
              //將DirectVolume 添加到VolumeManager管理
              vm->addVolume(dv);
    }

    fclose(fp);
    return 0;
}

vold.fstab文件:

  導出一個我的手機裏面的vold.fstab文件 內容:

dev_mount sdcard /mnt/sdcard emmc@fat /devices/platform/goldfish_mmc.0 /devices/platform/mtk-sd.0/mmc_host

dev_mount external_sdcard /mnt/sdcard/external_sd auto /devices/platform/goldfish_mmc.1 /devices/platform/mtk-sd.1/mmc_host

 

  vold.fstab格式是:

         type         label        mount_point part         sysfs_path      sysfs_path

  sysfs_path可以有多個 part指定分區個數,如果是auto沒有分區

三 Vold中各模塊分析

         在vold進程main函數中創建了很多的類實例,並將其启動。

int main()
{
         ……
         vm->start();
         nm->start();
         cl->startListener();
}

這些類對象之間是如何的,還需要現弄清楚每個類的職責和工作機制。

1 NetlinkManager模塊

  NetlinkManager模塊接收從Kernel發送的Uevent消息,解析轉換成NetlinkEvent對象;再將此NetlinkEvent對象傳遞给VolumeManager處理。

此模塊相關的類結構:

    

 

下面從start開始,看起如何對Kernel的Uevent消息進行監控的。

NetlinkManager start:

int NetlinkManager::start() {
    //netlink使用的socket結構
    struct sockaddr_nl nladdr;
        
    //初始化socket數據結構
    memset(&nladdr, 0, sizeof(nladdr));
    nladdr.nl_family = AF_NETLINK;
    nladdr.nl_pid = getpid();
    nladdr.nl_groups = 0xffffffff;
    //創建socket PF_NETLINK類型
    mSock = socket(PF_NETLINK,SOCK_DGRAM,NETLINK_KOBJECT_UEVENT);
    //配置socket 大小
    setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz);
    setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on);
    //bindsocket地址
    bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr);
        
    //創建NetlinkHandler 傳遞socket標識,並启動
    mHandler = new NetlinkHandler(mSock);
    mHandler->start();
    return 0;
} 

NetlinkHandler start:

int NetlinkHandler::start() {
    //父類startListener
    return this->startListener();
}

NetlinkListener start:

int SocketListener::startListener() {
   //NetlinkHandler mListen为false 
    if (mListen && listen(mSock, 4) < 0) {
        return -1;
    } else if (!mListen){
        //mListen为false 用於netlink消息監聽
        //創建SocketClient作为SocketListener 的客戶端 
        mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));
    }

    //創建匿名管道
    pipe(mCtrlPipe);
    //創建線程執行函數threadStart    参this
    pthread_create(&mThread, NULL, SocketListener::threadStart, this);
}

線程監聽Kernel netlink發送的UEvent消息:     

void *SocketListener::threadStart(void *obj) {

    //参數轉換
    SocketListener *me = reinterpret_cast<SocketListener *>(obj);

    me->runListener();

    pthread_exit(NULL);

    return NULL;

}

SocketListener 線程消息循環:

void SocketListener::runListener() {
        //SocketClient List
    SocketClientCollection *pendingList = new SocketClientCollection();

    while(1) {
        fd_set read_fds;
        //mListen 为false
        if (mListen) {
            max = mSock;
            FD_SET(mSock, &read_fds);
        }
        //加入一組文件描述符集合 選擇fd最大的max
        FD_SET(mCtrlPipe[0], &read_fds);
        pthread_mutex_lock(&mClientsLock);
        for (it = mClients->begin(); it != mClients->end(); ++it) {
            int fd = (*it)->getSocket();
            FD_SET(fd, &read_fds);
            if (fd > max)
                max = fd;
        }
        pthread_mutex_unlock(&mClientsLock);
        
        //監聽文件描述符是否變化
        rc = select(max + 1, &read_fds, NULL, NULL, NULL);
        //匿名管道被寫,退出線程
        if (FD_ISSET(mCtrlPipe[0], &read_fds))
            break;
        //mListen 为false
        if (mListen && FD_ISSET(mSock, &read_fds)) {
                //mListen 为ture 表示正常監聽socket
            struct sockaddr addr;
            do {
                //接收客戶端連接
                c = accept(mSock, &addr, &alen);
            } while (c < 0 && errno == EINTR);
            
            //此處創建一個客戶端SocketClient加入mClients列表中,異步延遲處理
            pthread_mutex_lock(&mClientsLock);
            mClients->push_back(new SocketClient(c, true, mUseCmdNum));
            pthread_mutex_unlock(&mClientsLock);
        }

        /* Add all active clients to the pending list first */
        pendingList->clear();
        //將所有有消息的Client加入到pendingList中
        pthread_mutex_lock(&mClientsLock);
        for (it = mClients->begin(); it != mClients->end(); ++it) {
            int fd = (*it)->getSocket();
            if (FD_ISSET(fd, &read_fds)) {
                pendingList->push_back(*it);
            }
        }
        pthread_mutex_unlock(&mClientsLock);

        //處理所有消息
        while (!pendingList->empty()) {
            it = pendingList->begin();
            SocketClient* c = *it;
            pendingList->erase(it);
               //處理有數據發送的socket 虛函數
            if (!onDataAvailable(c) && mListen) {
               //mListen为false
            }
        }
    }
}

Netlink消息處理:

Vold工作流程分析學習_第2张图片

 

  在消息循環中調用onDataAvailable處理消息,onDataAvailable是個虛函數,NetlinkListener重寫了此函數。

NetlinkListener onDataAvailable消息處理:

bool NetlinkListener::onDataAvailable(SocketClient *cli)
{
    //獲取socket id
    int socket = cli->getSocket();
    //接收netlink uevent消息
    count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_uid_recv(
                                 socket, mBuffer, sizeof(mBuffer), &uid));
    //解析uevent消息为NetlinkEvent消息
    NetlinkEvent *evt = new NetlinkEvent();
    evt->decode(mBuffer, count, mFormat);
    
    //處理NetlinkEvent onEvent虛函數
 onEvent(evt);
}

    將接收的Uevent數據轉化成NetlinkEvent數據,調用onEvent處理,NetlinkListener子類NetlinkHandler重寫了此函數。

NetlinkHandler NetlinkEvent數據處理:

void NetlinkHandler::onEvent(NetlinkEvent *evt) {

    //獲取VolumeManager實例
    VolumeManager *vm = VolumeManager::Instance();

    //設備類型
    const char *subsys = evt->getSubsystem();

                  

    //將消息傳遞给VolumeManager處理
    if (!strcmp(subsys, "block")) {
        vm->handleBlockEvent(evt);

    }

}

    NetlinkManager通過NetlinkHandler將接收到Kernel內核發送的Uenvet消息,

  轉化成了NetlinkEvent結構數據傳遞给VolumeManager處理。

2 VolumeManager模塊

  此模塊管理所有掛載的設備節點以及相關操作執行;下面是VolumeManager模塊類結構圖:

 

    Vold工作流程分析學習_第3张图片

 

    DirectVolume:一個實體存儲設備在代碼中的抽象。

    SocketListenner:創建線程,監聽socket。

  這裏VolumeManager構造的SocketListenner與NetlinkManager構造的SocketListenner有所不同的:

    NetlinkManager構造的SocketListenner:Kernel與Vold通信;

    VolumeManager構造的SocketListenner:Native Vold與Framework MountService 通信;

  VolumeManager構造的SocketListenner,由vold進程main函數中創建的CommandListener:

 int main() {
         ……

         CommandListener *cl;
         cl = new CommandListener();

        vm->setBroadcaster((SocketListener *) cl);

        //启動CommandListener監聽
        cl->startListener();

}          

VolumeManager工作流程:

//從main函數中的start開始:
int VolumeManager::start() {
    return 0;
}

  NetlinkManager接收到Kernel通過netlink發送的Uevent消息,轉化成了NetlinkEvent消息,再傳遞给了VolumeManager處理。

NetlinkManager與VolumeManager交互流程圖:

    

 

VolumeManager處理消息 handleBlockEvent:

  從NetlinkManager到VolumeManager代碼過程

  函數執行從onEvent到handleBlockEvent:

    void NetlinkHandler::onEvent(NetlinkEvent *evt) {
        ……
            //將消息傳遞给VolumeManager處理
        if (!strcmp(subsys, "block")) {
            vm->handleBlockEvent(evt);
        }
    }
    void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
        //有狀態變化設備路徑
      const char *devpath = evt->findParam("DEVPATH");

      //遍曆VolumeManager中所管理Volume對象(各存儲設備代碼抽象)
      for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
          if (!(*it)->handleBlockEvent(evt)) {
              hit = true;
              break;
          }
    }
}

將消息交给各個Volume對象處理:DirectVolume

  從VolumeManager到所管理的Volume對象

    這裏的Volume为其派生類DirectVolume。

int DirectVolume::handleBlockEvent(NetlinkEvent *evt) 
{
    //有狀態變化設備路徑
    const char *dp = evt->findParam("DEVPATH");
    PathCollection::iterator  it;
    for (it = mPaths->begin(); it != mPaths->end(); ++it) {
        //匹配 設備路徑 
        if (!strncmp(dp, *it, strlen(*it))) {
            int action = evt->getAction();
            const char *devtype = evt->findParam("DEVTYPE");
            //動作判斷
            if (action == NetlinkEvent::NlActionAdd) {
                int major = atoi(evt->findParam("MAJOR"));
                int minor = atoi(evt->findParam("MINOR"));
                char nodepath[255];
                //設備節點路徑名稱
                snprintf(nodepath,sizeof(nodepath), "/dev/block/vold/%d:%d",
                         major, minor);

                //創建設備節點
                createDeviceNode(nodepath, major, minor);
                if (!strcmp(devtype, "disk")) {
                    //添加disk
 handleDiskAdded(dp, evt);
                } else {
                    //添加分區
 handlePartitionAdded(dp, evt);
                }
            } else if (action == NetlinkEvent::NlActionRemove) {
               
            } else if (action == NetlinkEvent::NlActionChange) {
               
            } else {
                SLOGW("Ignoring non add/remove/change event");
            }
            return 0;
        }
    }
}

     为什麼要讓VolumeManager中的每一個Volume對象都去處理SD狀態變換消息,

  每一個Volume可能對應多個Path;即一個掛載點對應多個物理設備。

抽象存儲設備DirectVolume 動作狀態變化處理:

void DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt) {
    //主次設備號
    mDiskMajor = atoi(evt->findParam("MAJOR"));
    mDiskMinor = atoi(evt->findParam("MINOR"));
        
    //設備分區情況
    const char *tmp = evt->findParam("NPARTS");
  mDiskNumParts = atoi(tmp);
    
    if (mDiskNumParts == 0) {
        //沒有分區,Volume狀態为Idle
        setState(Volume::State_Idle);
    } else {
        //有分區未加載,設置Volume狀態Pending
        setState(Volume::State_Pending);
    }
    //格式化通知msg:"Volume sdcard /mnt/sdcard disk inserted (179:0)"
    char msg[255];
    snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)",
             getLabel(), getMountpoint(), mDiskMajor, mDiskMinor);
    //調用VolumeManager中的Broadcaster——>CommandListener 發送此msg
    mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,
                                        msg, false);
}

消息通知Framework層存儲設備狀態變化:

  類繼承關系:

    Vold工作流程分析學習_第4张图片

 

  發送消息通知Framework層是在SocketListener中完成;

void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) 
{
    pthread_mutex_lock(&mClientsLock);
    //遍曆所有的消息接收時創建的Client SocketClient
    // SocketClient將消息通過socket(“vold”)通信
    for (i = mClients->begin(); i != mClients->end(); ++i) {
        (*i)->sendMsg(code, msg, addErrno, false);
    }
    pthread_mutex_unlock(&mClientsLock);
}

  這裏工作的SocketListener是VolumeManager的,SocketListener的派生類CommandListener,

用來與Framework交互的,監聽Socket消息。通過VolumeManager中調用sendBroadcast,與CommandListener模塊進行交互。

由此需要清楚CommandListener模塊工作流程。

 

3 CommandListener模塊

  CommandListener監聽Socket,使Vold與Framework層進行進程通信;

其相關類繼承結構圖如下:

    Vold工作流程分析學習_第5张图片

 

CommandListener工作流程:

int main() 
{
    VolumeManager *vm;
    CommandListener *cl;
    NetlinkManager *nm;
  
     //CommandListener 創建vold socket監聽上層消息
    cl = new CommandListener();
  
    //作为VolumeManager與NetlinkManager的Broadcaster
    vm->setBroadcaster((SocketListener *) cl);
    nm->setBroadcaster((SocketListener *) cl);
    
     //启動CommandListener監聽
    cl->startListener();
    ……
}

CommandListener實例的創建:構造函數

         CommandListener構造函數:

  CommandListener::CommandListener() :
                FrameworkListener("vold", true) {

    //注冊Framework發送的相關命令 Command模式

    registerCmd(new DumpCmd());

    registerCmd(new VolumeCmd());

    registerCmd(new AsecCmd());

    registerCmd(new ObbCmd());

    registerCmd(new StorageCmd());

    registerCmd(new XwarpCmd());

    registerCmd(new CryptfsCmd());

}        

 

 

 

FrameworkListener構造函數:

FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :

                            SocketListener(socketName, true, withSeq) {

    mCommands = new FrameworkCommandCollection();

    mWithSeq = withSeq;

}

注冊Command:

void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
    mCommands->push_back(cmd);
}

SocketListener構造函數:

SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) {

    //mListen = true 正常的socket監聽
    mListen = listen;

    //socket 名稱“vold”
    mSocketName = socketName;

    mSock = -1;

    mUseCmdNum = useCmdNum;

    //初始化锁
    pthread_mutex_init(&mClientsLock, NULL);

    //構造Listener Client List
    mClients = new SocketClientCollection();

}

CommandListener启動 startListener:

int SocketListener::startListener() {
    //mSocketName = “Vold”
    mSock = android_get_control_socket(mSocketName);
        
    //NetlinkHandler mListen为true 監聽socket
    if (mListen && < 0) {
        return -1;
    } else if (!mListen){
        mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));
    }
        
    //創建匿名管道
    pipe(mCtrlPipe);
    //創建線程執行函數threadStart 参數this
    pthread_create(&mThread, NULL, SocketListener::threadStart, this);
}

void *SocketListener::threadStart(void *obj) {
    SocketListener *me = reinterpret_cast<SocketListener *>(obj);
    me->runListener();
}

void SocketListener::runListener() {
    //SocketClient List
    SocketClientCollection *pendingList = new SocketClientCollection();

    while(1) {
        fd_set read_fds;
                //mListen 为true
        if (mListen) {
            max = mSock;
            FD_SET(mSock, &read_fds);
        }
                //加入一組文件描述符集合 選擇fd最大的max select有關
        FD_SET(mCtrlPipe[0], &read_fds);
        pthread_mutex_lock(&mClientsLock);
        for (it = mClients->begin(); it != mClients->end(); ++it) {
            int fd = (*it)->getSocket();
            FD_SET(fd, &read_fds);
            if (fd > max)
                max = fd;
        }
        pthread_mutex_unlock(&mClientsLock);
        
        //監聽文件描述符是否變化
        rc = select(max + 1, &read_fds, NULL, NULL, NULL);
        //匿名管道被寫,退出線程
        if (FD_ISSET(mCtrlPipe[0], &read_fds))
            break;

        //mListen 为true
        if (mListen && FD_ISSET(mSock, &read_fds)) {
            //mListen 为ture 表示正常監聽socket
            struct sockaddr addr;
            do {
                c = accept(mSock, &addr, &alen);
            } while (c < 0 && errno == EINTR);
            
            //創建一個客戶端SocketClient,加入mClients列表中 到異步延遲處理
            pthread_mutex_lock(&mClientsLock);
            mClients->push_back(new SocketClient(c, true, mUseCmdNum));
            pthread_mutex_unlock(&mClientsLock);
        }

        /* Add all active clients to the pending list first */
        pendingList->clear();
        //將所有有消息的Client加入到pendingList中
        pthread_mutex_lock(&mClientsLock);
        for (it = mClients->begin(); it != mClients->end(); ++it) {
            int fd = (*it)->getSocket();
            if (FD_ISSET(fd, &read_fds)) {
                pendingList->push_back(*it);
            }
        }
        pthread_mutex_unlock(&mClientsLock);

        /* Process the pending list, since it is owned by the thread,*/
        while (!pendingList->empty()) {
            it = pendingList->begin();
            SocketClient* c = *it;
               //處理有數據發送的socket 
            if (!onDataAvailable(c) && mListen) {
               //mListen为true
               ……
            }
        }
    }
} 

  CommandListener启動的線程監聽Socket消息,接收到的消息處理onDataAvailable。

CommandListener父類FrameworkCommand重寫了此函數。

CommandListener監聽Socket消息處理:

bool FrameworkListener::onDataAvailable(SocketClient *c) {
    char buffer[255];
    //讀取socket消息
    len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));
    for (i = 0; i < len; i++) {
        if (buffer[i] == '\0') {
            //根據消息內容 派發命令
            dispatchCommand(c, buffer + offset);
            offset = i + 1;
        }
    }
    return true;
}

void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
   char *argv[FrameworkListener::CMD_ARGS_MAX];
    //解析消息內容 命令 参數
    ……
    
    //執行對應的消息
    for (i = mCommands->begin(); i != mCommands->end(); ++i) {
        FrameworkCommand *c = *i;
        //匹配命令
        if (!strcmp(argv[0], c->getCommand())) {
            //執行命令
            c->runCommand(cli, argc, argv);
            goto out;
        }
    }
out:
        return;
}

Command執行處理:以VolumeCommand为例 

CommandListener::VolumeCmd::VolumeCmd() :
                 VoldCommand("volume") {
}

int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
                                int argc, char **argv) {
        
    //獲取VolumeManager實例
    VolumeManager *vm = VolumeManager::Instance();
    //Action判斷 傳遞给VolumeManager處理
    if (!strcmp(argv[1], "list")) {
        return vm->listVolumes(cli);
    } else if (!strcmp(argv[1], "debug")) {
        vm->setDebug(!strcmp(argv[2], "on") ? true : false);
    } else if (!strcmp(argv[1], "mount")) {
        rc = vm->mountVolume(argv[2]);
    } else if (!strcmp(argv[1], "unmount")) {
        rc = vm->unmountVolume(argv[2], force, revert);
    } else if (!strcmp(argv[1], "format")) {
        rc = vm->formatVolume(argv[2]);
    } else if (!strcmp(argv[1], "share")) {
        rc = vm->shareVolume(argv[2], argv[3]);
    } else if (!strcmp(argv[1], "unshare")) {
        rc = vm->unshareVolume(argv[2], argv[3]);
    } else if (!strcmp(argv[1], "shared")) {
       ……

    return 0;
}

    CommandListener使用Command模式。

  CommandListener接收到來自Framework層得消息,派發命令處理,再傳遞给VolumeManager處理。

VolumeManager中Action處理:

int VolumeManager::unmountVolume(const char *label) {
  //查找Volume
  Volume *v = lookupVolume(label);
  //Volume執行動作
    return v-> unmountVol ();
}
//VolumeAction處理:
int Volume::unmountVol(bool force, bool revert) {
    doUnmount(Volume::SEC_STG_SECIMGDIR, force);
        ……
}

int Volume::doUnmount(const char *path, bool force) {
    ……
    //systemcall
    umount(path);
}

整個Vold處理過程框架圖如下:

    Vold工作流程分析學習_第6张图片

你可能感兴趣的:(Vold工作流程分析學習)