您的位置:首页 > 移动开发 > Android开发

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

2012-04-09 18:21 387 查看
作者:gzshun. 原创作品,转载请标明出处!

vold处理完磁盘事件,就要开始接受framework的操作命令,在main函数里面,开启了一个线程来监听framework的信息,当收到操作命令,vold进行解析,分析出命令,然后调用相应的磁盘操作函数,待操作完成后,再将操作结果的状态值反馈给framework,中间均使用了广播机制,使用了UDP协议。

在main函数中,有以下函数的调用:

[cpp] view
plaincopy

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类的声明:

[cpp] view
plaincopy

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函数,创建了以下线程:

[cpp] view
plaincopy

if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {

SLOGE("pthread_create (%s)", strerror(errno));

return -1;

}

这里跟前几章线程的创建几乎一样,

[cpp] view
plaincopy

void *SocketListener::threadStart(void *obj) {

SocketListener *me = reinterpret_cast<SocketListener *>(obj);

me->runListener();

pthread_exit(NULL);

return NULL;

}

线程真正实现的函数在这里:

[cpp] view
plaincopy

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类实现了该函数:

[cpp] view
plaincopy

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函数的源码:

[cpp] view
plaincopy

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参数各代表一个派生类的名字。

[cpp] view
plaincopy

void FrameworkListener::registerCmd(FrameworkCommand *cmd) {

mCommands->push_back(cmd);

}

在CommandListener类的构造函数中,分别对6个分支的派生类进行了注册,每次注册都实例化了一个新的对象存放到mCommands容器中。

[cpp] view
plaincopy

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赋值,源码:

[cpp] view
plaincopy

FrameworkCommand::FrameworkCommand(const char *cmd) {

mCommand = cmd;

}

在刚才的FrameworkListener::dispatchCommand函数里,有这么一个比较:

[cpp] view
plaincopy

if (!strcmp(argv[0], c->getCommand())){}

getCommand函数的源码:

[cpp] view
plaincopy

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这个参数,以下是初始化代码:

[cpp] view
plaincopy

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类的构造函数。

[cpp] view
plaincopy

VoldCommand::VoldCommand(const char *cmd) :

FrameworkCommand(cmd) {

}

所以这个比较,就是将framework发下来的命令的第一个参数与mCommands容器中的6个对象的mCommand参数进行了比较,从而选择正确的处理分支函数。
以上的内容涉及到好几个类,谷歌真是花了很大的力气啊。。

现在流程就走到了runCommand函数,该函数就声明在最上面那个CommandListener类里面,下一篇文章将介绍runCommand函数的实现。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: