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函数的实现。

    原文作者:Android源码分析
    原文地址: https://blog.csdn.net/gzshun/article/details/7110296
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞