chromium Mojo (译)

chromium官网对mojo的描述,地址如下,英语不太好,所以进行进行翻译如下:

https://chromium.googlesource.com/chromium/src.git/+/51.0.2704.48/docs/mojo_in_chromium.md。

Chromium的Mojo

本文档旨在用作Chromium开发人员的Mojo入门。 假定没有Mojo的相关认知。

目录

  • 我应该读这个吗?
  • 为什么选择Mojo?
  • Mojo概述
    • 消息管道
    • Mojom
    • 绑定管道
    • 回应请求
  • 在Chromium中公开服务
  • Mojo in Blink
  • 问题讨论等

我应该读这个吗?

如果您打算构建需要IPC的Chromium功能,并且尚未使用Mojo,那就可以! 旧版IPC已弃用。

为什么选择Mojo?

TL;DR: 长远的目的是将Chromium重构为一大批较小的服务。

我们可以更精明一些:

  • 我们提供或不提供哪些服务
  • 我们如何隔离这些服务以提高安全性和稳定性
  • 我们向一个或另一个用户提供哪些二进制功能

更强大的消息传递层为许多有趣的可能性打开了大门。 特别是,它允许我们集成大量组件而没有链接时的相互依赖性,并且打破了整个代码库中越来越多的有趣的跨语言边界。

在过去的几年中,从使用Chromium IPC和维护Chromium依赖关系中学到了很多东西,我们认为现在有很大的机会可以使开发人员的工作更轻松,并帮助他们更快,更轻松地构建更多更好的功能。 降低用户成本

Mojo概述

Mojo系统API提供了一小套低级IPC原语:消息管道,数据管道和共享缓冲区。 在此API之上,我们构建了更高级别的绑定API,以简化编写C ++,Java或JavaScript代码的消费者的消息传递。

本文档主要侧重于将C ++绑定与消息管道一起使用,这可能是Chromium开发人员遇到的最常见用法。

消息管道

消息管道是一种轻量级的原语,用于可靠地双向传输相对较小的数据包。 毫不奇怪,管道具有两个端点,并且任一端点都可以通过另一个消息管道进行传输。

因为我们在浏览器进程和每个子进程之间引入了原始消息管道,所以这意味着您可以创建一个新管道,并最终将任一端发送到任何进程,并且两端仍然可以无缝地相互通信。

尽管消息管道可以携带任意非结构化数据包,但我们通常将它们与生成的绑定结合使用,以确保所有端点上的一致性,定义良好的版本化消息结构。

Mojom

Mojom是Mojo接口的IDL。 给定一个.mojom文件,绑定生成器输出当前所有三种受支持语言的绑定。

For example:

// src/components/frob/public/interfaces/frobinator.mojom
module frob.mojom;

interface Frobinator {
  Frobinate();
};

would generate the following outputs:

out/Debug/gen/components/frob/public/interfaces/frobinator.mojom.cc
out/Debug/gen/components/frob/public/interfaces/frobinator.mojom.h
out/Debug/gen/components/frob/public/interfaces/frobinator.mojom.js
out/Debug/gen/components/frob/public/interfaces/frobinator.mojom.srcjar
...

生成的代码隐藏了在管道的两端对消息进行序列化和反序列化的所有详细信息。

C ++头(frobinator.mojom.h)为每个指定的mojom接口定义一个抽象类。 命名空间是从模块名称派生的。.

注意: chromium约定组件foo模块名称的为foo.mojom。 这意味着组件foo的所有由mojom生成的C ++类型名都将存在于foo :: mojom命名空间中,以避免与未生成的类型名发生冲突。

在此示例中,生成的frob :: mojom :: Frobinator具有单个纯虚函数:

namespace frob {

class Frobinator {
 public:
  virtual void Frobinate() = 0;
};

}  // namespace frob

要创建Frobinator服务,只需实现foo :: Frobinator并提供一种将管道绑定到它的方法。

绑定到管道

让我们看一些示例代码:

// src/components/frob/frobinator_impl.cc

#include "components/frob/public/interfaces/frobinator.mojom.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/interface_request.h"

namespace frob {

class FrobinatorImpl : public mojom::Frobinator {
 public:
  FrobinatorImpl(mojom::FrobinatorRequest request)
      : binding_(this, std::move(request)) {}
  ~FrobinatorImpl() override {}

  // mojom::Frobinator:
  void Frobinate() override { DLOG(INFO) << "I can't stop frobinating!"; }

 private:
  mojo::Binding binding_;
};

}  // namespace frob

首先要注意的是mojo :: Binding 将消息管道的一端绑定到服务的实现。 这意味着它将监视管道的末端是否有传入消息。 它知道如何解码接口T的消息,并将其分派到绑定T实现的方法中。

mojom :: FrobinatorRequest是mojo :: InterfaceRequest 的生成类型别名,本质上是强类型消息管道端点的语义糖。 创建新消息管道的常用方法是通过在interface_request.h中定义的GetProxy调用:

mojom::FrobinatorPtr proxy;
mojom::FrobinatorRequest request = mojo::GetProxy(&proxy);

这将创建一个新的消息管道,其一端由代理拥有,另一端由请求拥有。 它具有将普通类型信息附加到管道两端的不错的属性。

请注意,InterfaceRequest 实际上并没有任何作用。 它只是作用域管道端点,并在编译时将其与接口类型关联。 因此,其他类型的服务绑定原语(例如mojo :: Binding )在需要端点绑定时将这些对象用作输入。

mojom :: FrobinatorPtr是mojo :: InterfacePtr 的生成的类型别名。 InterfacePtr 也可以监视消息管道端点,但是它还通过序列化相应的消息并将其写入管道在内部实现T上的每个方法。

因此,我们可以将其放在一起以通过管道与FrobinatorImpl进行对话:

frob:mojom::FrobinatorPtr frobinator;
frob::FrobinatorImpl impl(GetProxy(&frobinator));

// Tada!
frobinator->Frobinate();

这会序列化与Frobinate请求相对应的消息并将其写入管道的一端。 最终,impl的内部mojo :: Binding将解码此消息并调度对impl.Frobinate()的调用。

注意: 在此示例中,服务和客户端处于同一过程中,并且工作正常。 如果它们处于不同的流程中(请参见下面的``在Chromium中公开服务''中的示例),则对Frobinate()的调用将看起来完全相同!

回应请求

Chromium IPC中的一个常见习惯是使用某种不透明标识符(即整数请求ID)来跟踪IPC请求,以便您以后可以在另一个方向上使用一些名义上相关的消息来响应特定请求。

我们可以像这样扩展我们的Frobinator服务:

module frob.mojom;

interface Frobinator {
  Frobinate();
  GetFrobinationLevels() => (int min, int max);
};

and update our implementation:

class FrobinatorImpl : public mojom::Frobinator {
 public:
  // ...

  // mojom::Frobinator:
  void Frobinate() override { /* ... */ }
  void GetFrobinationLevels(const GetFrobinationLevelsCallback& callback) {
    callback.Run(1, 42);
  }
};

当服务实现运行回调时,响应参数被序列化并通过管道发送回。 另一端的代理知道如何读取此响应,然后将其分派到该端的回调:

void ShowLevels(int min, int max) {
  DLOG(INFO) << "Frobinator min=" << min << " max=" << max;
}

// ...

  mojom::FrobinatorPtr frobinator;
  FrobinatorImpl impl(GetProxy(&frobinator));

  frobinator->GetFrobinatorLevels(base::Bind(&ShowLevels));

这正是您所期望的

在Chromium中公开服务

可以通过多种方式在浏览器的各个表面上公开服务。 现在一种常见的方法是使用content :: ServiceRegistry(link)。 这些通常成对出现,跨进程边界,并且它们提供原始服务注册和连接接口。 例如,每个RenderFrameHost和每个对应的RenderFrame都有一个ServiceRegistry。 这些注册表是交织在一起的。

要点是,您可以将服务添加到注册表的本地端(这只是从接口名称到工厂功能的映射),也可以按名称连接到在远程端注册的服务。

注意: 在这种情况下,“工厂功能”只是一个回调,它接受管道端点并对其执行某些操作。 期望您将其绑定到某种服务实现中,或者将其关闭,以有效地拒绝连接请求。

我们可以构建一个简单的浏览器端FrobinatorImpl服务,该服务可以访问与其连接的任何框架的BrowserContext:

#include "base/macros.h"
#include "components/frob/public/interfaces/frobinator.mojom.h"
#include "content/public/browser/browser_context.h"
#include "mojo/public/cpp/system/interface_request.h"
#include "mojo/public/cpp/system/strong_binding.h"

namespace frob {

class FrobinatorImpl : public mojom::Frobinator {
 public:
  FrobinatorImpl(content::BrowserContext* context,
                 mojom::FrobinatorRequest request)
      : context_(context), binding_(this, std::move(request)) {}
  ~FrobinatorImpl() override {}

  // A factory function to use in conjunction with ServiceRegistry.
  static void Create(content::BrowserContext* context,
                     mojom::FrobinatorRequest request) {
    // See comment below for why this doesn't leak.
    new FrobinatorImpl(context, std::move(request));
  }

 private:
  // mojom::Frobinator:
  void Frobinate() override { /* ... */ }

  content::BrowserContext* context_;

  // A StrongBinding is just like a Binding, except that it takes ownership of
  // its bound implementation and deletes itself (and the impl) if and when the
  // bound pipe encounters an error or is closed on the other end.
  mojo::StrongBinding binding_;

  DISALLOW_COPY_AND_ASSIGN(FrobinatorImpl);
};

}  // namespace frob

Now somewhere in the browser we register the Frobinator service with each RenderFrameHost (this is a popular spot):

frame_host->GetServiceRegistry()->AddService(
    base::Bind(
        &frob::FrobinatorImpl::Create,
        base::Unretained(frame_host->GetProcess()->GetBrowserContext())));

And in the render process we can now do something like:

mojom::FrobinatorPtr frobinator;
render_frame->GetServiceRegistry()->ConnectToRemoteService(
    mojo::GetProxy(&frobinator));

// It's IPC!
frobinator->Frobinate();

现在,在Chromium树中有许多Mojo用法的具体示例。 探究现有的mojom文件,看看它们的实现是如何构建和连接的。

Mojo in Blink

TODO

这是一个进展中的工作。 TL; DR:我们还将很快开始使用Blink的Mojo服务,以便平台层可以直接通过Mojo使用浏览器服务。

问题讨论等

chromium-mojo邮件列表是找到高度集中了解和关心Chromium中Mojo的人的好地方。

你可能感兴趣的:(chromium)