Android的存储系统(三)

回顾:前帖分析了Vold的main()函数和NetlinkManager的函数调用流程,截止到NetlinkHandler的创建和start()调用,本帖继续分析源码

1、处理block类型的uevent

  main()函数创建了CommandListener对象,NetlinkManager的start()函数又创建了NetlinkHandler对象,如果将CommandListener类和NetlinkHandler类的继承关系图画出来,会发现它们都是从SocketListener类派生出来的,如下图所示:

图1 NetlinkHandler和CommandListener的继承关系

  原理:处于最底层的SocketListener类的作用是监听socket的数据,接收到数据后分别交给FrameworkListener类和NetlinkListener类的函数,并分别对来自Framework和驱动的数据进行分析,分析后根据命令再分别调用CommandListener和NetlinkHandler中的函数。

  观察NetlinkHandler类的构造方法,代码如下:

NetlinkHandler::NetlinkHandler(int listenerSocket) :                NetlinkListener(listenerSocket) {}

  这个构造方法很简单,再看看它的start()方法,代码如下:

int NetlinkHandler::start() {    return this->startListener();}

  可以发现,start()方法调用了SocketListener的startListener()函数,代码如下:

 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家族图系中我们可以清晰的发现,其代码如下:

void *SocketListener::threadStart(void *obj) {     SocketListener *me = reinterpret_cast<SocketListener *>(obj);     me->runListener();                                             // 调用runListener()方法     pthread_exit(NULL);     return NULL;}

  threadStart()中又调用了runListener()函数,代码如下:

 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()函数是如何实现的!

  直接上代码:

 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) {18           SLOGE("Error decoding NetlinkEvent");19       }20       delete evt;21       return true;22 }

  NetlinkListener类的onDataAvailable()函数首先调用uevent_kernel_multicast_uid_recv()函数来接收uevent消息。

  接收到消息后,会创建NetlinkEvent对象,然后调用它的decode()函数对消息进行解码,然后用得到的消息数据给NetlinkEvent对象的成员变量赋值。

  最后onDataAvailable()函数调用了onEvent()函数继续处理消息,onEvent()函数的代码如下:

void NetlinkHandler::onEvent(NetlinkEvent *evt) {      VolumeManager *vm = VolumeManager::Instance();      const char *subsys = evt->getSubsystem();      if (!subsys) {          SLOGW("No subsystem found in netlink event");          return;      }      if (!strcmp(subsys, "block")) {          vm->handleBlockEvent(evt);           // 调用VolumeManager的handleBlockEvent()函数来处理      }}

  NetlinkHandler的onEvent()函数中会判断event属于哪个子系统的,如果属于“block”(SD热插拔),则调用VolumeManager的handleBlockEvent()函数来处理,代码如下:

void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {      const char *devpath = evt->findParam("DEVPATH");      VolumeCollection::iterator it;      bool hit = false;      for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {           if (!(*it)->handleBlockEvent(evt)) {        // 对每个DirectVolume对象,调用它handleBlockEvent来处理这个event               hit = true;                             // 如果某个Volume对象处理了Event,则返回 break;           }      }.....}

总结:本帖的源码分析先到这里为止,下一贴再分析DirectVolume对象的handleBlockEvent()函数以及CommandListener对象如何处理从MountService发送的命令数据,即我们之前还没有讨论的关于FrameworkListener的onDataAvailable()函数的代码!

PS:希望对Android手机开发、IOS、以及游戏(纯兴趣,白菜)和Java EE感兴趣的码友们互粉,这样我也能及时的看到你们的大神之作和经验之贴,感谢感谢!

更多相关文章

  1. 关于Android的浅杀
  2. Android之ViewModel
  3. Android(安卓)VelocityTracker简介
  4. android 6.0 以上 动态申请多个权限
  5. Android短彩信收发流程(应用层)
  6. 使用traceview进行Android性能测试
  7. Android使用Fragment来实现ViewPager的功能(解决切换Fragment状态
  8. SecureRandom漏洞解析
  9. Android(安卓)中application 详解

随机推荐

  1. Android设置launchMode为singleTask的Act
  2. Android(安卓)使用obb扩展App
  3. AIR Native Extension on Android(安卓)-
  4. Android(安卓)集成TBS浏览文档,不调用手
  5. Android实现文件的复制
  6. Android处理器
  7. Android(安卓)之 Shader 用法详细介绍
  8. Android通过HttpURLConnection获取JSON并
  9. Android(安卓)读取手机通讯录内容
  10. Android强大的图片加载框架Fresco简单用