歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Android-vold源碼分析

Android-vold源碼分析

日期:2017/3/1 10:41:28   编辑:Linux編程
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. private:
  6. static void dumpArgs(int argc, char **argv, int argObscure);
  7. class DumpCmd : public VoldCommand {
  8. public:
  9. DumpCmd();
  10. virtual ~DumpCmd() {}
  11. int runCommand(SocketClient *c, int argc, char ** argv);
  12. };
  13. class VolumeCmd : public VoldCommand {
  14. public:
  15. VolumeCmd();
  16. virtual ~VolumeCmd() {}
  17. int runCommand(SocketClient *c, int argc, char ** argv);
  18. };
  19. class ShareCmd : public VoldCommand {
  20. public:
  21. ShareCmd();
  22. virtual ~ShareCmd() {}
  23. int runCommand(SocketClient *c, int argc, char ** argv);
  24. };
  25. class AsecCmd : public VoldCommand {
  26. public:
  27. AsecCmd();
  28. virtual ~AsecCmd() {}
  29. int runCommand(SocketClient *c, int argc, char ** argv);
  30. };
  31. class StorageCmd : public VoldCommand {
  32. public:
  33. StorageCmd();
  34. virtual ~StorageCmd() {}
  35. int runCommand(SocketClient *c, int argc, char ** argv);
  36. };
  37. class XwarpCmd : public VoldCommand {
  38. public:
  39. XwarpCmd();
  40. virtual ~XwarpCmd() {}
  41. int runCommand(SocketClient *c, int argc, char ** argv);
  42. };
  43. };
在這個類中,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. me->runListener();
  4. pthread_exit(NULL);
  5. return NULL;
  6. }
線程真正實現的函數在這裡:
  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. FD_ZERO(&read_fds);
  8. if (mListen) {
  9. max = mSock;
  10. FD_SET(mSock, &read_fds);
  11. }
  12. FD_SET(mCtrlPipe[0], &read_fds);
  13. if (mCtrlPipe[0] > max)
  14. max = mCtrlPipe[0];
  15. pthread_mutex_lock(&mClientsLock);
  16. for (it = mClients->begin(); it != mClients->end(); ++it) {
  17. FD_SET((*it)->getSocket(), &read_fds);
  18. if ((*it)->getSocket() > max)
  19. max = (*it)->getSocket();
  20. }
  21. pthread_mutex_unlock(&mClientsLock);
  22. if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
  23. SLOGE("select failed (%s)", strerror(errno));
  24. sleep(1);
  25. continue;
  26. } else if (!rc)
  27. continue;
  28. if (FD_ISSET(mCtrlPipe[0], &read_fds))
  29. break;
  30. if (mListen && FD_ISSET(mSock, &read_fds)) {
  31. struct sockaddr addr;
  32. socklen_t alen = sizeof(addr);
  33. int c;
  34. if ((c = accept(mSock, &addr, &alen)) < 0) {
  35. SLOGE("accept failed (%s)", strerror(errno));
  36. sleep(1);
  37. continue;
  38. }
  39. pthread_mutex_lock(&mClientsLock);
  40. mClients->push_back(new SocketClient(c));
  41. pthread_mutex_unlock(&mClientsLock);
  42. }
  43. do {
  44. pthread_mutex_lock(&mClientsLock);
  45. for (it = mClients->begin(); it != mClients->end(); ++it) {
  46. int fd = (*it)->getSocket();
  47. if (FD_ISSET(fd, &read_fds)) {
  48. pthread_mutex_unlock(&mClientsLock);
  49. /*當收到framework的操作命令,執行該函數*/
  50. if (!onDataAvailable(*it)) {
  51. close(fd);
  52. pthread_mutex_lock(&mClientsLock);
  53. delete *it;
  54. it = mClients->erase(it);
  55. pthread_mutex_unlock(&mClientsLock);
  56. }
  57. FD_CLR(fd, &read_fds);
  58. continue;
  59. }
  60. }
  61. pthread_mutex_unlock(&mClientsLock);
  62. } while (0);
  63. }
  64. }
將收到的命令交給onDataAvailable函數來處理,onDataAvailable函數是類的純虛函數,在FrameworkListener類實現了該函數:
  1. bool FrameworkListener::onDataAvailable(SocketClient *c) {
  2. char buffer[255];
  3. int len;
  4. if ((len = read(c->getSocket(), buffer, sizeof(buffer) -1)) < 0) {
  5. SLOGE("read() failed (%s)", strerror(errno));
  6. return errno;
  7. } else if (!len)
  8. return false;
  9. int offset = 0;
  10. int i;
  11. for (i = 0; i < len; i++) {
  12. if (buffer[i] == '\0') {
  13. /*命令的處理函數*/
  14. dispatchCommand(c, buffer + offset);
  15. offset = i + 1;
  16. }
  17. }
  18. return true;
  19. }
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. /*中間省略了字符串的處理部分,將每個子串保存到了argv數組中,
  8. 所以在out標記的位置,對argv[i]的數組進行釋放,
  9. 因為使用了strdup函數復制字符串*/
  10. /*下面這個循環用來循環選擇不同的分支實現函數,
  11. mCommands容器保存著6個新聲明的類對象*/
  12. for (i = mCommands->begin(); i != mCommands->end(); ++i) {
  13. FrameworkCommand *c = *i;
  14. /*當第一個參數與FrameworkCommand類中的mCommand參數相等時,
  15. 才去調用該對象新實現的runCommand函數*/
  16. if (!strcmp(argv[0], c->getCommand())) {
  17. if (c->runCommand(cli, argc, argv)) {
  18. SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
  19. }
  20. goto out;
  21. }
  22. }
  23. cli->sendMsg(500, "Command not recognized", false);
  24. out:
  25. int j;
  26. for (j = 0; j < argc; j++)
  27. free(argv[j]);
  28. return;
  29. }
這裡從代碼可能有點疑問,這個循環為什麼可以選擇不同的分支新實現的函數呢?
仔細看下代碼會發現,在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