zoukankan      html  css  js  c++  java
  • chromium mojo 快速入门

    版权声明:本文为CSDN博主「tornmy」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:

    • https://blog.csdn.net/tornmy/article/details/82748058

     https://blog.csdn.net/mengxin00100/article/details/106325249?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase

    • https://blog.csdn.net/qq_27022241/article/details/103906792

     这是对chromium文档的翻译:src/docs/mojo_and_services.md

    消息管道:是一组端点. 每个endpoint有一个接受消息的队列, 在一个端点上写消息会高效地放入对端端点的消息队列上。所以消息管道是双工通信的。

    mojom文件:描述了接口,它们描述了类似proto files的强类型消息结构,通过binding generator可以产生对应于不同语言的文件。

    给定一个mojom interface和一条message pipe, 它的两个端点可以打上InterfacePtr和Binding的标签。现在它描述了一条这样的message pipe,它发送由mojom interface描述的消息。

    InterfacePtr:是发送消息的端点,一旦绑定到一个消息管道的端点,就可以马上序列化要发送的消息,并写入管道

    InterfaceRequest:是接受消息的端点,本质上仅仅是一个持有消息管道端点的容器,本身不会做任何事情,需要传递到直到绑定了实现了mojom文件接口的类,才能读取消息。

    考虑如下的mojom文件:

    module sample.mojom;

    interface Logger {
    Log(string message);
    };
    通过mojo的binding generator可以产生以下的logging.mojom.h的c++文件:

    namespace sample {
    namespace mojom {

    class Logger {
    virtual ~Logger() {}

    virtual void Log(const std::string& message) = 0;
    };

    using LoggerPtr = mojo::InterfacePtr<Logger>;
    using LoggerRequest = mojo::InterfaceRequest<Logger>;

    } // namespace mojom
    } // namespace sample
     首先需要创建消息管道,通常调用MakeRequest创建:

    #include "sample/logger.mojom.h"

    sample::mojom::LoggerPtr logger;
    auto request = mojo::MakeRequest(&logger);
    MakeRequset的如下: 

    template <typename Interface>
    InterfaceRequest<Interface> MakeRequest(
    InterfacePtr<Interface>* ptr,
    scoped_refptr<base::SingleThreadTaskRunner> runner = nullptr) {
    MessagePipe pipe;
    ptr->Bind(InterfacePtrInfo<Interface>(std::move(pipe.handle0), 0u),
    std::move(runner));
    return InterfaceRequest<Interface>(std::move(pipe.handle1));
    }
    可见创建消息管道的同时,InterfacePtr端已经绑定到了消息管道的一端,也就是此时,InterfacePtr已经可以向消息管道发送消息了,当然对端还未绑定,发送的消息会堆积在对端。 

    接下来就需要绑定InterfaceRequest端,即LoggerRequest,一旦绑定,就会安排一个task去读取、反序列化并分化所有可读的消息给mojom文件中接口实现类。例如接口类实现如下:

    #include "base/logging.h"
    #include "base/macros.h"
    #include "sample/logger.mojom.h"

    class LoggerImpl : public sample::mojom::Logger {
    public:
    // NOTE: A common pattern for interface implementations which have one
    // instance per client is to take an InterfaceRequest in the constructor.

    explicit LoggerImpl(sample::mojom::LoggerRequest request)
    : binding_(this, std::move(request)) {}
    ~Logger() override {}

    // sample::mojom::Logger:
    void Log(const std::string& message) override {
    LOG(ERROR) << "[Logger] " << message;
    }

    private:
    mojo::Binding<sample::mojom::Logger> binding_;

    DISALLOW_COPY_AND_ASSIGN(LoggerImpl);
    };
    此时我们可以使用前面构造的LoggerRequest构造一个LoggerImpl,一但构造完成,消息就会尽可能快地发送给LoggerImpl。最终就可以在实现类的一端看到Logger发送的“hello”。

    总的流程可以概括如下:

    当然有时候发送端可能期望有一个回复,此时mojom接口可以调整为

    module sample.mojom;

    interface Logger {
    Log(string message);
    GetTail() => (string message);
    };
    其中,Log中的message参数和GetTail后置的message都是会被序列化进管道传送的消息。对应的C++文件如下:

    namespace sample {
    namespace mojom {

    class Logger {
    public:
    virtual ~Logger() {}

    virtual void Log(const std::string& message) = 0;

    using GetTailCallback = base::OnceCallback<void(const std::string& message)>;

    virtual void GetTail(GetTailCallback callback) = 0;
    }

    } // namespace mojom
    } // namespace sample
    和不需要回复的版本一样,发送端调用的接口,在实现端也会对应的被调用,而其中的GetTail,发送端发送一个回调函数的参数以接受回复。

    接受端的实现类如下

    class LoggerImpl : public sample::mojom::Logger {
    public:
    // NOTE: A common pattern for interface implementations which have one
    // instance per client is to take an InterfaceRequest in the constructor.

    explicit LoggerImpl(sample::mojom::LoggerRequest request)
    : binding_(this, std::move(request)) {}
    ~Logger() override {}

    // sample::mojom::Logger:
    void Log(const std::string& message) override {
    LOG(ERROR) << "[Logger] " << message;
    lines_.push_back(message);
    }

    void GetTail(GetTailCallback callback) override {
    std::move(callback).Run(lines_.back());
    }

    private:
    mojo::Binding<sample::mojom::Logger> binding_;
    std::vector<std::string> lines_;

    DISALLOW_COPY_AND_ASSIGN(LoggerImpl);
    那么,在发送端发送过消息后,即调用过Log后,继续如下调用GetTail

    void OnGetTail(const std::string& message) {
    LOG(ERROR) << "Tail was: " << message;
    }

    logger->GetTail(base::BindOnce(&OnGetTail));
    那么在实现端调用了GetTail后,将会将line_.back()序列化并发送回发送端,同时遵循发送端的内部逻辑,触发回调函数得到发送过去的最后一条消息。 

    当然在browser和renderer通信时, browser其实通过消息管道连接到Service Manager,由它统一管理和render进程的连接。此时需要在browser的manifet文件和renderer的manifest文件中申明,如下

    content_renderer_manifest.json:
    ...
    "interface_provider_specs": {
    "service_manager:connector": {
    "provides": {
    "cool_ping_feature": [
    "sample::mojom::Logger"
    ]
    },
    },
    ...
    content_browser_manifest.json:
    ...
    "interface_provider_specs": {
    "service_manager:connector": {
    "requires": {
    "content_renderer": [ "cool_ping_feature" ],
    },
    },
    },
    ...
    在renderer端则可以如下实现接口类,并通常在Init时注册到Service Manager,

    class LoggerImpl : mojom::Logger {
    void BindToInterface(example::mojom::LoggerRequest request) {
    binding_.reset(
    new mojo::Binding<mojom::MemlogClient>(this, std::move(request)));
    }
    void Log(const std::string& message) override {
    LOG(ERROR) << "[Logger] " << message;
    lines_.push_back(message);
    }
    void GetTail(LoggerCallback callback) { std::move(callback).Run(4); }
    std::unique_ptr<mojo::Binding<mojom::Logger>> binding_;
    };

    RenderThreadImpl::Init() {
    ...
    this->logger = std::make_unique<LoggerImpl>();
    auto registry = base::MakeUnique<service_manager::BinderRegistry>();

    // This makes the assumption that |this->logger| will outlive |registry|.
    registry->AddInterface(base::Bind(&LoggerImpl::BindToInterface), base::Unretained(this->Logger.get()));

    GetServiceManagerConnection()->AddConnectionFilter(
    base::MakeUnique<SimpleConnectionFilter>(std::move(registry)));
    ...
    }
    那么此时,browser端可以如下建立与renderer的连接,通常有如下两种方式

    sample::mojom::LoggerPtr logger; // Make sure to keep this alive! Otherwise the response will never be received.
    sample::mojom::LoggerRequest request = mojo::MakeRequest(&logger);
    logger->GetTail(base::BindOnce(&OnGetTail));
    content::RenderProcessHost* host = GetRenderProcessHost();
    content::BindInterface(host, std::move(request));
    其中content::BindInterface是一个辅助接口,通过Service Manager通过postTask将request传送给renderer,创建对应的LoggerImpl,完成连接。

    或者

    sample::mojom::LoggerPtr logger;
    render_frame->GetRemoteInterfaces()->GetInterface(mojo::MakeRequest(&logger));
    logger->GetTail(base::BindOnce(&OnGetTail));
    RenderProcessHost作为sender,RenderProcess为receiver的例子如下, 

    void RenderProcessHostImpl::InitializeChannelProxy() {
    ...
    content::BindInterface(this, &child_control_interface_);
    ...
    }


    template <typename Host, typename Interface>
    void BindInterface(Host* host, mojo::InterfacePtr<Interface>* ptr) {
    mojo::MessagePipe pipe;
    ptr->Bind(mojo::InterfacePtrInfo<Interface>(std::move(pipe.handle0), 0u));
    host->BindInterface(Interface::Name_, std::move(pipe.handle1));
    }
    renderer和browser建立通信,更详细的可以看这个帖子。

    Mojo in Chromium

    Mojo C++ System API

    Mojo C++ Bindings API

    Understanding mojo behavior
    ————————————————

  • 相关阅读:
    css3 2D变形(transform)移动、缩放、旋转、倾斜
    鼠标经过图片会移动(css3过渡,overflow:hidden)
    CSS3 过渡 (transition )
    LICEcap – 灵活好用,GIF 屏幕录制工具
    CSS3新增选择器:伪元素选择器
    CSS3 新增选择器:伪类选择器和属性选择器
    HTML插入音频和视频:audio和video标签及其属性
    HTML5新增input标签属性
    HTML5新增常用标签
    通过EntityFramework来操作MySQL数据库
  • 原文地址:https://www.cnblogs.com/bigben0123/p/13183078.html
Copyright © 2011-2022 走看看