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、消息的声明
IPC_MESSAGE_ROUTED2(FrameHostMsg_MyMessage, GURL, int)
这个宏用来声明routed消息,这里声明了一个从render进程发送到browser进程的消息,并有一个GURL参数,一个int参数
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的创建:
void IPCChannelMojoTestBase::CreateChannel(IPC::Listener* listener) {
channel_ =
IPC::ChannelMojo::Create(TakeHandle(), IPC::Channel::MODE_SERVER,
listener, base::ThreadTaskRunnerHandle::Get());
}
在IPC::ChannelMojo::Create里看到需要 IPC::ChannelMojo的构造,
ChannelMojo::ChannelMojo(
mojo::ScopedMessagePipeHandle handle,
Mode mode,
Listener* listener,
const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner)
: task_runner_(ipc_task_runner),
pipe_(handle.get()),
listener_(listener),
weak_factory_(this) {
weak_ptr_ = weak_factory_.GetWeakPtr();
bootstrap_ = MojoBootstrap::Create(std::move(handle), mode, ipc_task_runner);
}
在MojoBootstrapImpl里完成sender和listener的绑定:
class MojoBootstrapImpl : public MojoBootstrap {
public:
MojoBootstrapImpl(
mojo::ScopedMessagePipeHandle handle,
const scoped_refptr<ChannelAssociatedGroupController> controller)
: controller_(controller),
associated_group_(controller),
handle_(std::move(handle)) {} ~MojoBootstrapImpl() override {
controller_->ShutDown();
} private:
void Connect(mojom::ChannelAssociatedPtr* sender,
mojom::ChannelAssociatedRequest* receiver) override {
controller_->Bind(std::move(handle_));
controller_->CreateChannelEndpoints(sender, receiver);
} 。。。
}
上面的mojo Channel的创建过程,linux提供的IPC比如:pipe,unix socket,share memory都不是线程安全的,mojo封装了底层IPC细节并提供了线程安全保障,并且看上面的性能对比,mojo性能更好,这也是chromium逐渐转用mojo的主要因素吧。
OK,上面介绍了mojo,接下来我们会发现,在进程里都是使用IPC::ChannelProxy这个类来代理完成Channel的各种工作。
这里我们只需看一个例子就能理解了,比如在browser进程的RenderProcessHost类里声明了GetChannel接口:
IPC::ChannelProxy* GetChannel() = ;
根据chromium的套路,你大致就能想到,有一个RenderProcessHostImpl类会来实现这个接口,嗯,果不其然:
class CONTENT_EXPORT RenderProcessHostImpl
: public RenderProcessHost,
public ChildProcessLauncher::Client,
public ui::GpuSwitchingObserver,
public mojom::RouteProvider,
public mojom::AssociatedInterfaceProvider,
public mojom::RendererHost {
...
IPC::ChannelProxy* GetChannel() override;
...
}
我们可以看到这里会提供一个IPC::ChannelProxy的指针,那么顺着这个,ChannelProxy的创建和初始化就不远了。
bool RenderProcessHostImpl::Init() {
...
if (!channel_)
InitializeChannelProxy(); ...
CreateMessageFilters();
RegisterMojoInterfaces();
... }
可以看到,上面初始化了Channel并给当前实例创建了MessageFilter和在mojo里注册了消息发送的mojo interface。
mojo会负责将channel两端连通,之后的消息发送就可使用IPC::ChannelProxy来完成了。
三、发送者和接收者
1、发送者
chromium里定义了IPC::Sender的接口:
class Message; class IPC_EXPORT Sender {
public:
// Sends the given IPC message. The implementor takes ownership of the
// given Message regardless of whether or not this method succeeds. This
// is done to make this method easier to use. Returns true on success and
// false otherwise.
virtual bool Send(Message* msg) = ; protected:
virtual ~Sender() {}
};
上面的使用例子,我们可以看到 IPC::ChannelProxy 是消息的发送者,看类的声明:
class IPC_EXPORT ChannelProxy : public Sender { }
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) = ; ...
};
我们在前面提到的router,是消息接收者,也是消息发送者:
class IPC_EXPORT MessageRouter : public Listener, public Sender {
...
}
还有子线程实例也是Listener:
class CONTENT_EXPORT ChildThreadImpl
: public IPC::Listener,
virtual public ChildThread,
private base::FieldTrialList::Observer,
public mojom::RouteProvider,
public mojom::AssociatedInterfaceProvider,
public mojom::ChildControl {
...
}
好了,更多例子我也不举了,chromium IPC还有更多的内容,在代码待我们学习,这里暂时总结到这里,后续再补充。
chromium源码阅读--进程间通信(IPC)的更多相关文章
- [原创]chromium源码阅读-进程间通信IPC.消息的接收与应答
chromium源码阅读-进程间通信IPC.消息的接收与应答 chromium源码阅读-进程间通信IPC.消息的接收与应答 介绍 chromium进程间通信在win32下是通过命名管道的方式实现的 ...
- chromium源码阅读--Browser进程初始化
最近在研读chromium源码,经过一段懵懂期,查阅了官网和网上的技术文章,是时候自己总结一下了,首先IPC message loop开始吧,这是每个主线程必须有的一个IPC消息轮训主体,类似之前的q ...
- chromium源码阅读--进程的Message Loop
上一篇总结了chromium进程的启动,接下来就看线程的消息处理,这里的线程包含进程的主进程. 消息处理是由base::MessageLoop中实现,消息中的任务和定时器都是异步事件的. 主要如下几点 ...
- chromium源码阅读--HTTP Cache
最近积累了一些关于HTTP缓存的知识,因此结合Chromium的实现总结一下,主要从如下2个分面: 1.HTTP缓存的基础知识 2.Chromium关于HTTP缓存的实现分析 一.HTTP缓存的基础知 ...
- chromium源码阅读--V8 Embbeding
V8是google提供高性能JavaScript解释器,嵌入在chromium里执行JavaScript代码. V8本身是C++实现的,所有嵌入本身毫无压力,一起编译即可,不过作为一个动态语言解释器, ...
- chromium源码阅读--图片处理
JavaScript 图像替换 JavaScript 图像替换技术检查设备能力,然后“做正确的事”. 您可以通过 window.devicePixelRatio 确定设备像素比,获取屏幕的宽度和高度, ...
- chromium源码阅读
linux下chromium的入口函数在文件:src/chrome/app/chrome_exe_main_aura.cc 中 int main(int argc, const char** argv ...
- Android源码阅读 – Zygote
@Dlive 本文档: 使用的Android源码版本为:Android-4.4.3_r1 kitkat (源码下载: http://source.android.com/source/index.ht ...
- Chromium源码--网络请求流程分析
转载请注明出处:http://www.cnblogs.com/fangkm/p/3784660.html 本文探讨一下chromium中加载URL的流程,具体来说是从地址栏输入URL地址到通过URLR ...
随机推荐
- eclipse配置maven + 创建maven项目(三)
上篇博文中我们介绍了maven下载.安装和配置(二),这篇博文我们配置一下eclipse,将它和maven结合,并我们创建一个maven的项目. 准备工作 在eclipse配置maven之前需要我们做 ...
- 1 Spring Cloud Eureka服务治理(下)
注:此随笔为读书笔记.<Spring Cloud微服务实战> 上篇主要介绍了什么是微服务以及微服务治理的简单实现,如微服务注册中心的实现.微服务注册的实现.微服务的发现和消费的实现.微服务 ...
- 关于Android WebView上传文件的解决方案
我们在开发需求的时候,难免会接入一下第三方的H5页面,有些H5页面是具有上传照片的功能,Android 中的 WebView是不能直接打开文件选择弹框的 接下来我讲简单提供一下解决方案,先说一下思路 ...
- 云计算之openstack ocata 项目搭建详细方法
之前写过一篇<openstack mitaka 配置详解>然而最近使用发现阿里不再提供m版本的源,所以最近又开始学习ocata版本,并进行总结,写下如下文档 OpenStack ocata ...
- 进入css3动画世界(一)
其实我做css3动画也没有多久,这篇文章目标人群是css3动画的新手,不喜勿喷. 分类 目前我接触到的css3动画有2类:一种是transition的,另一种是@keyframes的. 两者的区别就是 ...
- MMORPG战斗系统随笔(一)
前言 很久没有更新博客,中间迁移过一次博客,后来一直忙于项目的开发,忙的晚上回去没时间写博客,周日又要自我调整一下,所以空闲了很久没有继续写博客.最近终于慢慢放慢节奏,项目也快上线了,可以有空写一些个 ...
- JS组件系列——基于Bootstrap Ace模板的菜单Tab页效果优化
前言:之前发表过一篇 JS组件系列——基于Bootstrap Ace模板的菜单和Tab页效果分享(你值得拥有) ,收到很多园友的反馈,当然也包括很多诟病,因为上篇只是将功能实现了,很多细节都没有处理 ...
- Centos7环境下使用Nginx托管.Net Core应用程序
一.安装.Net Core 参考官方文档:https://www.microsoft.com/net/core#linuxcentos 1.添加dotnet产品Feed 在安装.NET Core之前, ...
- Ionic3学习笔记(三)禁止横屏
本文为原创文章,转载请标明出处 目录 安装 使用 参数 1. 安装 命令行输入 ionic cordova plugin add cordova-plugin-screen-orientation n ...
- Asp.net MVC4高级编程学习笔记-视图学习第三课Razor页面布局20171010
Razor页面布局 1) 在布局模板页中使用@RenderBody标记来渲染主要内容.比如很多web页面说头部和尾部相同,中间内容部分使用@RenderBody来显示不同的页面内容. 2) 在布局 ...