Android vold通讯篇(CommandListener)

来源:互联网 发布:直接引用vue.js没反应 编辑:程序博客网 时间:2024/06/08 19:22

前一篇文章:Androidvold核心篇,介绍了vold接收到NetlinkManager发来的内核消息进行对应的处理后(包含挂载卸载等),将处理后的结果发送到FrameWrok,具体是怎么发送的,以及怎么接收从Framework发来的消息,在本文解析。

一、CommandListener类的实现

我们回到Main.cpp的主函数main中,里面有定义一个变量如下:

CommandListener *cl;

cl = new CommandListener();
那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 AsecCmd : public VoldCommand {    public:        AsecCmd();        virtual ~AsecCmd() {}        int runCommand(SocketClient *c, int argc, char ** argv);    private:        void listAsecsInDirectory(SocketClient *c, const char *directory);    };    class ObbCmd : public VoldCommand {    public:        ObbCmd();        virtual ~ObbCmd() {}        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);    };    class CryptfsCmd : public VoldCommand {    public:        CryptfsCmd();        virtual ~CryptfsCmd() {}        int runCommand(SocketClient *c, int argc, char ** argv);    };    class FstrimCmd : public VoldCommand {    public:        FstrimCmd();        virtual ~FstrimCmd() {}        int runCommand(SocketClient *c, int argc, char ** argv);    };};
我们知道它继承自FrameworkListener,且定义了很多了内部类,这些内部类都继承自VoldCommand,关于VoldCommand稍后我们会介绍。

那么FrameworkListener类又是干什么的呢?

class FrameworkListener : public SocketListener {public:    static const int CMD_ARGS_MAX = 26;    /* 1 out of errorRate will be dropped */    int errorRate;private:    int mCommandCount;    bool mWithSeq;    FrameworkCommandCollection *mCommands;public:    FrameworkListener(const char *socketName);    FrameworkListener(const char *socketName, bool withSeq);    virtual ~FrameworkListener() {}protected:    void registerCmd(FrameworkCommand *cmd);    virtual bool onDataAvailable(SocketClient *c);private:    void dispatchCommand(SocketClient *c, char *data);    void init(const char *socketName, bool withSeq);};
原来FrameworkListener继承自SocketListener;

现在请关注一下FrameworkListener的两个构造函数,我们发现它的构造函数都需要有参数,但是CommandListener的构造函数确没有

那就看一下CommandListener的构造函数的实现,如下:

CommandListener::CommandListener() :                 FrameworkListener("vold", true) {    registerCmd(new DumpCmd());    registerCmd(new VolumeCmd());    registerCmd(new AsecCmd());    registerCmd(new ObbCmd());    registerCmd(new StorageCmd());    registerCmd(new XwarpCmd());    registerCmd(new CryptfsCmd());    registerCmd(new FstrimCmd());}
哦,原来是给FrameworkListener传了一个常量的字符串“vold”,通过代码的追踪发现,这个参数传到了SocketListener中,根据该字符串创建了一个套接字,

将该套接字包装到了SocketClient类对象,而该对象保存在mClients集合变量中。


从这个构造函数中,还可以发现,这里注册了很多的类对象,而这些类都是在CommandListener中创建的内部类(参考CommandListener的实现)。

那么registerCmd是干什么用的呢,此时需要跳转到FrameworkListener的registerCmd函数:

void FrameworkListener::registerCmd(FrameworkCommand *cmd) {    mCommands->push_back(cmd);}

关于mCommands成员变量,:

FrameworkCommandCollection *mCommands;
而FrameworkCommandCollection 实际是一个FrameworkCommand类对象的集合

通过registerCmd可以推断出在CommandListener中创建的内部类应该都为FrameworkCommand的子类,从CommandListener的内部类的定义可以知道,所有的内部内都继承自VoldCommand,而VoldCommand类则是简单的继承钰FrameworkCommand,代码如下(前面有提到过该类,但是没有详细介绍):

class VoldCommand : public FrameworkCommand {public:    VoldCommand(const char *cmd);    virtual ~VoldCommand() {}};

到这里,可以说把跟CommandListener类相关的类都理清了。

总结一下:

CommandListener的最终根父类为SocketListener;

CommandListener对象在构造的过程中,在SocketListener构造函数中创建了“vold”套接字;

CommandListener对象在构造的过程中,注册了一些从FrameworkCommand类派生的类对象;


二、CommandListener是如何发挥作用的

在main函数中,有这么一段代码:

if (cl->startListener()) {        SLOGE("Unable to start CommandListener (%s)", strerror(errno));        exit(1);    }
由第一段“CommandListener的实现”知道,CommandListener最终的根父类是SocketListener,在上面代码中调用的startListener函数正是在SocketListener中实现的,其实关于SocketListener的startListener函数在我的前一遍博文Androidvold启动篇中分析过,此处简单提一下:

startListener函数基于前面创建的vold套接字,对Framework发送的消息进行监听,并且传递到FrameworkListener::onDataAvailable的函数中进行处理,再到FrameworkListener::dispatchCommand函数中进行处理,在该函数中的核心代码如下:

for (i = mCommands->begin(); i != mCommands->end(); ++i) {        FrameworkCommand *c = *i;        if (!strcmp(argv[0], c->getCommand())) {            if (c->runCommand(cli, argc, argv)) {                SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));            }            goto out;        }    }
也就是说,此时从Framework发下来的消息传递到了从VoldCommand类派生的子类中,

下面分析一个派生类:VolumeCmd的runCommand函数,代码比较多但是很清晰,可以快速浏览:

int CommandListener::VolumeCmd::runCommand(SocketClient *cli,                                                      int argc, char **argv) {    dumpArgs(argc, argv, -1);    if (argc < 2) {        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);        return 0;    }    VolumeManager *vm = VolumeManager::Instance();    int rc = 0;    if (!strcmp(argv[1], "list")) {        return vm->listVolumes(cli);    } else if (!strcmp(argv[1], "debug")) {        if (argc != 3 || (argc == 3 && (strcmp(argv[2], "off") && strcmp(argv[2], "on")))) {            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume debug <off/on>", false);            return 0;        }        vm->setDebug(!strcmp(argv[2], "on") ? true : false);    } else if (!strcmp(argv[1], "mount")) {        if (argc != 3) {            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false);            return 0;        }        rc = vm->mountVolume(argv[2]);    } else if (!strcmp(argv[1], "unmount")) {        if (argc < 3 || argc > 4 ||           ((argc == 4 && strcmp(argv[3], "force")) &&            (argc == 4 && strcmp(argv[3], "force_and_revert")))) {            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume unmount <path> [force|force_and_revert]", false);            return 0;        }        bool force = false;        bool revert = false;        if (argc >= 4 && !strcmp(argv[3], "force")) {            force = true;        } else if (argc >= 4 && !strcmp(argv[3], "force_and_revert")) {            force = true;            revert = true;        }        rc = vm->unmountVolume(argv[2], force, revert);    } else if (!strcmp(argv[1], "format")) {        if (argc < 3 || argc > 4 ||            (argc == 4 && strcmp(argv[3], "wipe"))) {            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume format <path> [wipe]", false);            return 0;        }        bool wipe = false;        if (argc >= 4 && !strcmp(argv[3], "wipe")) {            wipe = true;        }        rc = vm->formatVolume(argv[2], wipe);    } else if (!strcmp(argv[1], "share")) {        if (argc != 4) {            cli->sendMsg(ResponseCode::CommandSyntaxError,                    "Usage: volume share <path> <method>", false);            return 0;        }        rc = vm->shareVolume(argv[2], argv[3]);    } else if (!strcmp(argv[1], "unshare")) {        if (argc != 4) {            cli->sendMsg(ResponseCode::CommandSyntaxError,                    "Usage: volume unshare <path> <method>", false);            return 0;        }        rc = vm->unshareVolume(argv[2], argv[3]);    } else if (!strcmp(argv[1], "shared")) {        bool enabled = false;        if (argc != 4) {            cli->sendMsg(ResponseCode::CommandSyntaxError,                    "Usage: volume shared <path> <method>", false);            return 0;        }        if (vm->shareEnabled(argv[2], argv[3], &enabled)) {            cli->sendMsg(                    ResponseCode::OperationFailed, "Failed to determine share enable state", true);        } else {            cli->sendMsg(ResponseCode::ShareEnabledResult,                    (enabled ? "Share enabled" : "Share disabled"), false);        }        return 0;    } else if (!strcmp(argv[1], "mkdirs")) {        if (argc != 3) {            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mkdirs <path>", false);            return 0;        }        rc = vm->mkdirs(argv[2]);    } else {        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume cmd", false);    }    if (!rc) {        cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false);    } else {        int erno = errno;        rc = ResponseCode::convertFromErrno();        cli->sendMsg(rc, "volume operation failed", true);    }    return 0;}
通过上面的代码可知,此函数实现了挂载、共享、格式化等操作,并且操作完成或者发生错误时,会将消息返回给Framewrok。


三、vold向上层发送消息

在Android vold核心篇的最后,我们提到了疑问,vold向Framewrok层发送消息时使用的SocketListener的成员变量mClients(SocketClientCollection类型)是如何来的,以及mClient集合的元素的套接字又是怎么来的,通过以上分析我相信大家应该知道了吧。


四、总结

CommandListener的作用:

将vold层的消息发送到Framewrok层

接收Framewrok的消息,进行处理

CommandListener就是vold与Framework的通讯核心。







0 0
原创粉丝点击