Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> Android存儲系統—Vold與MountService分析(三)

Android存儲系統—Vold與MountService分析(三)

編輯:關於android開發

  回顧:前帖分析了Vold的main()函數和NetlinkManager的函數調用流程,截止到NetlinkHandler的創建和start()調用,本帖繼續分析源碼

  1、處理block類型的uevent

  main()函數創建了CommandListener對象,NetlinkManager的start()函數又創建了NetlinkHandler對象,如果將CommandListener類和NetlinkHandler類的繼承關系圖畫出來,會發現它們都是從SocketListener類派生出來的,如下圖所示:

Android存儲系統—Vold與MountService分析(三)

圖1 NetlinkHandler和CommandListener的繼承關系

  原理:處於最底層的SocketListener類的作用是監聽socket的數據,接收到數據後分別交給FrameworkListener類和NetlinkListener類的函數,並分別對來自Framework和驅動的數據進行分析,分析後根據命令再分別調用CommandListener和NetlinkHandler中的函數。

  觀察NetlinkHandler類的構造方法,代碼如下:

Java代碼
  1. NetlinkHandler::NetlinkHandler(int listenerSocket) :  
  2.                 NetlinkListener(listenerSocket) {  
  3. }  

  這個構造方法很簡單,再看看它的start()方法,代碼如下:

Java代碼
  1. int NetlinkHandler::start() {  
  2.     return this->startListener();  
  3. }  

  可以發現,start()方法調用了SocketListener的startListener()函數,代碼如下:

Java代碼
  1. int SocketListener::startListener(int backlog) {  
  2.      if (!mSocketName && mSock == -1) {  
  3.          SLOGE("Failed to start unbound listener");  
  4.          errno = EINVAL;  
  5.          return -1;  
  6.      } else if (mSocketName) {            // 只有CommandListener中會設置mSocketName  
  7.            if ((mSock = android_get_control_socket(mSocketName)) < 0) {  
  8.                SLOGE("Obtaining file descriptor socket '%s' failed: %s",mSocketName, strerror(errno));  
  9.                return -1;  
  10.            }  
  11.            SLOGV("got mSock = %d for %s", mSock, mSocketName);  
  12.      }  
  13.   
  14.      if (mListen && listen(mSock, backlog) < 0) {  
  15.          SLOGE("Unable to listen on socket (%s)", strerror(errno));  
  16.          return -1;  
  17.      } else if (!mListen)  
  18.           mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));  
  19.   
  20.      if (pipe(mCtrlPipe)) {                          // 創建管道,用於退出監聽線程  
  21.          SLOGE("pipe failed (%s)", strerror(errno));  
  22.          return -1;  
  23.      }  
  24.   
  25.      if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {         // 創建一個監聽線程  
  26.          SLOGE("pthread_create (%s)", strerror(errno));  
  27.          return -1;  
  28.      }  
  29.   
  30.      return 0;  
  31. }  

  startListener()函數開始監聽socket,這個函數在NetlinkHandler中會被調用,在CommandListener也會被調用。

  startListener()函數首先判斷變量mSocketName是否有值,只有CommandListener對象會對這個變量賦值,它的值就是在init.rc中定義的socket字符串。

  調用函數 android_get_control_socket()的目的是從環境變量中取得socket的值,這樣CommandListener對象得到了它需要監聽的socket,

  而對於NetlinkHandler對象而言,它的mSocket不為NULL,前面已經創建了socket。

  startListener()函數接下來會根據成員變量mListener的值來判斷是否需要調用Listen()函數來監聽socket。這個mListen的值在對象構造時根據參數來初始化。

  對於CommandListener對象,mListener的值為ture,對於NetlinkHandler對象,mListener的值為false,這是因為CommandListener對象和SystemServer通信,需要監聽socket連接,而NetlinkHandler對象則不用。

  接下來startListener()函數會創建一個管道,這個管道的作用是通知線程停止監聽,這個線程就是startListener()函數最後創建的監聽線程,它的運行函數是threadStart(),在前貼的NetlinkManager家族圖系中我們可以清晰的發現,其代碼如下:

Java代碼
  1. void *SocketListener::threadStart(void *obj) {  
  2.      SocketListener *me = reinterpret_cast<SocketListener *>(obj);  
  3.      me->runListener();                                             // 調用runListener()方法  
  4.      pthread_exit(NULL);  
  5.      return NULL;  
  6. }  

  threadStart()中又調用了runListener()函數,代碼如下:

Java代碼
  1. void SocketListener::runListener() {  
  2.   
  3.       SocketClientCollection pendingList;  
  4.   
  5.       while(1) {             // 無限循環,一直監聽  
  6.             SocketClientCollection::iterator it;  
  7.             fd_set read_fds;  
  8.             int rc = 0;  
  9.             int max = -1;  
  10.   
  11.             FD_ZERO(&read_fds);       // 清空文件描述符集read_fds  
  12.   
  13.             if (mListen) {            // 如果需要監聽  
  14.                 max = mSock;  
  15.                 FD_SET(mSock, &read_fds);               // 把mSock加入到read_fds  
  16.             }  
  17.   
  18.             FD_SET(mCtrlPipe[0], &read_fds);                 // 把管道mCtrlPipe[0]也加入到read_fds  
  19.             if (mCtrlPipe[0] > max)  
  20.                 max = mCtrlPipe[0];  
  21.   
  22.             pthread_mutex_lock(&mClientsLock);               // 對容器mClients的操作需要加鎖  
  23.             for (it = mClients->begin(); it != mClients->end(); ++it) {    // mClient中保存的是NetlinkHandler對象的socket,或者CommandListener接入的socket  
  24.                   int fd = (*it)->getSocket();  
  25.                   FD_SET(fd, &read_fds);      // 遍歷容器mClients的所有成員,調用內聯函數getSocket()獲取文件描述符,並添加到文件描述符集read_fds  
  26.                   if (fd > max) {                                     // 也加入到read_fds  
  27.                       max = fd;  
  28.                   }  
  29.             }  
  30.             pthread_mutex_unlock(&mClientsLock);  
  31.             SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName);  
  32.             if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {              // 執行select調用,開始等待socket上的數據到來  
  33.                  if (errno == EINTR)                                              // 因為中斷退出select,繼續  
  34.                      continue;  
  35.                  SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max);  
  36.                  sleep(1);                               // select出錯,休眠1秒後繼續  
  37.                  continue;  
  38.             } else if (!rc)  
  39.                  continue;                           // 如果fd上沒有數據到達,繼續  
  40.   
  41.             if (FD_ISSET(mCtrlPipe[0], &read_fds)) {  
  42.                 char c = CtrlPipe_Shutdown;  
  43.                 TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1));  
  44.                 if (c == CtrlPipe_Shutdown) {  
  45.                     break;  
  46.                 }  
  47.                 continue;  
  48.             }  
  49.             if (mListen && FD_ISSET(mSock, &read_fds)) {           // 如果是CommandListener對象上有連接請求  
  50.                 struct sockaddr addr;  
  51.                 socklen_t alen;  
  52.                 int c;  
  53.   
  54.                 do {  
  55.                       alen = sizeof(addr);  
  56.                       c = accept(mSock, &addr, &alen);             // 接入連接請求  
  57.                       SLOGV("%s got %d from accept", mSocketName, c);  
  58.                 } while (c < 0 && errno == EINTR);                 // 如果是中斷導致失敗,重新接入  
  59.                 if (c < 0) {  
  60.                     SLOGE("accept failed (%s)", strerror(errno));  
  61.                     sleep(1);  
  62.                     continue;                                      // 接入發生錯誤,繼續循環  
  63.                 }  
  64.                 pthread_mutex_lock(&mClientsLock);  
  65.                 mClients->push_back(new SocketClient(c, true, mUseCmdNum));   // 把接入的socket連接加入到mClients,這樣再循環時就會監聽到它的數據到達  
  66.                 pthread_mutex_unlock(&mClientsLock);  
  67.             }  
  68.               
  69.             /* Add all active clients to the pending list first */  
  70.             pendingList.clear();  
  71.             pthread_mutex_lock(&mClientsLock);  
  72.             for (it = mClients->begin(); it != mClients->end(); ++it) {  
  73.                  SocketClient* c = *it;  
  74.                  int fd = c->getSocket();  
  75.                  if (FD_ISSET(fd, &read_fds)) {  
  76.                      pendingList.push_back(c);             // 如果mClients中的某個socket上有數據了,把它加入到pendingList列表中  
  77.                      c->incRef();  
  78.                  }  
  79.             }  
  80.             pthread_mutex_unlock(&mClientsLock);  
  81.   
  82.             /* Process the pending list, since it is owned by the thread,* there is no need to lock it */  
  83.             while (!pendingList.empty()) {                 // 處理pendingList列表  
  84.                   /* Pop the first item from the list */  
  85.                   it = pendingList.begin();  
  86.                   SocketClient* c = *it;  
  87.                   pendingList.erase(it);                   // 把處理了的socket從pendingList列表中刪除  
  88.                   /* Process it, if false is returned, remove from list */  
  89.                   if (!onDataAvailable(c)) {  
  90.                       release(c, false);   // 調用release()函數-->調用onDataAvailable()方法  
  91.                   }  
  92.                   c->decRef();  
  93.             }  
  94.       }  
  95. }  

  SocketListener::runListener是線程真正執行的函數。

  以上runListener()函數雖然比較長,但這是一段標准的處理混合socket連接的代碼,對於我們編寫socket的程序大有幫助,這裡先做簡單了解。

  <--------接下來,我們繼續分析......-------->

  runListener()函數收到從驅動傳遞的數據或者MountService傳遞的數據後,調用onDataAvailable()函數來處理,FrameworkListener類和NetlinkListener類都會重載這個函數。

  首先來分析一下NetlinkListener類的onDataAvailable()函數是如何實現的!

  直接上代碼:

Java代碼
  1. bool NetlinkListener::onDataAvailable(SocketClient *cli)  
  2. {  
  3.       int socket = cli->getSocket();  
  4.       ssize_t count;  
  5.       uid_t uid = -1;  
  6.       /*從socket中讀取kernel發送來的uevent消息*/  
  7.       count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_uid_recv(socket, mBuffer, sizeof(mBuffer), &uid));  
  8.       if (count < 0) {                     // 如果count<0,進行錯誤處理  
  9.           if (uid > 0)  
  10.               LOG_EVENT_INT(65537, uid);  
  11.           return false;  
  12.       }  
  13.   
  14.       NetlinkEvent *evt = new NetlinkEvent();     // 創建NetlinkEvent對象  
  15.       if (evt->decode(mBuffer, count, mFormat)) {     // 調用decode()函數  
  16.           onEvent(evt);                           // 在NetlinkHandler中實現17       } else if (mFormat != NETLINK_FORMAT_BINARY) {  
  17.           SLOGE("Error decoding NetlinkEvent");  
  18.       }  
  19.       delete evt;  
  20.       return true;  
  21. }  

  NetlinkListener類的onDataAvailable()函數首先調用uevent_kernel_multicast_uid_recv()函數來接收uevent消息。

  接收到消息後,會創建NetlinkEvent對象,然後調用它的decode()函數對消息進行解碼,然後用得到的消息數據給NetlinkEvent對象的成員變量賦值。

  最後onDataAvailable()函數調用了onEvent()函數繼續處理消息,onEvent()函數的代碼如下:

Java代碼
  1. void NetlinkHandler::onEvent(NetlinkEvent *evt) {  
  2.       VolumeManager *vm = VolumeManager::Instance();  
  3.       const char *subsys = evt->getSubsystem();  
  4.   
  5.       if (!subsys) {  
  6.           SLOGW("No subsystem found in netlink event");  
  7.           return;  
  8.       }  
  9.   
  10.       if (!strcmp(subsys, "block")) {  
  11.           vm->handleBlockEvent(evt);           // 調用VolumeManager的handleBlockEvent()函數來處理  
  12.       }  
  13. }  

  NetlinkHandler的onEvent()函數中會判斷event屬於哪個子系統的,如果屬於“block”(SD熱插拔),則調用VolumeManager的handleBlockEvent()函數來處理,代碼如下:

Java代碼
  1. void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {  
  2.       const char *devpath = evt->findParam("DEVPATH");  
  3.       VolumeCollection::iterator it;  
  4.       bool hit = false;  
  5.       for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {  
  6.            if (!(*it)->handleBlockEvent(evt)) {        // 對每個DirectVolume對象,調用它handleBlockEvent來處理這個event  
  7.                hit = true;                             // 如果某個Volume對象處理了Event,則返回  
  8.                break;  
  9.            }  
  10.       }  
  11. .....  
  12. }  

  總結:本帖的源碼分析先到這裡為止,下一貼再分析DirectVolume對象的handleBlockEvent()函數以及CommandListener對象如何處理從MountService發送的命令數據,即我們之前還沒有討論的關於FrameworkListener的onDataAvailable()函數的代碼!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved