Android-vold源码分析


vold处理完磁盘事件(见  ),就要开始接受framework的操作命令,在main函数里面,开启了一个线程来监听framework的信息,当收到操作命令,vold进行解析,分析出命令,然后调用相应的磁盘操作函数,待操作完成后,再将操作结果的状态值反馈给framework,中间均使用了广播机制,使用了UDP协议。

在main函数中,有以下函数的调用:

  1. if (cl->startListener()) {  
  2.     SLOGE("Unable to start CommandListener (%s)", strerror(errno));  
  3.     exit(1);  
  4. }  
cl是CommandListener类实例化的一个对象,该对象专门负责与framework的通信,首先说明与CommandListener类相关的一些继承关系。
CommandListener --> FrameworkListener --> SocketListener(父类)
在CommandListener类中,声明了6个类,这6个类继承了VoldCommand类,VoldCommand类继承了FrameworkCommand,关系如下:
VoldCommand --> FrameworkCommand(父类)
以下是CommandListener类的声明:
  1. class CommandListener : public FrameworkListener {  
  2. public:  
  3.     CommandListener();  
  4.     virtual ~CommandListener() {}  
  5.   
  6. private:  
  7.     static void dumpArgs(int argc, char **argv, int argObscure);  
  8.   
  9.     class DumpCmd : public VoldCommand {  
  10.     public:  
  11.         DumpCmd();  
  12.         virtual ~DumpCmd() {}  
  13.         int runCommand(SocketClient *c, int argc, char ** argv);  
  14.     };  
  15.   
  16.     class VolumeCmd : public VoldCommand {  
  17.     public:  
  18.         VolumeCmd();  
  19.         virtual ~VolumeCmd() {}  
  20.         int runCommand(SocketClient *c, int argc, char ** argv);  
  21.     };  
  22.   
  23.     class ShareCmd : public VoldCommand {  
  24.     public:  
  25.         ShareCmd();  
  26.         virtual ~ShareCmd() {}  
  27.         int runCommand(SocketClient *c, int argc, char ** argv);  
  28.     };  
  29.   
  30.     class AsecCmd : public VoldCommand {  
  31.     public:  
  32.         AsecCmd();  
  33.         virtual ~AsecCmd() {}  
  34.         int runCommand(SocketClient *c, int argc, char ** argv);  
  35.     };  
  36.   
  37.     class StorageCmd : public VoldCommand {  
  38.     public:  
  39.         StorageCmd();  
  40.         virtual ~StorageCmd() {}  
  41.         int runCommand(SocketClient *c, int argc, char ** argv);  
  42.     };  
  43.   
  44.     class XwarpCmd : public VoldCommand {  
  45.     public:  
  46.         XwarpCmd();  
  47.         virtual ~XwarpCmd() {}  
  48.         int runCommand(SocketClient *c, int argc, char ** argv);  
  49.     };  
  50. };  
在这个类中,VoldCommand主要写了一个纯虚函数runCommand,声明如下:
virtual int runCommand(SocketClient *c, int argc, char **argv) = 0;
为了就是在CommandListener类中的实现,这里���共实现了6个版本的runCommand函数,下一篇文章只讨论其中一个比较重要的VolumeCmd类的实现,其余的跟这个类的实现差不多。
开始深入startListener线程:
进入startListener函数,创建了以下线程:
  1. if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {  
  2.     SLOGE("pthread_create (%s)", strerror(errno));  
  3.     return -1;  
  4. }  
这里跟前几章线程的创建几乎一样,
  1. void *SocketListener::threadStart(void *obj) {  
  2.     SocketListener *me = reinterpret_cast<SocketListener *>(obj);  
  3.   
  4.     me->runListener();  
  5.     pthread_exit(NULL);  
  6.     return NULL;  
  7. }  
线程真正实现的函数在这里:
  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.   
  8.         FD_ZERO(&read_fds);  
  9.   
  10.         if (mListen) {  
  11.             max = mSock;  
  12.             FD_SET(mSock, &read_fds);  
  13.         }  
  14.   
  15.         FD_SET(mCtrlPipe[0], &read_fds);  
  16.         if (mCtrlPipe[0] > max)  
  17.             max = mCtrlPipe[0];  
  18.   
  19.         pthread_mutex_lock(&mClientsLock);  
  20.         for (it = mClients->begin(); it != mClients->end(); ++it) {  
  21.             FD_SET((*it)->getSocket(), &read_fds);  
  22.             if ((*it)->getSocket() > max)  
  23.                 max = (*it)->getSocket();  
  24.         }  
  25.         pthread_mutex_unlock(&mClientsLock);  
  26.   
  27.         if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {  
  28.             SLOGE("select failed (%s)", strerror(errno));  
  29.             sleep(1);  
  30.             continue;  
  31.         } else if (!rc)  
  32.             continue;  
  33.   
  34.         if (FD_ISSET(mCtrlPipe[0], &read_fds))  
  35.             break;  
  36.         if (mListen && FD_ISSET(mSock, &read_fds)) {  
  37.             struct sockaddr addr;  
  38.             socklen_t alen = sizeof(addr);  
  39.             int c;  
  40.   
  41.             if ((c = accept(mSock, &addr, &alen)) < 0) {  
  42.                 SLOGE("accept failed (%s)", strerror(errno));  
  43.                 sleep(1);  
  44.                 continue;  
  45.             }  
  46.             pthread_mutex_lock(&mClientsLock);  
  47.             mClients->push_back(new SocketClient(c));  
  48.             pthread_mutex_unlock(&mClientsLock);  
  49.         }  
  50.   
  51.         do {  
  52.             pthread_mutex_lock(&mClientsLock);  
  53.             for (it = mClients->begin(); it != mClients->end(); ++it) {  
  54.                 int fd = (*it)->getSocket();  
  55.                 if (FD_ISSET(fd, &read_fds)) {  
  56.                     pthread_mutex_unlock(&mClientsLock);  
  57.                     /*当收到framework的操作命令,执行该函数*/  
  58.                     if (!onDataAvailable(*it)) {  
  59.                         close(fd);  
  60.                         pthread_mutex_lock(&mClientsLock);  
  61.                         delete *it;  
  62.                         it = mClients->erase(it);  
  63.                         pthread_mutex_unlock(&mClientsLock);  
  64.                     }  
  65.                     FD_CLR(fd, &read_fds);  
  66.                     continue;  
  67.                 }  
  68.             }  
  69.             pthread_mutex_unlock(&mClientsLock);  
  70.         } while (0);  
  71.     }  
  72. }  
将收到的命令交给onDataAvailable函数来处理,onDataAvailable函数是类的纯虚函数,在FrameworkListener类实现了该函数:
  1. bool FrameworkListener::onDataAvailable(SocketClient *c) {  
  2.     char buffer[255];  
  3.     int len;  
  4.   
  5.     if ((len = read(c->getSocket(), buffer, sizeof(buffer) -1)) < 0) {  
  6.         SLOGE("read() failed (%s)", strerror(errno));  
  7.         return errno;  
  8.     } else if (!len)  
  9.         return false;  
  10.   
  11.     int offset = 0;  
  12.     int i;  
  13.   
  14.     for (i = 0; i < len; i++) {  
  15.         if (buffer[i] == '\0') {  
  16.             /*命令的处理函数*/  
  17.             dispatchCommand(c, buffer + offset);  
  18.             offset = i + 1;  
  19.         }  
  20.     }  
  21.     return true;  
  22. }  
dispatchCommand函数用来选择不同的分支函数,因为在类有6个分支的实现版本,包括DumpCmd,VolumeCmd,ShareCmd,AsecCmd,StorageCmd和XwarpCmd。以下是dispatchCommand函数的源码:
  1. void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {  
  2.     FrameworkCommandCollection::iterator i;  
  3.     int argc = 0;  
  4.     /*static const int CMD_ARGS_MAX = 16; 
  5.     说明framework发送的命令最多只能容纳16个子串*/  
  6.     char *argv[FrameworkListener::CMD_ARGS_MAX];  
  7.       
  8.     /*中间省略了字符串的处理部分,将每个子串保存到了argv数组中, 
  9.     所以在out标记的位置,对argv[i]的数组进行释放, 
  10.     因为使用了strdup函数复制字符串*/  
  11.           
  12.     /*下面这个循环用来循环选择不同的分支实现函数, 
  13.     mCommands容器保存着6个新声明的类对象*/  
  14.     for (i = mCommands->begin(); i != mCommands->end(); ++i) {  
  15.         FrameworkCommand *c = *i;  
  16.         /*当第一个参数与FrameworkCommand类中的mCommand参数相等时, 
  17.         才去调用该对象新实现的runCommand函数*/  
  18.         if (!strcmp(argv[0], c->getCommand())) {  
  19.             if (c->runCommand(cli, argc, argv)) {  
  20.                 SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));  
  21.             }  
  22.             goto out;  
  23.         }  
  24.     }  
  25.   
  26.     cli->sendMsg(500, "Command not recognized"false);  
  27. out:  
  28.     int j;  
  29.     for (j = 0; j < argc; j++)  
  30.         free(argv[j]);  
  31.     return;  
  32. }  
这里从代码可能有点疑问,这个循环为什么可以选择不同的分支新实现的函数呢?
仔细看下代码会发现,在FrameworkListener中有一个注册函数,将新的派生类的名字注册到mCommands容器中,每个类的mCommand参数各代表一个派生类的名字。
  1. void FrameworkListener::registerCmd(FrameworkCommand *cmd) {  
  2.     mCommands->push_back(cmd);  
  3. }  
在CommandListener类的构造函数中,分别对6个分支的派生类进行了注册,每次注册都实例化了一个新的对象存放到mCommands容器中。
  1. CommandListener::CommandListener() :  
  2.                  FrameworkListener("vold") {  
  3.     registerCmd(new DumpCmd());  
  4.     registerCmd(new VolumeCmd());  
  5.     registerCmd(new AsecCmd());  
  6.     registerCmd(new ShareCmd());  
  7.     registerCmd(new StorageCmd());  
  8.     registerCmd(new XwarpCmd());  
  9. }  
那这6个派生类的名称保存在FrameworkCommand类的一个私有变量mCommand中,该类的构造函数就是给mCommand赋值,源码:
  1. FrameworkCommand::FrameworkCommand(const char *cmd) {  
  2.     mCommand = cmd;  
  3. }  
在刚才的FrameworkListener::dispatchCommand函数里,有这么一个比较:
  1. if (!strcmp(argv[0], c->getCommand())){}  
getCommand函数的源码:
  1. const char *getCommand() { return mCommand; }  

这里来看mCommand的赋值,我们知道以下关系:
DumpCmd --> VoldCommand --> FrameworkCommand
VolumeCmd --> VoldCommand --> FrameworkCommand
ShareCmd --> VoldCommand --> FrameworkCommand
AsecCmd --> VoldCommand --> FrameworkCommand
StorageCmd --> VoldCommand --> FrameworkCommand
XwarpCmd --> VoldCommand --> FrameworkCommand
所以在CommandListener类中的6个派生类中的构造函数中,必须初始化const char *cmd这个参数,以下是初始化代码:

  1. CommandListener::DumpCmd::DumpCmd() :  
  2.                  VoldCommand("dump") {  
  3. }  
  4. CommandListener::VolumeCmd::VolumeCmd() :  
  5.                  VoldCommand("volume") {  
  6. }  
  7. CommandListener::ShareCmd::ShareCmd() :  
  8.                  VoldCommand("share") {  
  9. }  
  10. CommandListener::StorageCmd::StorageCmd() :  
  11.                  VoldCommand("storage") {  
  12. }  
  13. CommandListener::AsecCmd::AsecCmd() :  
  14.                  VoldCommand("asec") {  
  15. }  
  16. CommandListener::XwarpCmd::XwarpCmd() :  
  17.                  VoldCommand("xwarp") {  
  18. }  
6个构造函数均初始化不同的cmd参数,分别为dump,volume,share,storage,asec,xwarp。
在VoldCommand类的构造函数中,将cmd的值初始化FrameworkCommand类的构造函数。
  1. VoldCommand::VoldCommand(const char *cmd) :  
  2.               FrameworkCommand(cmd)  {  
  3. }  

所以这个比较,就是将framework发下来的命令的第一个参数与mCommands容器中的6个对象的mCommand参数进行了比较,从而选择正确的处理分支函数。

以上的内容涉及到好几个类,谷歌真是花了很大的力气啊。。
现在流程就走到了runCommand函数,该函数就声明在最上面那个CommandListener类里面,下一篇文章将介绍runCommand函数的实现。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 下一页
【内容导航】
第1页:startListener 第2页:runCommand
第3页:挂载SD卡 第4页:卸载SD卡
第5页:格式化SD卡 第6页:连接电脑OTG

相关内容