作者:gzshun. 原创作品,转载请标明出处!
vold处理完磁盘事件,就要开始接受framework的操作命令,在main函数里面,开启了一个线程来监听framework的信息,当收到操作命令,vold进行解析,分析出命令,然后调用相应的磁盘操作函数,待操作完成后,再将操作结果的状态值反馈给framework,中间均使用了广播机制,使用了UDP协议。
cl是CommandListener类实例化的一个对象,该对象专门负责与framework的通信,首先说明与CommandListener类相关的一些继承关系。
CommandListener --> FrameworkListener --> SocketListener(父类)
在CommandListener类中,声明了6个类,这6个类继承了VoldCommand类,VoldCommand类继承了FrameworkCommand,关系如下:
VoldCommand --> FrameworkCommand(父类)
以下是CommandListener类的声明:
在这个类中,VoldCommand主要写了一个纯虚函数runCommand,声明如下:
virtual int runCommand(SocketClient *c, int argc, char **argv) = 0;
为了就是在CommandListener类中的实现,这里总共实现了6个版本的runCommand函数,下一篇文章只讨论其中一个比较重要的VolumeCmd类的实现,其余的跟这个类的实现差不多。
开始深入startListener线程:
进入startListener函数,创建了以下线程:
这里跟前几章线程的创建几乎一样,
线程真正实现的函数在这里:
将收到的命令交给onDataAvailable函数来处理,onDataAvailable函数是类的纯虚函数,在FrameworkListener类实现了该函数:
dispatchCommand函数用来选择不同的分支函数,因为在类有6个分支的实现版本,包括DumpCmd,VolumeCmd,ShareCmd,AsecCmd,StorageCmd和XwarpCmd。以下是dispatchCommand函数的源码:
这里从代码可能有点疑问,这个循环为什么可以选择不同的分支新实现的函数呢?
仔细看下代码会发现,在FrameworkListener中有一个注册函数,将新的派生类的名字注册到mCommands容器中,每个类的mCommand参数各代表一个派生类的名字。
在CommandListener类的构造函数中,分别对6个分支的派生类进行了注册,每次注册都实例化了一个新的对象存放到mCommands容器中。
那这6个派生类的名称保存在FrameworkCommand类的一个私有变量mCommand中,该类的构造函数就是给mCommand赋值,源码:
在刚才的FrameworkListener::dispatchCommand函数里,有这么一个比较:
getCommand函数的源码:
6个构造函数均初始化不同的cmd参数,分别为dump,volume,share,storage,asec,xwarp。
在VoldCommand类的构造函数中,将cmd的值初始化FrameworkCommand类的构造函数。
现在流程就走到了runCommand函数,该函数就声明在最上面那个CommandListener类里面,下一篇文章将介绍runCommand函数的实现。
vold处理完磁盘事件,就要开始接受framework的操作命令,在main函数里面,开启了一个线程来监听framework的信息,当收到操作命令,vold进行解析,分析出命令,然后调用相应的磁盘操作函数,待操作完成后,再将操作结果的状态值反馈给framework,中间均使用了广播机制,使用了UDP协议。
在main函数中,有以下函数的调用:
- if (cl->startListener()) {
- SLOGE("Unable to start CommandListener (%s)", strerror(errno));
- exit(1);
- }
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);
- };
- };
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);
- }
- }
- 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;
- }
- 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::CommandListener() :
- FrameworkListener("vold") {
- registerCmd(new DumpCmd());
- registerCmd(new VolumeCmd());
- registerCmd(new AsecCmd());
- registerCmd(new ShareCmd());
- registerCmd(new StorageCmd());
- registerCmd(new XwarpCmd());
- }
- FrameworkCommand::FrameworkCommand(const char *cmd) {
- mCommand = cmd;
- }
- if (!strcmp(argv[0], c->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函数的实现。