Android vold通讯篇(CommandListener)

前一篇文章: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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值