歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Android-vold源碼分析

vold處理完磁盤事件(見 http://www.linuxidc.com/Linux/2011-12/50395.htm ),就要開始接受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函數的實現。
Copyright © Linux教程網 All Rights Reserved