Android-vold源码分析之startListener(6)

作者:gzshun. 原创作品,转载请标明出处!

vold处理完磁盘事件,就要开始接受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函数的实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值