For Developers‎ > ‎Design Documents‎ > ‎Mojo‎ > ‎

Mojo Migration Guide

Summary

We’re migrating Chrome’s IPCs to Mojo, our new IPC system. See the chromium-dev post for the motivation behind this project.

How do I migrate my IPC to Mojo?

Don’t panic

If you get stuck reach out to chromium-mojo@ and we’ll help. :)

Read the Mojo documentation

The Mojo documentation and a getting started guide can be found on the Mojo documentation page. There’s also a Chrome IPC To Mojo IPC Cheat Sheet which is particularly useful for this conversion.

Claim your message(s)

We track the messages that still need to be converted in two spreadsheets:
Please put your username next to the one(s) you’re converting to prevent duplication of effort. If you’re not very familiar with the messages you plan to convert, it might be worth asking the owner first.

Convert your Chrome IPCs to Mojo

Converting from Chrome IPC to Mojo is mostly straightforward, but still requires some thought. Here we outline the basic approach. See the Chrome IPC To Mojo IPC Cheat Sheet for more details. See the "Common scenarios" section below for commonly occurring scenarios.
 
The below examples snippets were taken from https://codereview.chromium.org/2024363002, where you can find a complete example. The code below removes some details from that CL for clearer presentation.

Convert the message definition

The old Chrome IPC system uses macros to generate IPC “stubs”. In Mojo we use an IDL. For example, if you previously had this old-style IPC message defined in mime_registry_messages.h:
 
 
IPC_SYNC_MESSAGE_CONTROL1_1(MimeRegistryMsg_GetMimeTypeFromExtension,   
                            base::FilePath::StringType /* extension */, 
                            std::string /* mime_type */)
 
You need to replace that with this .mojom file:
 
 
module blink.mojom;
 
 
interface MimeRegistry {
  [Sync]
  GetMimeTypeFromExtension(string extension) => (string mime_type);
};
 
Note that Mojo can group several messages together into an interface, which helps bring some structure to Chrome’s many IPCs.

Whitelist the IPC

We don't want every process to be able to talk to every other process so we maintain a whitelist of which interfaces each process exports. You will need to add your interface to the right whitelist. If you don't you'll find that e.g. browser tests fail with an error saying that the connection to the interface was disallowed.
 
There are several of these files e.g. chrome/browser/chrome_content_utility_manifest_overlay.json lists the interfaces exported by the utility process to the browser process. You will have to find the corresponding JSON file your process.

Fix build files and includes

Add a build target for your new .mojom file:
 
 
import("//mojo/public/tools/bindings/mojom.gni")
mojom("mime_registry_mojom") {
  sources = [
    "platform/mime_registry.mojom",
  ]
}
 
If your new .mojom file imports any other .mojom files, add their targets as public_deps above.
 
Include the generated Mojo header in your C++ file instead of the old IPC header:
 
#include "third_party/WebKit/public/platform/mime_registry.mojom.h"

Register the interface implementation

Interface implementations (the "server" side of the interface) need to be registered before they can be called by a client. The registration happens in interface registries. Such registries can be accessed in the various processes (e.g. one is passed to RenderProcessHostImpl::RegisterMojoInterfaces, in which you can register your service).
 
Here’s now you get the InterfaceRegistry to register the interface implementation on, depending on where the message is sent from and if the old Chrome IPC message was routed or not:
 
   Renderer-initiated  Browser-initiated
 Routed  RenderFrameHost::GetInterfaceRegistry()  RenderFrame::GetInterfaceRegistry()
 Control  RenderProcessHostImpl::RegisterMojoInterfaces()  RenderThreadImpl::Init()
Example:
 
 
GetInterfaceRegistry()->AddInterface(
    base::Bind(&MimeRegistryImpl::Create),
    BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
 
(In the above example we want messages to be handled on a particular thread, so we pass an optional argument to indicate that.)
 
As you can see above, the interface implementation is created lazily when a connection is created through the call to MimeRegistryImpl::Create. This is done to not unnecessarily create instances that might not be used. The ownership of the created instances is often tied to the lifetime of the connection, using a StrongBinding:
 
 
 
// static
void MimeRegistryImpl::Create(blink::mojom::MimeRegistryRequest request) {
  mojo::MakeStrongBinding(
      base::MakeUnique<MimeRegistryImpl>(),
      std::move(request));
}
 
(MakeStrongBinding was introduced after the CL this example is based on, as a simplification.)
 

Call the interface

Calling the interface requires creating a connection (which can be reused for multiple calls) and an interface proxy to use to call the implementation (the server):
 
 
// Only once:
blink::mojom::MimeRegistryPtr mime_registry;
RenderThread::Get()->GetRemoteInterfaces()->GetInterface(
    mojo::GetProxy(&mime_registry));
 
// Every time:
std::string mime_type;
if (!mime_registry->GetMimeTypeFromExtension(
    base::UTF16ToUTF8(base::string16(file_extension)), &mime_type)) {
  return string();  // Error handling.
}
 
Here’s how you get the InterfaceProvider to lookup the interface implementation from, depending on where the message is sent from and if the old Chrome IPC message was routed or not:
 
   Browser-initiated  Renderer-initiated
 Routed  RenderFrameHost::GetRemoteInterfaces()  RenderFrame::GetRemoteInterfaces()
 Control  RenderProcessHost::GetRemoteInterfaces()  RenderThread::GetRemoteInterfaces()

Two approaches to migrating your IPC

Longer term we'd like Chrome to consist of more loosely connected services. This means that we'd like to avoid unnecessary ordering constraints between Mojo interfaces. This is why Mojo messages aren't ordered between interfaces (unless you use associated interfaces) by default.
 
Because today there are many such ordering dependencies, you have two options when converting IPC to Mojo:
  • For things that could be easily made a standalone service (e.g. a JSON parser) use the above means of registering your interface.
  • For things that can't be easily converted into standalone services, use the helpers described in "Converting BrowserMessageFilters" and "Converting WebContentsObservers" below. These provide stronger (i.e. the same as before) ordering guarantees for messages and lifetime guarantees for the service implementations.

Common scenarios

Converting BrowserMessageFilters

Example CL: https://codereview.chromium.org/2167513003

Browser message filters are quite straightforward to convert:

  1. Have your message filter inherit from BrowserAssociatedInterface. You typically can just keep the old implementation with some minor tweaks e.g. you need to remove the On prefix from the message handler method names.
  2. Optionally override methods such as OnDestruct if you e.g. need your implementation to be deleted on a certain thread.

Converting WebContentsObservers

 
Use the GetAssociatedInterfaceRegistry and GetRemoteAssociatedInterfaces helpers to register your service and connect your client. Your messages will be ordered w.r.t. all old Chrome IPCs, WebContentsObservermethods, and other interfaces using these helpers.

Lifetime issues

In the typical case we use StrongBinding for the server side. StrongBinding takes ownership of the interface implementation and will delete it when the connection to the client is closed. This means that the implementation will be deleted quite "late" i.e. some time before the message loop is. This in turn means that some care must be taken when referring to other objects in the implementation's destructor, as they might have been deleted.

These issues can typically be avoided using the helpers described above.

Handling "late" messages

Messages can in principle arrive at any time before the connection is closed. In particular messages could arrive e.g. after the render process host has been deleted. This means that any state referred to in the interface method implementations must be either

  • owned
  • referred to through some form of weak pointer (so we can detect if it still exists), or
  • or looked up on each use e.g. using the process ID (which is not unlike using a weak pointer).

These issues can typically be avoided using the helpers described above.

Mocking in tests

Unlike Chrome IPC, Mojo IPCs can currently only be mocked on the server side, meaning that the test will actually send a message and your mock will make sure that it arrived. This introduces a few extra steps in your test.

First you need a mock of the interface. Your mock is probably be similar to your old Chome IPC test. Example:

class MockPageLoadMetrics : public mojom::PageLoadMetrics {
 public:
  MOCK_METHOD2(TimingUpdated,
               void(const PageLoadTiming&, const PageLoadMetadata&));
};
 
Second, to put it all together, you create a client connection connected to your mock:
 
 
class PageTimingMetricsSenderTest : public testing::Test {
 public:
  PageTimingMetricsSenderTest() : binding_(&mock_page_load_metrics_) {}
 
 protected:
  void SetUp() override {
    binding_.Bind(mojo::GetProxy(&page_load_metrics_));
  }
 
  base::MessageLoop loop_;  // 1
  mojom::PageLoadMetricsPtr page_load_metrics_;  // 2
  MockPageLoadMetrics mock_page_load_metrics_;  // 3
  mojo::Binding<mojom::PageLoadMetrics> binding_;
};
  1. You will not actually use the loop_ variable, but one need to exist and this declaration causes a global message loop to be created.
  2. This is the client side, which you will pass to the class under of test (which will need to e.g. have a test-only constructor that allows it to be injected).
  3. This is your mock (aka the server side).
Third, after a method that causes a message to be sent is called, we need to manually step the message loop to actually deliver the message (i.e. to your server-side mock):
 
 
TEST_F(PageTimingMetricsSenderTest, MyTest) {
  MyClient client(std::move(page_load_metrics_));
  client.SomeMethod();  // Calls TimingUpdated internally.  
  base::RunLoop().RunUntilIdle();  // Actually deliver message(s).
  EXPECT_CALL(mock_page_load_metrics_, TimingUpdated(_, _));
}

Replacing request/response messages pairs

A set of request/response messages

 
IPC_MESSAGE_ROUTED0(FooHostMsg_Frobinate)
IPC_MESSAGE_ROUTED0(FooMsg_DidFrobinate)
IPC_MESSAGE_ROUTED1(FooMsg_FrobinateError, std::string /* error */)
 
should be replaced by a method with a return value (with an optional error)
 
 
Interface Foo {
  Frobinate() => (bool success, string? error);
};
 
This doesn’t work if the reply isn’t always sent (in which case you need two interfaces, similar to the current Chrome IPC situation).

Replacing routing IDs

Chrome IPC uses routing IDs to dispatch messages specific to a particular RenderFrame(Host). When converting to Mojo, a whole connection may be specific to a particular frame. It is the responsibility of interface implementation to retain this knowledge. Example:

 
GetInterfaceRegistry->AddInterface(
    base::Bind(&CreateUsbDeviceManager, render_frame_host));
 
When sending messages, instead of passing the routing ID in the message, use the InterfaceProvider on the RenderFrame(Host) corresponding to the routing ID.

Dealing with message ordering

Mojo doesn’t provide a FIFO guarantee between messages sent on different message pipes. If you need cross-interface message ordering either

  • use the associated interface feature or
  • use the GetAssociatedInterfaceRegistry and GetRemoteAssociatedInterfaces helpers mentioned earlier.

Dealing with circular build dependencies

With Mojo’s typemap feature, which lets you have Mojo automatically communicate in terms of your own existing C++ types, there are situations where you might end up with a circular build dependency. Here’s an example:
 
 
Here we have a mojom target and the content component involved in a cycle. The mojom typemaps some type defined in your_type.h and thus depends on content. Content contains code using the mojom and thus depends on it, hence the cycle.
 
The answer here is to pick one component that will link the mojom symbols and then re-export the symbols, for use in another component. Example (CL):
 
mojom("mojo_bindings") {
  # ...
 
  # The chromium variant must be linked with content and use the same export
  # settings in component build because of the WebBluetoothDeviceId typemap
  # inside content.
  export_class_attribute = "CONTENT_EXPORT"
  export_define = "CONTENT_IMPLEMENTATION=1"
  export_header = "content/common/content_export.h"
  # Similarly, the blink variant must be linked with the platform component
  # since it uses types from it in its typemaps.
  export_class_attribute_blink = "BLINK_PLATFORM_EXPORT"
  export_define_blink = "BLINK_PLATFORM_IMPLEMENTATION=1"
  export_header_blink = "third_party/WebKit/public/platform/WebCommon.h"
}

Example CLs

Some additional example CLs are listed in this document.
 
 
 

[Chromium文档转载,第001章] Mojo Migration Guide的更多相关文章

  1. [Chromium文档转载,第003章]Proposal: Mojo Synchronous Methods

    Proposal: Mojo Synchronous Methods yzshen@chromium.org 02/02/2016 Overview Currently there are quite ...

  2. [Chromium文档转载,第002章]Mojo C++ Bindings API

    Mojo C++ Bindings API This document is a subset of the Mojo documentation. Contents Overview Getting ...

  3. [Chromium文档转载,第006章]Chrome IPC To Mojo IPC Cheat Sheet

    For Developers‎ > ‎Design Documents‎ > ‎Mojo‎ > ‎ Chrome IPC To Mojo IPC Cheat Sheet 目录 1 O ...

  4. [Chromium文档转载,第005章]Calling Mojo from Blink

    For Developers‎ > ‎Design Documents‎ > ‎Mojo‎ > ‎ Calling Mojo from Blink Variants Let's as ...

  5. [Chromium文档转载,第004章]Mojo Synchronous Calls

    For Developers‎ > ‎Design Documents‎ > ‎Mojo‎ > ‎ Synchronous Calls Think carefully before ...

  6. [Chromium文档转载,第007章]JNI on Chromium for Android

    Overview JNI (Java Native Interface) is the mechanism that enables Java code to call native function ...

  7. 用R创建Word和PowerPoint文档--转载

    https://www.jianshu.com/p/7df62865c3ed Rapp --简书 Microsoft的Office软件在办公软件领域占有绝对的主导地位,几乎每个职场人士都必须掌握Wor ...

  8. java实现支付宝接口--文档..转载

    //实现java支付宝很简单,只要从支付宝官方下载   http://help.alipay.com/support/index_sh.htm下载程序,配置一下参数就OK了:   1.先到http:/ ...

  9. iOS开发主要参考文档(转载)

    Objective-C,语言的系统详细资料.这是做iOS开发的前题与基础.https://developer.apple.com/library/ios/#documentation/Cocoa/Co ...

随机推荐

  1. UVALIVE 4287 Proving Equivalences (强连通分量+缩点)

    题意:给定一个图,问至少加入多少条边能够使这个图强连通. 思路:首先求出这个图的强连通分量.然后把每个强连通分量缩成一个点.那么这个图变成了一个DAG,求出全部点的入度和出度,由于强连通图中每个节点的 ...

  2. Android中的跨进程通信方法实例及特点分析(一):AIDL Service

    转载请注明出处:http://blog.csdn.net/bettarwang/article/details/40947481 近期有一个需求就是往程序中增加大数据的採集点,可是由于我们的Andro ...

  3. ,典型递归问题-F(1025)mod 5 的值

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/ ...

  4. hdoj--2098--分拆素数和(水题)

    分拆素数和 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Subm ...

  5. <a>标签是什么意思 怎么使用?

    转自:https://www.imooc.com/qadetail/190881 (1) a标签的作用:超链接,用于跳转到别的网页. (2) a标签的用法:<a href="网址&qu ...

  6. Boostrap零散

    12 row 是核心控件 class="form-control" 弹窗口<input data-toggle="modal" data-target=& ...

  7. SSRS 报表 日期类表达式

    一.如何填写表达式 右键点击单元格-表达式 二.表达式 当月1号 =DateSerial(DatePart("yyyy",Now()), DatePart("m" ...

  8. Golang 在 Mac、Linux、Windows 下交叉编译

    Golang 支持在一个平台下生成另一个平台可执行程序的交叉编译功能. Mac下编译Linux, Windows平台的64位可执行程序: CGO_ENABLED= GOOS=linux GOARCH= ...

  9. Python json数据中文输出问题。

    这个问题困扰了我好久好久,最后看了一眼官方文档,解决问题了. 问题描述:从web上获取的json数据,然后对应的保存到了python的类型中.再次输出这个数据时,中文总会变成\u1234这种形式. P ...

  10. 1x1卷积核作用

    1. 实现跨通道的交互和信息整合 对于某个卷积层,无论输入图像有多少个通道,输出图像通道数总是等于卷积核数量! 对多通道图像做1x1卷积,其实就是将输入图像于每个通道乘以卷积系数后加在一起,即相当于把 ...