chromium源码阅读--进程间通信(IPC)

     第一篇就有提到Chromium是目前默认是采用多进程架构,当然,chromium有singe-process的版本。

     多进程与多线程的区别,确实有很多可以讲的,我的另一篇博客也讲了一些 (Linux 进程,线程),这里是从浏览器的角度来说,如果是多线程,如果一个线程崩溃,影响了整个浏览器的使用,因为在现在的网页标准更新了很多个版本,会有不同标准的页面在网络上,极大可能出现解析,渲染,插件等问题,那么对于用户来说,体验就会差很多了,浏览一个页面出问题,就要重启浏览器。而多进程则可以避免此问题,render进程崩溃只会影响当前的tab。

    嗯,上面说了那么多,就是为了说,多进程之间就需要进程通信来协作,而chromium的进程间通信是非常繁杂的,如何处理这个是我们需要了解的关键。

   那么本质的问题就是:

         1、发那些消息(Message Type)

         2、消息通道是怎么建立的 (Message Channel)

         3、发送者和接收者(Sender,Listener)

OK,咱一个个来。

 

一、 Message Type 

     主要分为2类:“routed” 和 “control”。

     1、routed消息

         主要是用来给某个RenderViewHost对象发送消息的。不过,任何类都可以通过GetNextRoutingID 和 AddRoute 注册,就能接收routed消息。

     2、control消息

          control消息有创建pipe的类处理,当然这些类也可以接收routed消息。比如,请求资源或修改剪贴板不是特定于视图的,所以是控制消息。

     3、消息的声明

1 IPC_MESSAGE_ROUTED2(FrameHostMsg_MyMessage, GURL, int)

      这个宏用来声明routed消息,这里声明了一个从render进程发送到browser进程的消息,并有一个GURL参数,一个int参数

1 IPC_MESSAGE_CONTROL0(FrameMsg_MyMessage)

     这个宏用来声明control消息,这里声明了一个从browser进程发送到render进程的消息,没有参数。

     这里还有几个默认的约定:

          (1)这些宏后面的数字表明有几个参数,最多5个参数,即: IPC_MESSAGE_ROUTED0~IPC_MESSAGE_ROUTED5 或者 IPC_MESSAGE_CONTROL0~IPC_MESSAGE_CONTROL5

          (2)消息名称表明消息的接受者,FrameHostMsg,带Host后缀的类,表示在browser进程接收处理的消息,FrameMsg,则表示在render进程处理的消息,如果是Plugin进程,也会带有Plugin字样。

 

二、Message Channel

    chromium的使用mojo IPC,并且在官网提供了性能对比 (Times in microseconds

 

Windows Z840

Linux Z620

MacBook Pro 15" 2016

IPC

36.9

69.5

52.5

Mojo cross-process

28.2

48

34.9

 

这里是官网关于mojo的一些介绍,https://chromium.googlesource.com/chromium/src/+/master/mojo/README.md#System-Overview

从unittest看channel的创建:

 

1 void IPCChannelMojoTestBase::CreateChannel(IPC::Listener* listener) {
2   channel_ =
3       IPC::ChannelMojo::Create(TakeHandle(), IPC::Channel::MODE_SERVER,
4                                listener, base::ThreadTaskRunnerHandle::Get());
5 }

 在IPC::ChannelMojo::Create里看到需要 IPC::ChannelMojo的构造,

 1 ChannelMojo::ChannelMojo(
 2     mojo::ScopedMessagePipeHandle handle,
 3     Mode mode,
 4     Listener* listener,
 5     const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner)
 6     : task_runner_(ipc_task_runner),
 7       pipe_(handle.get()),
 8       listener_(listener),
 9       weak_factory_(this) {
10   weak_ptr_ = weak_factory_.GetWeakPtr();
11   bootstrap_ = MojoBootstrap::Create(std::move(handle), mode, ipc_task_runner);
12 }

 在MojoBootstrapImpl里完成sender和listener的绑定:

 1 class MojoBootstrapImpl : public MojoBootstrap {
 2  public:
 3   MojoBootstrapImpl(
 4       mojo::ScopedMessagePipeHandle handle,
 5       const scoped_refptr<ChannelAssociatedGroupController> controller)
 6       : controller_(controller),
 7         associated_group_(controller),
 8         handle_(std::move(handle)) {}
 9 
10   ~MojoBootstrapImpl() override {
11     controller_->ShutDown();
12   }
13 
14  private:
15   void Connect(mojom::ChannelAssociatedPtr* sender,
16                mojom::ChannelAssociatedRequest* receiver) override {
17     controller_->Bind(std::move(handle_));
18     controller_->CreateChannelEndpoints(sender, receiver);
19   }
20 
21  。。。
22 }

 上面的mojo  Channel的创建过程,linux提供的IPC比如:pipe,unix socket,share memory都不是线程安全的,mojo封装了底层IPC细节并提供了线程安全保障,并且看上面的性能对比,mojo性能更好,这也是chromium逐渐转用mojo的主要因素吧。

 OK,上面介绍了mojo,接下来我们会发现,在进程里都是使用IPC::ChannelProxy这个类来代理完成Channel的各种工作。

 这里我们只需看一个例子就能理解了,比如在browser进程的RenderProcessHost类里声明了GetChannel接口:

1 IPC::ChannelProxy* GetChannel() = 0;

根据chromium的套路,你大致就能想到,有一个RenderProcessHostImpl类会来实现这个接口,嗯,果不其然:

 1 class CONTENT_EXPORT RenderProcessHostImpl
 2     : public RenderProcessHost,
 3       public ChildProcessLauncher::Client,
 4       public ui::GpuSwitchingObserver,
 5       public mojom::RouteProvider,
 6       public mojom::AssociatedInterfaceProvider,
 7       public mojom::RendererHost {
 8       ...
 9       IPC::ChannelProxy* GetChannel() override;
10       ...
11 }

我们可以看到这里会提供一个IPC::ChannelProxy的指针,那么顺着这个,ChannelProxy的创建和初始化就不远了。

bool RenderProcessHostImpl::Init() {
   ...
   if (!channel_)
    InitializeChannelProxy();
  
   ...
   CreateMessageFilters();
  RegisterMojoInterfaces();
  ...

}

可以看到,上面初始化了Channel并给当前实例创建了MessageFilter和在mojo里注册了消息发送的mojo interface。

mojo会负责将channel两端连通,之后的消息发送就可使用IPC::ChannelProxy来完成了。

 

三、发送者和接收者

    1、发送者

    chromium里定义了IPC::Sender的接口:

 1 class Message;
 2 
 3 class IPC_EXPORT Sender {
 4  public:
 5   // Sends the given IPC message.  The implementor takes ownership of the
 6   // given Message regardless of whether or not this method succeeds.  This
 7   // is done to make this method easier to use.  Returns true on success and
 8   // false otherwise.
 9   virtual bool Send(Message* msg) = 0;
10 
11  protected:
12   virtual ~Sender() {}
13 };

    上面的使用例子,我们可以看到 IPC::ChannelProxy 是消息的发送者,看类的声明:

1 class IPC_EXPORT ChannelProxy : public Sender {
2 
3 }

2、接收者

    同样chromium也定义Listener。

class Message;

// Implemented by consumers of a Channel to receive messages.
class IPC_EXPORT Listener {
 public:
  // Called when a message is received.  Returns true iff the message was
  // handled.
  virtual bool OnMessageReceived(const Message& message) = 0;

  ...
};

我们在前面提到的router,是消息接收者,也是消息发送者:

1 class IPC_EXPORT MessageRouter : public Listener, public Sender { 
2     ...
3 }

还有子线程实例也是Listener:

1 class CONTENT_EXPORT ChildThreadImpl
2     : public IPC::Listener,
3       virtual public ChildThread,
4       private base::FieldTrialList::Observer,
5       public mojom::RouteProvider,
6       public mojom::AssociatedInterfaceProvider,
7       public mojom::ChildControl {
8     ...
9  }

好了,更多例子我也不举了,chromium IPC还有更多的内容,在代码待我们学习,这里暂时总结到这里,后续再补充。

 

   

转载于:https://www.cnblogs.com/danxi/p/7766147.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要下载Chromium源码,你可以按照以下步骤进行操作: 1. 首先,你需要下载depot_tools,这是一个用于管理Chromium源码的工具集。你可以在官方网址http://www.chromium.org/developers/how-tos/build-instructions-windows 下载depot_tools。 2. 下载完成后,将depot_tools添加到系统的环境变量中,以便在任何位置都可以使用它。 3. 接下来,你需要创建一个自定义的源码目录,并使用命令行工具进入该目录。 4. 在源码目录中,执行命令"gclient config http://src.chromium.org/svn/releases/31.0.1620.2"来配置Chromium的版本。你可以根据需要下载不同的版本,可以在http://src.chromium.org/viewvc/chrome/releases/ 查看可用的版本。 5. 如果你不需要下载LayoutTest测试文件,可以打开以版本名称命名的目录下的DEPS文件,并将"src/third_party/WebKit/LayoutTests"修改为None。 6. 第一次执行"gclient sync"命令时,会自动安装git、python等必要的工具。请耐心等待安装完成。 7. 在安装过程中,可能会出现连接错误。如果出现连接错误,你可以尝试将以下内容复制到C:\Windows\System32\drivers\etc\hosts文件中,以解决连接问题。 8. 安装完成后,你可以执行"gclient sync"命令来获取Chromium源码。如果下载过程中出现问题,可以重复执行"gclient sync"命令。 9. 下载完成后,进入源码目录,并执行"gn gen out/Default"命令来生成编译规则到out/Default目录中。 这样,你就成功下载了Chromium源码。希望对你有帮助!\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* [下载Chromium源码方法及问题记录](https://blog.csdn.net/hezhipin610039/article/details/31372619)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Chrome源码chromium下载编译详细步骤](https://blog.csdn.net/langeldep/article/details/120032077)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值