vold挂载管理

来源:互联网 发布:linux echo 串口 编辑:程序博客网 时间:2024/05/16 13:01

看了很长时间Vold存储模块的相关知识,也深入的研究一段时间的Android源码,打算把自己看过的经验之贴、参考资料和自己的一些见解,以帖子的形式发出来,供有兴趣的同仁们参考,有不对的地方请指正,我们相互交流。

1.1 vold的原理与机制分析

1.1.1 Vold 架构


从上图中可知:

·  Vold中的NetlinkManager模块接收来自Linux内核的uevent消息。例如SD卡的插拔等动作都会引起Kernel向NM发送uevent消息。

·  NetlinkManager将这些消息转发给VolumeManager模块。VolumeManager会对应做一些操作,然后把相关信息通过CommandListener发送给MountService,MountService根据收到的消息会发送相关的处理命令给VolumeManager做进一步的处理。例如待SD卡插入后,VolumeManager会将来自NetlinkManager的“Disk Insert”消息发送给MountService,而后MountService则发送“Mount”指令给Vold,指示它挂载这个SD卡。

·  CommandListener模块内部封装了一个Socket用于跨进程通信。它在Vold进程中属于监听端(即是服务端),而它的连接端(即客户端)则是MountService。它一方面接收来自MountService的控制命令(例如卸载存储卡、格式化存储卡等),另一方面VolumeManagerNetlinkManager模块又会通过它,将一些信息发送给MountService。

1.1.2初识Vold

下面来初步的认识Vold,代码在system\vold\main.cpp

int main() {    mkdir("/dev/block/vold", 0755);  //创建一个目录/dev/block/vold  //创建一个VolumeManager对象,该对象为单例模式    if (!(vm = VolumeManager::Instance())) {        SLOGE("Unable to create VolumeManager");        exit(1);    };  //创建一个NetlinkManager对象,该对象为单例模式    if (!(nm = NetlinkManager::Instance())) {        SLOGE("Unable to create NetlinkManager");        exit(1);    };  //创建一个CommandListener对象    cl = new CommandListener();    vm->setBroadcaster((SocketListener *) cl);    nm->setBroadcaster((SocketListener *) cl);//启动VolumeManager    if (vm->start()) {        SLOGE("Unable to start VolumeManager (%s)", strerror(errno));        exit(1);    }//根据fstab配置文件初始化VolumeManager    if (process_config(vm)) {        SLOGE("Error reading configuration (%s)... continuing anyways", strerror(errno));    }//启动NetlinkManager对象    if (nm->start()) {        SLOGE("Unable to start NetlinkManager (%s)", strerror(errno));        exit(1);    }//通过往/sys/block目录下对应的uevent文件写“add\n”来触发内核发送Uevent消息    coldboot("/sys/block");//启动CommandListener    if (cl->startListener()) {        SLOGE("Unable to start CommandListener (%s)", strerror(errno));        exit(1);    }}

1.2 NetlinkManager模块的分析

1.2.1 NetlinkManager架构流程图



上图中的虚线为启动是的调用流程。
 (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来读取数据)

1.2.2 start的分析

NetlinkManager模块将使用Netlink套接字实现用户进程与内核进程通信的一种特殊的进程间通信(IPC) ,一起看下面代码
int NetlinkManager::start() {      struct sockaddr_nl nladdr;      int sz = 64 * 1024;      int on = 1;      memset(&nladdr, 0, sizeof(nladdr));      nladdr.nl_family = AF_NETLINK;      nladdr.nl_pid = getpid();      nladdr.nl_groups = 0xffffffff;      // 创建一个socket用于内核空间和用户空间的异步通信,监控系统的hotplug事件      if ((mSock = socket(PF_NETLINK,                          SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {          SLOGE("Unable to create uevent socket: %s", strerror(errno));          return -1;      }      if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {          SLOGE("Unable to set uevent socket SO_RECBUFFORCE option: %s", strerror(errno));          return -1;      }      if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {          SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));          return -1;      }        if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {          SLOGE("Unable to bind uevent socket: %s", strerror(errno));          return -1;      }      // 利用新创建的socket实例化一个NetlinkHandler类对象,NetlinkHandler继承了类NetlinkListener,          // NetlinkListener又继承了类SocketListener          mHandler = new NetlinkHandler(mSock);      if (mHandler->start()) {  //启动NetlinkHandler          SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));          return -1;      }      return 0;  } 
NetlinkHandler构造

NetlinkHandler::NetlinkHandler(int listenerSocket) :                NetlinkListener(listenerSocket) {}
继承父类
NetlinkListener::NetlinkListener(int socket) :                            SocketListener(socket, false) {    mFormat = NETLINK_FORMAT_ASCII;}

这里又是构造了一个SockListener的实例,传入了上面创建的socket标识。

接着调用的start()函数,也是最终实现在SockListener的startListener()。

int NetlinkHandler::start() {      return this->startListener();  }    int SocketListener::startListener() {        if (!mSocketName && mSock == -1) {          SLOGE("Failed to start unbound listener");          errno = EINVAL;          return -1;      } else if (mSocketName) {          if ((mSock = android_get_control_socket(mSocketName)) < 0) {              SLOGE("Obtaining file descriptor socket '%s' failed: %s",                   mSocketName, strerror(errno));              return -1;          }      }        if (mListen && listen(mSock, 4) < 0) {          SLOGE("Unable to listen on socket (%s)", strerror(errno));          return -1;      } else if (!mListen)          mClients->push_back(new SocketClient(mSock, false));        if (pipe(mCtrlPipe)) {          SLOGE("pipe failed (%s)", strerror(errno));          return -1;      }        if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {          SLOGE("pthread_create (%s)", strerror(errno));          return -1;      }        return 0;  }    void *SocketListener::threadStart(void *obj) {      SocketListener *me = reinterpret_cast<SocketListener *>(obj);        me->runListener();      pthread_exit(NULL);      return NULL;  }    void SocketListener::runListener() {        SocketClientCollection *pendingList = new SocketClientCollection();        while(1) { // 死循环,一直监听          SocketClientCollection::iterator it;          fd_set read_fds;          int rc = 0;          int max = -1;            FD_ZERO(&read_fds); //清空文件描述符集read_fds             if (mListen) {              max = mSock;              FD_SET(mSock, &read_fds); //添加文件描述符到文件描述符集read_fds          }            FD_SET(mCtrlPipe[0], &read_fds); //添加管道的读取端文件描述符到read_fds          if (mCtrlPipe[0] > max)              max = mCtrlPipe[0];            pthread_mutex_lock(&mClientsLock); //对容器mClients的操作需要加锁          for (it = mClients->begin(); it != mClients->end(); ++it) {              int fd = (*it)->getSocket();              FD_SET(fd, &read_fds); ////遍历容器mClients的所有成员,调用内联函数getSocket()获取文件描述符,并添加到文件描述符集read_fds              if (fd > max)                  max = fd;          }          pthread_mutex_unlock(&mClientsLock);          // 等待文件描述符中某一文件描述符或者说socket有数据到来          if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {              if (errno == EINTR)                  continue;              SLOGE("select failed (%s)", strerror(errno));              sleep(1);              continue;          } else if (!rc)              continue;            if (FD_ISSET(mCtrlPipe[0], &read_fds))              break;          if (mListen && FD_ISSET(mSock, &read_fds)) { //监听套接字处理              struct sockaddr addr;              socklen_t alen;              int c;                do {                  alen = sizeof(addr);                  c = accept(mSock, &addr, &alen); //接收链接请求,建立连接,如果成功c即为建立链接后的数据交换套接字,将其添加到mClient容器              } while (c < 0 && errno == EINTR);              if (c < 0) {                  SLOGE("accept failed (%s)", strerror(errno));                  sleep(1);                  continue;              }              pthread_mutex_lock(&mClientsLock);              mClients->push_back(new SocketClient(c, true));              pthread_mutex_unlock(&mClientsLock);          }            /* Add all active clients to the pending list first */          pendingList->clear();          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,          * there is no need to lock it */          while (!pendingList->empty()) { //非监听套接字处理              /* Pop the first item from the list */              it = pendingList->begin();              SocketClient* c = *it;              pendingList->erase(it);              /* Process it, if false is returned and our sockets are              * connection-based, remove and destroy it */              // ****** onDataAvailable在NetlinkListener中实现*********               if (!onDataAvailable(c) && mListen) {                  /* Remove the client from our array */                  pthread_mutex_lock(&mClientsLock);                  for (it = mClients->begin(); it != mClients->end(); ++it) {                      if (*it == c) {                          mClients->erase(it);                          break;                      }                  }                  pthread_mutex_unlock(&mClientsLock);                  /* Remove our reference to the client */                  c->decRef();              }          }      }      delete pendingList;  }
SocketListener::runListener是线程真正执行的函数:mListen成员用来判定是否监听套接字,Netlink套接字属于udp套接字,非监听套接字,该函数的主要功能体现在,如果该套接字有数据到来,就调用函数onDataAvailable读取数据
bool NetlinkListener::onDataAvailable(SocketClient *cli){    int socket = cli->getSocket();    ssize_t count;    uid_t uid = -1;    count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_uid_recv(                                       socket, mBuffer, sizeof(mBuffer), &uid)); //从socket中读取event信息    if (count < 0) {        if (uid > 0)            LOG_EVENT_INT(65537, uid);        SLOGE("recvmsg failed (%s)", strerror(errno));        return false;    }    NetlinkEvent *evt = new NetlinkEvent();    if (!evt->decode(mBuffer, count, mFormat)) {   //调用NetlinkEvent解析event        SLOGE("Error decoding NetlinkEvent");    } else {        onEvent(evt);  //传递event给子类NetlinkHandler处理    }    delete evt;    return true;}

到NetlinkHandler.cpp中:
void NetlinkHandler::onEvent(NetlinkEvent *evt) {    VolumeManager *vm = VolumeManager::Instance();    const char *subsys = evt->getSubsystem();    if (!subsys) {        SLOGW("No subsystem found in netlink event");        return;    }    if (!strcmp(subsys, "block")) {   //EVENT为block类型        int action = evt->getAction();        vm->updatePullOutState(evt);        vm->setHotPlug(true);        vm->handleBlockEvent(evt);  //把event交给<span style="font-family: Arial; line-height: 26px;">VolumeManager处理</span>        vm->setHotPlug(false);    }

1.2.3 NM模块的总结

NM模块的功能就是从Kernel接收Uevent消息,然后转换成一个NetlinkEvent对象,最后会调用VM的处理函数来处理这个NetlinkEvent对象。

1.3 VolumeManager模块的分析

1.3.1 Vold使用VM模块的流程


  调用Instance创建一个VM对象。

  调用setBroadcaster设置CL对象

  调用start启动VM。

  调用process_config配置VM。

1.3.2 VM的创建

VolumeManager *VolumeManager::Instance() {    if (!sInstance)        sInstance = new VolumeManager();    return sInstance;}

VolumeManager::VolumeManager() {    mDebug = false;    mVolumes = new VolumeCollection();  //一个容器,保存<span style="color: rgb(85, 85, 85); font-family: 'microsoft yahei'; font-size: 15px; line-height: 35px;">Volume的集合</span>    mActiveContainers = new AsecIdCollection();    mBroadcaster = NULL;   //指向socketlisten,用于发送挂载事件    mUmsSharingCount = 0;    mSavedDirtyRatio = -1;    mUmsDirtyRatio = dirtyRatio();    mVolManagerDisabled = 0;    mIsHotPlug= false;    mUseBackupContainers =false;    mIsFirstBoot = false;    mIpoState = State_Ipo_Start;}

1.3.3 VM的启动

int VolumeManager::start() {    return 0;   //<span style="font-family: Arial; font-size: 14px; line-height: 26px;">VM的启动什么也没有做</span>}

1.3.4 process_config分析

这个函数用于解析指定的配置文件,根据内容构造DirectVolume以及父类然后保存进VolumeManager的容器中,供VolumeManager用于挂载事件的管理
static int process_config(VolumeManager *vm){    char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];    fstab = fs_mgr_read_fstab(fstab_filename);   //读取fstab文件    if (!fstab) {        SLOGE("failed to open %s\n", fstab_filename);        return -1;    }    /* 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;            flags = 0;             /* Set any flags that might be set for this volume */            if (fs_mgr_is_nonremovable(&fstab->recs[i])) {                flags |= VOL_NONREMOVABLE;            }            if (fs_mgr_is_encryptable(&fstab->recs[i])) {                flags |= VOL_ENCRYPTABLE;            }            /* Only set this flag if there is not an emulated sd card */            if (fs_mgr_is_noemulatedsd(&fstab->recs[i]) &&                !strcmp(fstab->recs[i].fs_type, "vfat")) {                flags |= VOL_PROVIDES_ASEC;            }            dv = new DirectVolume(vm, &(fstab->recs[i]), flags);            if (dv->addPath(fstab->recs[i].blk_device)) {                SLOGE("Failed to add devpath %s to volume %s",                      fstab->recs[i].blk_device, fstab->recs[i].label);                goto out_fail;            }            vm->addVolume(dv);  //添加到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/devices/platform/mtk-msdc.0/mmc_host   auto      vfat      defaults        voldmanaged=sdcard0:emmc@fat,noemulatedsd/devices/platform/mtk-msdc.1/mmc_host   auto      vfat      defaults        voldmanaged=sdcard1:auto


1.3.5 DirectVolume分析


DirectVolume从Volume类派生,可把它看成是一个外部存储卡(例如一张SD卡)在代码中的代表物。它封装了对外部存储卡的操作,例如加载/卸载存储卡、格式化存储卡等
DirectVolume构造
DirectVolume::DirectVolume(VolumeManager *vm,const char *label,                           const char*mount_point, int partIdx) :              Volume(vm, label, mount_point) {//初始化基类   /*      注意其中的参数:     label为”sdcard”,mount_point为”/mnt/sdcard”,partIdx为1    */   mPartIdx = partIdx;//PathCollection定义为typedef android::List<char *> PathCollection//其实就是一个字符串list    mPaths= new PathCollection();    for(int i = 0; i < MAX_PARTITIONS; i++)       mPartMinors[i] = -1;   mPendingPartMap = 0;   mDiskMajor = -1;  //存储设备的主设备号   mDiskMinor = -1;  //存储设备的次设备号,一个存储设备将由主次两个设备号标识。   mDiskNumParts = 0;   //设置状态为NoMedia   setState(Volume::State_NoMedia);}//再来看addPath函数,它主要目的是添加设备在sysfs中的路径,int DirectVolume::addPath(const char *path) {   mPaths->push_back(strdup(path));    return0;}
addPath把和某个存储卡接口相关的设备路径与这个DirectVolume绑定到一起,并且这个设备路径和Uevent中的DEVPATH是对应的,这样就可以根据Uevent的DEVPATH找到是哪个存储卡的DirectVolume发生了变动。当然手机上目前只有一个存储卡接口,所以Vold也只有一个DirectVolume。

1.3.6 VM与NM交互

在分析NM模块的数据处理时发现,NM模块接收到Uevent事件后,会调用VM模块进行处理,如果Uevent是block子系统,则调用handleBlockEvent
void VolumeManager::handleBlockEvent(NetlinkEvent*evt) {    constchar *devpath = evt->findParam("DEVPATH"); /*前面在process_config中构造的DirectVolume对象保存在了mVolumes中,它的定义如下:typedef android::List<Volume *>VolumeCollection,也是一个列表。  注意它保存的是Volume指针,而我们的DirectVolume是从Volume派生的*/   VolumeCollection::iterator it;    boolhit = false;for (it = mVolumes->begin(); it !=mVolumes->end(); ++it) {        //调用每个Volume的handleBlockEvent事件,实际上将调用        //DirectVolume的handleBlockEvent函数。        if(!(*it)->handleBlockEvent(evt)) {           hit = true;           break;        }    }}
int DirectVolume::handleBlockEvent(NetlinkEvent*evt) {    constchar *dp = evt->findParam("DEVPATH"); PathCollection::iterator  it;//将Uevent的DEVPATH和addPath添加的路径进行对比,判断属不属于自己管理的范围。    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);                 //创建设备节点               if (createDeviceNode(nodepath, major, minor)) {                    ......               }               if (!strcmp(devtype, "disk")) {                    handleDiskAdded(dp, evt);//添加一个磁盘               } else {                    /*对于有分区的SD卡,先收到上面的“disk”消息,然后每个分区就会收到                   一个分区添加消息。                   */                    handlePartitionAdded(dp,evt);               }           } else if (action == NetlinkEvent::NlActionRemove) {                ......           } else if (action == NetlinkEvent::NlActionChange) {              ......           }           ......           return 0;        }    }    errno= ENODEV;    return-1;}

1.4 commandlisten模块分析

1.4.1 commandlisten构造

 /system/vold/main.cpp
cl = new CommandListener();  vm->setBroadcaster((SocketListener *) cl);  nm->setBroadcaster((SocketListener *) cl);    ...    /* * Now that we're up, we can respond to commands */  if (cl->startListener()) {     SLOGE("Unable to start CommandListener (%s)", strerror(errno));     exit(1);  }
构造函数/system/vold/CommandListener.cpp
CommandListener::CommandListener() :                 FrameworkListener("vold", true) {    registerCmd(new DumpCmd());    registerCmd(new VolumeCmd());    registerCmd(new AsecCmd());    registerCmd(new ObbCmd());    registerCmd(new StorageCmd());    registerCmd(new XwarpCmd());    registerCmd(new CryptfsCmd());    registerCmd(new FstrimCmd());    //M{#ifndef MTK_EMULATOR_SUPPORT    registerCmd(new USBCmd());#endif    registerCmd(new CDROMCmd());    //}M#if defined (ENG_BUILD_ENG)        registerCmd(new SilkRoad());#endif}
构造一个父类FrameworkListener
FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :                              SocketListener(socketName, true, withSeq) {      init(socketName, withSeq);  }
void FrameworkListener::init(const char *socketName, bool withSeq) {      mCommands = new FrameworkCommandCollection();      errorRate = 0;      mCommandCount = 0;      mWithSeq = withSeq;  }
SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) {    init(socketName, -1, listen, useCmdNum);}
void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {    mListen = listen;    mSocketName = socketName;    mSock = socketFd;    mUseCmdNum = useCmdNum;    pthread_mutex_init(&mClientsLock, NULL);    mClients = new SocketClientCollection();}

1.4.2 Command注册

CommandListener的构造函数中调用父类的注册函数register, 注册commad到FrameworkListener的mCommands容器中
void FrameworkListener::registerCmd(FrameworkCommand *cmd) {    mCommands->push_back(cmd);}
CommandListener::VolumeCmd::VolumeCmd() :                 VoldCommand("volume") {}
VoldCommand::VoldCommand(const char *cmd) :              FrameworkCommand(cmd)  {}
FrameworkCommand::FrameworkCommand(const char *cmd) {    mCommand = cmd;}

将volume这个command注册到mCommands这个容器中之后,目的是当FrameworkListerer从SlocketListener接收到command的时候,会依据mCommands 中的command进行解析筛选判断分发,调用对应的command执行类

1.4.3 startListener的分析和数据处理

int SocketListener::startListener() {        if (!mSocketName && mSock == -1) {          SLOGE("Failed to start unbound listener");          errno = EINVAL;          return -1;      } else if (mSocketName) {          if ((mSock = android_get_control_socket(mSocketName)) < 0) {//获取socket的文件描述符,这里是获取Vold这个socket的              SLOGE("Obtaining file descriptor socket '%s' failed: %s",                   mSocketName, strerror(errno));              return -1;          }          SLOGV("got mSock = %d for %s", mSock, mSocketName);      }        if (mListen && listen(mSock, 4) < 0) {          SLOGE("Unable to listen on socket (%s)", strerror(errno));          return -1;      } else if (!mListen)//是否正常监听socket          mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));        if (pipe(mCtrlPipe)) {//新建管道,保存文件描述符到数组          SLOGE("pipe failed (%s)", strerror(errno));          return -1;      }        if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {//开了一个线程来处理          SLOGE("pthread_create (%s)", strerror(errno));          return -1;      }        return 0;  } 
开启线程用于监听
void *SocketListener::threadStart(void *obj) {      SocketListener *me = reinterpret_cast<SocketListener *>(obj);//threadStart为static函数,上面开线程创建的时候传了this,这里需要转换一个一样bit位的SocketListener指针        me->runListener();//SocketListener真正的执行函数      pthread_exit(NULL);      return NULL;  } 
对socket监听处理
void SocketListener::runListener() {        SocketClientCollection *pendingList = new SocketClientCollection();//暂存mClients中的SocketClient        while(1) {          SocketClientCollection::iterator it;          fd_set read_fds;          int rc = 0;          int max = -1;            FD_ZERO(&read_fds);//清空文件描述符集read_fds             if (mListen) {              max = mSock;              FD_SET(mSock, &read_fds);//如果正常的监听,这里就把之前获得的vold的文件描述符添加进去          }            FD_SET(mCtrlPipe[0], &read_fds);//添加管道读取端的文件描述符          if (mCtrlPipe[0] > max)              max = mCtrlPipe[0];            pthread_mutex_lock(&mClientsLock);//加锁操作,多线程安全          for (it = mClients->begin(); it != mClients->end(); ++it) {//遍历mClients,获取fd 添加到read_fds              int fd = (*it)->getSocket();              FD_SET(fd, &read_fds);              if (fd > max)                  max = fd;          }          pthread_mutex_unlock(&mClientsLock);//解锁          SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);    //linux下socket编程的select,这里检测read_fds集合里面是否有可读的,也就是有没有数据过来,没有数据的文件描述符会从read_fds中被剔除,这里的select设置time out为NULL,阻塞操作,直到read_fds集合中描述符有变化          if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {              if (errno == EINTR)                  continue;              SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);              sleep(1);              continue;          } else if (!rc)              continue;            if (FD_ISSET(mCtrlPipe[0], &read_fds))//如果匿名管道有数据可读,就退出              break;          if (mListen && FD_ISSET(mSock, &read_fds)) {//如果是正常监听的 mListen 为true,然后mSock这个描述符有可读数据,就创建链接,新建异步处理的SocketClient加入到mClients容器,这里的mSock 是vold这个套接字的描述符              struct sockaddr addr;              socklen_t alen;              int c;                do {                  alen = sizeof(addr);                  c = accept(mSock, &addr, &alen);                  SLOGV("%s got %d from accept", mSocketName, c);              } while (c < 0 && errno == EINTR);              if (c < 0) {                  SLOGE("accept failed (%s)", strerror(errno));                  sleep(1);                  continue;              }              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();          pthread_mutex_lock(&mClientsLock);          for (it = mClients->begin(); it != mClients->end(); ++it) {//把上面有请求建立链接的Client加入到pendingList 容器中,后面处理              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,          * there is no need to lock it */          while (!pendingList->empty()) {//遍历处理              /* Pop the first item from the list */              it = pendingList->begin();              SocketClient* c = *it;              pendingList->erase(it);              /* Process it, if false is returned and our sockets are              * connection-based, remove and destroy it */              if (!onDataAvailable(c) && mListen) {//调用到FrameworkListener 中onDataAvailable处理Socket事件                  /* Remove the client from our array */                  SLOGV("going to zap %d for %s", c->getSocket(), mSocketName);                  pthread_mutex_lock(&mClientsLock);                  for (it = mClients->begin(); it != mClients->end(); ++it) {                      if (*it == c) {                          mClients->erase(it);//处理完成之后,从容器中移除这次的监听到的SocketClient                          break;                      }                  }                  pthread_mutex_unlock(&mClientsLock);                  /* Remove our reference to the client */                  c->decRef();              }          }      }      delete pendingList;  }  
SocketListener的核心处理函数是onDataAvailable
bool FrameworkListener::onDataAvailable(SocketClient *c) {      char buffer[255];      int len;        len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));//读Socket 内容保存到buffer      if (len < 0) {          SLOGE("read() failed (%s)", strerror(errno));          return false;      } else if (!len)          return false;        int offset = 0;      int i;        for (i = 0; i < len; i++) {          if (buffer[i] == '\0') {//一次传入一个字符串             <span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: rgb(240, 247, 254);"> //分发命令,最终会调用对应命令对象的runCommand进行函数处理。</span>            dispatchCommand(c, buffer + offset);              offset = i + 1;          }      }      return true;  }  </span>
调用dispatchcommand
void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {      FrameworkCommandCollection::iterator i;      int argc = 0;      char *argv[FrameworkListener::CMD_ARGS_MAX];      char tmp[255];    ...//解析判断command buffer        for (i = mCommands->begin(); i != mCommands->end(); ++i) {//遍历之前register到FrameworkListener中的FrameworkCommand容器          FrameworkCommand *c = *i;            if (!strcmp(argv[0], c->getCommand())) {//其中有注册“Volume”,如果这里是Volume开头的command,那么就调用,Volume构造的时候所构造的父类FrameworkCommand中的runCommand函数              if (c->runCommand(cli, argc, argv)) {                  SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));              }              goto out;          }      }   } 
以Volume这个runcommand为例 /system/vold/CommandListener.cpp中

int CommandListener::VolumeCmd::runCommand(SocketClient *cli,                                                        int argc, char **argv) {      dumpArgs(argc, argv, -1);        if (argc < 2) {          cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);          return 0;      }        VolumeManager *vm = VolumeManager::Instance();//获取已经存在的VolumeManager实例    ...    else if (!strcmp(argv[1], "mount")) {//判断command 内容          if (argc != 3) {              cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false);              return 0;          }          rc = vm->mountVolume(argv[2]);//交给VolumeManager来对Volume进行操作      }    ...    } 

1.4.4 commandlisten 数据处理流程图




1.5 mountservice模块的介绍

1.5.1 mountservice构造

public MountService(Context context) {          mContext = context;            synchronized (mVolumesLock) {              readStorageListLocked(); // 解析/frameworks/base/core/res/res/xml/storage_list.xml保存volume到 MountService的list :mVolumes中          }            // XXX: This will go away soon in favor of IMountServiceObserver          mPms = (PackageManagerService) ServiceManager.getService("package");            mHandlerThread = new HandlerThread("MountService");          mHandlerThread.start();          mHandler = new MountServiceHandler(mHandlerThread.getLooper());//新建消息处理handler            // Watch for user changes          final IntentFilter userFilter = new IntentFilter();          userFilter.addAction(Intent.ACTION_USER_ADDED);          userFilter.addAction(Intent.ACTION_USER_REMOVED);          mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);//注册广播接收            // Watch for USB changes on primary volume          final StorageVolume primary = getPrimaryPhysicalVolume();          if (primary != null && primary.allowMassStorage()) {              mContext.registerReceiver(                      mUsbReceiver, new IntentFilter(UsbManager.ACTION_USB_STATE), null, mHandler);          }            // Add OBB Action Handler to MountService thread.          mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());            /*          * Create the connection to vold with a maximum queue of twice the          * amount of containers we'd ever expect to have. This keeps an          * "asec list" from blocking a thread repeatedly.          */          mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25);//创建 vold 的监听接收,用于接收system中Vold的socket消息            Thread thread = new Thread(mConnector, VOLD_TAG);          thread.start();//启动线程,NativeDaemonConnector实现了Runnable接口,实现在 run中            // Add ourself to the Watchdog monitors if enabled.          if (WATCHDOG_ENABLE) {              Watchdog.getInstance().addMonitor(this);          }      } 

1.5.2构造了NativeDaemonConnector用来接收来自下层的socket消息

NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,          int responseQueueSize, String logTag, int maxLogSize) {      mCallbacks = callbacks; //回调      mSocket = socket; // socket名称      mResponseQueue = new ResponseQueue(responseQueueSize);//构建一个响应队列      mSequenceNumber = new AtomicInteger(0);      TAG = logTag != null ? logTag : "NativeDaemonConnector";    }
开启监测线程的run方法
public void run() {      HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler"); //TAG 为 VoldConnector,这里新建一个名为VoldConnector.CallbackHandler的消息处理线程,用于下面接收到vold 的socket之后的处理      thread.start();      mCallbackHandler = new Handler(thread.getLooper(), this); //创建handler 用于分发消息       while (true) {          try {              listenToSocket();// while 循环 监听socket          } catch (Exception e) {              loge("Error in NativeDaemonConnector: " + e);              SystemClock.sleep(5000);          }      }  } 
private void listenToSocket() throws IOException {      LocalSocket socket = null;        try {          socket = new LocalSocket();  //创建本地socket          LocalSocketAddress address = new LocalSocketAddress(mSocket,                  LocalSocketAddress.Namespace.RESERVED);//获得服务端vold socket的地址            socket.connect(address);//连接            InputStream inputStream = socket.getInputStream();          synchronized (mDaemonLock) {              mOutputStream = socket.getOutputStream();          }//获取输入输出流            mCallbacks.onDaemonConnected();//回调,在MountService中执行,初始化一些Volume状态信息            byte[] buffer = new byte[BUFFER_SIZE];          int start = 0;            while (true) {              int count = inputStream.read(buffer, start, BUFFER_SIZE - start);//读取数据到buffer              if (count < 0) {//连接断开,跳出当前while ,外部while循环 重新调用该函数连接                  loge("got " + count + " reading with start = " + start);                  break;              }                  // Add our starting point to the count and reset the start.              count += start;              start = 0;                for (int i = 0; i < count; i++) {                  if (buffer[i] == 0) {                      final String rawEvent = new String(                              buffer, start, i - start, Charsets.UTF_8);                      log("RCV <- {" + rawEvent + "}");                        try {                          final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent(                                  rawEvent);   //解析成event 保存                          if (event.isClassUnsolicited()) {    //判断event的code范围 code >= 600 && code < 700                              // TODO: migrate to sending NativeDaemonEvent instances                              mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage( //发送消息,把event交给handle来分发处理                                      event.getCode(), event.getRawEvent()));                          } else {                              mResponseQueue.add(event.getCmdNumber(), event);//加入到响应队列                          }                      } catch (IllegalArgumentException e) {                          log("Problem parsing message: " + rawEvent + " - " + e);                      }                        start = i + 1;                  }              }
在NativeDaemonConnector中的handle处理为:
public boolean handleMessage(Message msg) {      String event = (String) msg.obj;      try {          if (!mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))) { //回调到MountService 的onEent函数              log(String.format("Unhandled event '%s'", event));          }      } catch (Exception e) {          loge("Error handling '" + event + "': " + e);      }      return true;  } 
MountService中onEvent
public boolean onEvent(int code, String raw, String[] cooked) {          if (DEBUG_EVENTS) {              StringBuilder builder = new StringBuilder();              builder.append("onEvent::");              builder.append(" raw= " + raw);              if (cooked != null) {                  builder.append(" cooked = " );                  for (String str : cooked) {                      builder.append(" " + str);                  }              }              Slog.i(TAG, builder.toString());          }          if (code == VoldResponseCode.VolumeStateChange) { //根据 Vold的Code 执行              /*              * One of the volumes we're managing has changed state.              * Format: "NNN Volume <label> <path> state changed              * from <old_#> (<old_str>) to <new_#> (<new_str>)"              */              notifyVolumeStateChange(                      cooked[2], cooked[3], Integer.parseInt(cooked[7]),                              Integer.parseInt(cooked[10])); //更新状态          } else if ((code == VoldResponseCode.VolumeDiskInserted) ||                     (code == VoldResponseCode.VolumeDiskRemoved) ||                     (code == VoldResponseCode.VolumeBadRemoval))      ...                      if (code == VoldResponseCode.VolumeDiskInserted) { //如果接收到的是插入disk的消息,则执行挂载操作                  new Thread() {                      @Override                      public void run() {                          try {                              int rc;                              if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {                                  Slog.w(TAG, String.format("Insertion mount failed (%d)", rc));                              }                          } catch (Exception ex) {                              Slog.w(TAG, "Failed to mount media on insertion", ex);                          }                      }                  }.start();              }  }

1.5.3 MountService下发command

MountService中对Volume的各种操作都是需要转换成符合Vold中socket command,这样Vold中才能正确的解析识别调用
private int doMountVolume(String path) {      int rc = StorageResultCode.OperationSucceeded;        final StorageVolume volume;      synchronized (mVolumesLock) {          volume = mVolumesByPath.get(path);      }        if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path);      try {          mConnector.execute("volume", "mount", path);// 调用到NativeDaemonConnector中的execute      } 
NativeDaemonConnector的execute
public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args)              throws NativeDaemonConnectorException {          final ArrayList<NativeDaemonEvent> events = Lists.newArrayList();            final int sequenceNumber = mSequenceNumber.incrementAndGet();          final StringBuilder cmdBuilder =                  new StringBuilder(Integer.toString(sequenceNumber)).append(' ');          final long startTime = SystemClock.elapsedRealtime();            makeCommand(cmdBuilder, cmd, args); //转换制作成标准的Command            final String logCmd = cmdBuilder.toString(); /* includes cmdNum, cmd, args */          log("SND -> {" + logCmd + "}");            cmdBuilder.append('\0');          final String sentCmd = cmdBuilder.toString(); /* logCmd + \0 */            synchronized (mDaemonLock) {              if (mOutputStream == null) {                  throw new NativeDaemonConnectorException("missing output stream");              } else {                  try {                      mOutputStream.write(sentCmd.getBytes(Charsets.UTF_8)); //通过在listenToSocket中获取的输出流,写入转换好的sentCmd                  } catch (IOException e) {                      throw new NativeDaemonConnectorException("problem sending command", e);                  }              }          }  }

1.5.4 Mountservice 数据处理流程图













0 0
原创粉丝点击