vold處理完磁盤事件(見 http://www.linuxidc.com/Linux/2011-12/50395.htm ),就要開始接受framework的操作命令,在main函數裡面,開啟了一個線程來監聽framework的信息,當收到操作命令,vold進行解析,分析出命令,然後調用相應的磁盤操作函數,待操作完成後,再將操作結果的狀態值反饋給framework,中間均使用了廣播機制,使用了UDP協議。
在main函數中,有以下函數的調用:
- if (cl->startListener()) {
- SLOGE("Unable to start CommandListener (%s)", strerror(errno));
- exit(1);
- }
cl是CommandListener類實例化的一個對象,該對象專門負責與framework的通信,首先說明與CommandListener類相關的一些繼承關系。
CommandListener --> FrameworkListener --> SocketListener(父類)
在CommandListener類中,聲明了6個類,這6個類繼承了VoldCommand類,VoldCommand類繼承了FrameworkCommand,關系如下:
VoldCommand --> FrameworkCommand(父類)
以下是CommandListener類的聲明:
- class CommandListener : public FrameworkListener {
- public:
- CommandListener();
- virtual ~CommandListener() {}
-
- private:
- static void dumpArgs(int argc, char **argv, int argObscure);
-
- class DumpCmd : public VoldCommand {
- public:
- DumpCmd();
- virtual ~DumpCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
-
- class VolumeCmd : public VoldCommand {
- public:
- VolumeCmd();
- virtual ~VolumeCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
-
- class ShareCmd : public VoldCommand {
- public:
- ShareCmd();
- virtual ~ShareCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
-
- class AsecCmd : public VoldCommand {
- public:
- AsecCmd();
- virtual ~AsecCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
-
- class StorageCmd : public VoldCommand {
- public:
- StorageCmd();
- virtual ~StorageCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
-
- class XwarpCmd : public VoldCommand {
- public:
- XwarpCmd();
- virtual ~XwarpCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
- };
在這個類中,VoldCommand主要寫了一個純虛函數runCommand,聲明如下:
virtual int runCommand(SocketClient *c, int argc, char **argv) = 0;
為了就是在CommandListener類中的實現,這裡總共實現了6個版本的runCommand函數,下一篇文章只討論其中一個比較重要的VolumeCmd類的實現,其余的跟這個類的實現差不多。
開始深入startListener線程:
進入startListener函數,創建了以下線程:
- if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
- SLOGE("pthread_create (%s)", strerror(errno));
- return -1;
- }
這裡跟前幾章線程的創建幾乎一樣,
- void *SocketListener::threadStart(void *obj) {
- SocketListener *me = reinterpret_cast<SocketListener *>(obj);
-
- me->runListener();
- pthread_exit(NULL);
- return NULL;
- }
線程真正實現的函數在這裡:
- void SocketListener::runListener() {
- while(1) {
- SocketClientCollection::iterator it;
- fd_set read_fds;
- int rc = 0;
- int max = 0;
-
- FD_ZERO(&read_fds);
-
- if (mListen) {
- max = mSock;
- FD_SET(mSock, &read_fds);
- }
-
- 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) {
- FD_SET((*it)->getSocket(), &read_fds);
- if ((*it)->getSocket() > max)
- max = (*it)->getSocket();
- }
- pthread_mutex_unlock(&mClientsLock);
-
- if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
- 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 = sizeof(addr);
- int c;
-
- if ((c = accept(mSock, &addr, &alen)) < 0) {
- SLOGE("accept failed (%s)", strerror(errno));
- sleep(1);
- continue;
- }
- pthread_mutex_lock(&mClientsLock);
- mClients->push_back(new SocketClient(c));
- pthread_mutex_unlock(&mClientsLock);
- }
-
- do {
- pthread_mutex_lock(&mClientsLock);
- for (it = mClients->begin(); it != mClients->end(); ++it) {
- int fd = (*it)->getSocket();
- if (FD_ISSET(fd, &read_fds)) {
- pthread_mutex_unlock(&mClientsLock);
- /*當收到framework的操作命令,執行該函數*/
- if (!onDataAvailable(*it)) {
- close(fd);
- pthread_mutex_lock(&mClientsLock);
- delete *it;
- it = mClients->erase(it);
- pthread_mutex_unlock(&mClientsLock);
- }
- FD_CLR(fd, &read_fds);
- continue;
- }
- }
- pthread_mutex_unlock(&mClientsLock);
- } while (0);
- }
- }
將收到的命令交給onDataAvailable函數來處理,onDataAvailable函數是類的純虛函數,在FrameworkListener類實現了該函數:
- bool FrameworkListener::onDataAvailable(SocketClient *c) {
- char buffer[255];
- int len;
-
- if ((len = read(c->getSocket(), buffer, sizeof(buffer) -1)) < 0) {
- SLOGE("read() failed (%s)", strerror(errno));
- return errno;
- } else if (!len)
- return false;
-
- int offset = 0;
- int i;
-
- for (i = 0; i < len; i++) {
- if (buffer[i] == '\0') {
- /*命令的處理函數*/
- dispatchCommand(c, buffer + offset);
- offset = i + 1;
- }
- }
- return true;
- }
dispatchCommand函數用來選擇不同的分支函數,因為在類有6個分支的實現版本,包括DumpCmd,VolumeCmd,ShareCmd,AsecCmd,StorageCmd和XwarpCmd。以下是dispatchCommand函數的源碼:
- void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
- FrameworkCommandCollection::iterator i;
- int argc = 0;
- /*static const int CMD_ARGS_MAX = 16;
- 說明framework發送的命令最多只能容納16個子串*/
- char *argv[FrameworkListener::CMD_ARGS_MAX];
-
- /*中間省略了字符串的處理部分,將每個子串保存到了argv數組中,
- 所以在out標記的位置,對argv[i]的數組進行釋放,
- 因為使用了strdup函數復制字符串*/
-
- /*下面這個循環用來循環選擇不同的分支實現函數,
- mCommands容器保存著6個新聲明的類對象*/
- for (i = mCommands->begin(); i != mCommands->end(); ++i) {
- FrameworkCommand *c = *i;
- /*當第一個參數與FrameworkCommand類中的mCommand參數相等時,
- 才去調用該對象新實現的runCommand函數*/
- if (!strcmp(argv[0], c->getCommand())) {
- if (c->runCommand(cli, argc, argv)) {
- SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
- }
- goto out;
- }
- }
-
- cli->sendMsg(500, "Command not recognized", false);
- out:
- int j;
- for (j = 0; j < argc; j++)
- free(argv[j]);
- return;
- }
這裡從代碼可能有點疑問,這個循環為什麼可以選擇不同的分支新實現的函數呢?
仔細看下代碼會發現,在FrameworkListener中有一個注冊函數,將新的派生類的名字注冊到mCommands容器中,每個類的mCommand參數各代表一個派生類的名字。
- void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
- mCommands->push_back(cmd);
- }
在CommandListener類的構造函數中,分別對6個分支的派生類進行了注冊,每次注冊都實例化了一個新的對象存放到mCommands容器中。
- CommandListener::CommandListener() :
- FrameworkListener("vold") {
- registerCmd(new DumpCmd());
- registerCmd(new VolumeCmd());
- registerCmd(new AsecCmd());
- registerCmd(new ShareCmd());
- registerCmd(new StorageCmd());
- registerCmd(new XwarpCmd());
- }
那這6個派生類的名稱保存在FrameworkCommand類的一個私有變量mCommand中,該類的構造函數就是給mCommand賦值,源碼:
- FrameworkCommand::FrameworkCommand(const char *cmd) {
- mCommand = cmd;
- }
在剛才的FrameworkListener::dispatchCommand函數裡,有這麼一個比較:
- if (!strcmp(argv[0], c->getCommand())){}
getCommand函數的源碼:
- 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這個參數,以下是初始化代碼:
- CommandListener::DumpCmd::DumpCmd() :
- VoldCommand("dump") {
- }
- CommandListener::VolumeCmd::VolumeCmd() :
- VoldCommand("volume") {
- }
- CommandListener::ShareCmd::ShareCmd() :
- VoldCommand("share") {
- }
- CommandListener::StorageCmd::StorageCmd() :
- VoldCommand("storage") {
- }
- CommandListener::AsecCmd::AsecCmd() :
- VoldCommand("asec") {
- }
- CommandListener::XwarpCmd::XwarpCmd() :
- VoldCommand("xwarp") {
- }
6個構造函數均初始化不同的cmd參數,分別為dump,volume,share,storage,asec,xwarp。
在VoldCommand類的構造函數中,將cmd的值初始化FrameworkCommand類的構造函數。
- VoldCommand::VoldCommand(const char *cmd) :
- FrameworkCommand(cmd) {
- }
所以這個比較,就是將framework發下來的命令的第一個參數與mCommands容器中的6個對象的mCommand參數進行了比較,從而選擇正確的處理分支函數。
以上的內容涉及到好幾個類,谷歌真是花了很大的力氣啊。。
現在流程就走到了runCommand函數,該函數就聲明在最上面那個CommandListener類裡面,下一篇文章將介紹runCommand函數的實現。