Chromium多进程架构

多进程架构

转载请注明出处:https://ahangchen.gitbooks.io/chromium_doc_zh/content/zh//Start_Here_Background_Reading/Multi-process_Architecture.html

有github账号的话,不妨随手star一个 https://github.com/ahangchen/Chromium_doc_zh

这个文档描述了Chromium的高层架构

问题

构建一个从不会挂起或崩溃的渲染引擎几乎是不可能的。构建一个完全安全的渲染引擎也是几乎不可能的。

在某种程度上,web浏览器当前状态就像一个与过去的多任务操作系统合作的单独的用户。正如在一个这样的操作系统中的错误程序会让整个系统挂掉,所以一个错误的web页面也可以让一个现代浏览器挂掉。仅仅需要一个浏览器或插件的bug,就饿能让整个浏览器和所有正在运行的标签页停止运行。

现代操作系统更加鲁棒,因为他们把应用程序分成了彼此隔离的独立线程。一个程序中的crash通常不会影响其他程序或整个操作系统,每个用户对用户数据的访问也是有限制的。

架构概览

我们为浏览器的标签页使用独立的进程,以此保护整个应用程序免受渲染引擎中的bug和故障的伤害。我们也会限制每个渲染引擎进程的相互访问,以及他们与系统其他部分的访问。某些程度上,这为web浏览提供了内存保护,为操作系统提供了访问控制。

我们把运行UI的进程叫做主进程(main),把插件进程称为“浏览器进程”或“浏览器(Browser)”。相似的,标签页相关的进程被称作“渲染线程”或“渲染器(renderer)”。渲染器使用WebKit开源引擎来实现中断与html的布局。

管理渲染进程

每个渲染进程有一个全局的RenderProcess对象,管理它与父浏览器进程之间的通信,维护全局的状态。浏览器为每个渲染进程维护一个对应的RenderViewHost,用来管理浏览器状态,并与渲染器交流。浏览器与渲染器使用Chromium’s IPC system进行交流。

管理view

每个渲染进程有一个以上的RenderView对象,由RenderProcess管理(它与标签页的内容相关)。对应的RenderProcessHost维护一个与渲染器中每个view相关的RenderViewHost。每个view被赋予一个view ID,以区分同一个渲染器中的不同view。这些ID在每个渲染器内是唯一的,但在浏览器中不是,所以区分一个view需要一个RenderProcessHost和一个view ID。

浏览器与一个包含内容的特定标签页之间的交流是通过这些RenderViewHost对象来完成的,它们知道如何通过他们的RenderProcessHost向RenderProcess和RenderView送消息。

组件与接口

在渲染进程中:

  • RenderProcess处理与浏览器中对应的RenderProcessHost的通信。每个渲染进程就有唯一的一个RenderProcess对象。这就是所有浏览器-渲染器之间的交互发生的方式。

  • RenderView对象与它在浏览器进程中对应的RenderViewHost和我们的webkit嵌入层通信(通过RenderProcess)。这个对象代表了一个网页在标签页或一个弹出窗口的内容。

在浏览器进程中:

  • Browser对象代表了顶级浏览器窗口
  • RenderProcessHost对象代表了浏览器端浏览器的与渲染器的IPC连接。在浏览器进程里,每个渲染进程有一个RenderProcessHost对象。
  • RenderViewHost对象封装了与远端浏览器的交流,RenderWidgetHost处理输入并在浏览器中为RenderWidget进行绘制。

想要得到更多关于这种嵌入是如何工作的详细信息,可以查看How Chromium displays web pages design document

共享绘制器进程

通常,每个新的window或标签页是在一个新进程里打开的。浏览器会生成一个新的进程,然后指导它去创建一个RenderView

有时候,有这样一种必要或欲望在标签页或窗口间共享渲染进程。一个web应用程序会在期望同步交流时,打开一个新的窗口,比如,在javascript里使用window.open。这种情况下,当我们创建一个新的window或标签页时,我们需要重用打开这个window的进程。我们也有一些策略来把新的标签页分配的已有的进程(如果总的进程数太大的话,或者如果用户已经为这个域名打开了一个进程)。这些策略在Process Models里也有阐述。

检测crash或者失误的渲染

每个到浏览器进程的IPC连接会观察进程句柄。如果这些句柄是signaled(有信号的),那么渲染进程已经挂了,标签页会得到一个通知。从这时开始,我们会展示一个“sad tab”画面来通知用户渲染器已经挂掉了。这个页面可以按刷新按钮或者通过打开一个新的导航来重新加载。这时,我们会注意到没有对应的进程,然后创建一个新的。

渲染器中的沙箱

给定的WebKit是运行在独立的进程中的,所以我们有机会限制它对系统资源的访问。例如,我们可以确保渲染器唯一的网络权限是通过它的父浏览器进程实现。相似的,我们可以限制它对文件系统的访问权限来使用host操作系统内置的权限。

除了限制渲染器对文件系统和网络的访问权限,我们也可以限制它对用户的显示器以及相关的东西的一些权限。我们在独立的windows桌面(对用户不可见)中运行每个进程。这避免了让渲染器在新的标签页或捕捉按键之间妥协。

归还内存

让渲染器运行在独立的进程中,赋予隐藏的标签页更低的优先级会更加直接。通常,Windows平台上的最小化的进程会把它们的内存自动房东一个“可用内存”池里。在低内存的情况下,Windows会在交换这部分内存到更高优先级内存前,把它们交换到磁盘,以保证用户可见的程序更易响应。我们可以对隐藏的标签页使用相同的策略。当渲染器进程没有顶层标签页时,我们可以释放进程的“工作集”空间,作为一个给系统的信号,让它如果必要的话,优先把这些内存交换到磁盘。因为我们发现,当用户在两个标签页间切换时,减少工作集大小也会减少标签页切换性能,所以我们是逐渐释放这部分内存的。这意味着如果用户切换回最近使用的标签页,这个标签页的内存比最近较少访问的标签页更可能被换入。有着足够内存的用户运行他们所有的程序时根本不会注意到这个进程:事实上Windows只会在需要的时候重新声明这块数据,所以在有充分内存时,不会有性能瓶颈。

这能帮助我们在低内存的情况下得到最佳的内存轨迹。几乎不被使用的后台标签页相关的内存可以被完全交换掉,前台标签页的数据可以被完全加载进内存。相反的,一个单进程浏览器会在它的内存里随机分配所有标签页的数据,并且不可能如此清晰地隔离已使用的和未使用的数据,导致了内存和性能上的浪费。

插件

Firefox风格的NPAPI插件运行在他们自己的进程里,与渲染器隔离。这会在Plugin Architecture中描述。

如何添加新特性(不用扩充RenderView/RenderViewHost/WebContents)

问题

过去,新的特性(比如,自动填充选取样例)可以通过把新特性的代码导入到RenderView类(在渲染器进程里)和RenderViewHost类(在浏览器进程里)。如果一个新的特性是在浏览器进程的IO线程里处理的,那么它的IPC信息由BrowserMessageFilter调度。RenderViewHost会只为了调用WebContent对象进程调用IPC信息,这会调用另一块代码。所有的浏览器与渲染器之间的IPC信息会被声明在一个巨大的render_messages_internal.h里,为每个新特性修改所有的这些文件意味着这些类会变得臃肿。

解决方案

我们增加了helper类和对上面的每个线程IPC信息的过滤的机制。这使得编写自洽的特性更加容易。

渲染器端

如果你想要过滤和发送IPC信息,实现RenderViewObserver接口(content/renderer/render_view_observer.h)。RenderViewObserver基类持有一个RenderView类,管理对象的生命周期,使其绑定到RenderView(它是可重写的)。这个类就可以过滤和发送IPC消息,此外还可以获得许多特性需要的关于页面加载与关闭的通知。作为一个例子,可以查看ChromeExtensionHelper (chrome/renderer/extensions/chrome_extension_helper.h)。

如果你的特性有一部分代码是在WebKit内的,避免通过WebViewClient接口回调,这样我们就不会使得WebViewClient变得庞大。考虑创建新的WebKit接口给WebKit代码调用,让渲染器端的类去实现它。作为一个例子,查看WebAutoFillClient (WebKit/chromium/public/WebAutoFillClient.h).

浏览器UI线程

WebContentsObserver (content/public/browser/web_contents_observer.h)接口允许UI线程的对象过滤IPC信息,以及给出关于页面导航的通知。作为一个例子:查看TabHelper (chrome/browser/extensions/tab_helper.h)。

浏览器其他线程

为了过滤和发送IPC信息给其他的浏览器线程,比如IO/FILE/WEBKIT等等,实现BrowserMessageFilter接口(content/browser/browser_message_filter.h)。BrowserRenderProcessHost对象在它的CreateMessageFilters函数里创造和增加过滤器。

通常,如果一个特性有许多IPC消息,这些消息应该移动到一个独立的文件(例如,不要加到render_messages_internal.h里)。这对过滤线程(除了IO线程)也有帮助。作为一个例子,查看content/common/pepper_file_messages.h。这允许他们的过滤器PepperFileMessageFilter方便的发送文件到file线程,而不用在很多位置指定它们的ID。

void PepperFileMessageFilter::OverrideThreadForMessage(
const IPC::Message& message,
BrowserThread::ID* thread) {
if (IPC_MESSAGE_CLASS(message) == PepperFileMsgStart)
*thread = BrowserThread::FILE;
}

Chromium的更多相关文章

  1. QT5利用chromium内核与HTML页面交互

    在QT5.4之前,做QT开发浏览器只能选择QWebkit,但是有过使用的都会发现,这个webkit不是出奇的慢,简直是慢的令人发指,Release模式下还行,debug下你就无语了,但是webkit毕 ...

  2. Google之Chromium浏览器源码学习——base公共通用库(一)

    Google的优秀C++开源项目繁多,其中的Chromium浏览器项目可以说是很具有代表性的,此外还包括其第三开发开源库或是自己的优秀开源库,可以根据需要抽取自己感兴趣的部分.在研究.学习该项目前的时 ...

  3. 如何在windows上编译Chromium (CEF3) 并加入MP3支持(二)

    时隔一年,再次编译cef3,独一无二的目的仍为加入mp3支持.新版本的编译环境和注意事项都已经发生了变化,于是再记录一下. 一.编译版本 cef版本号格式为X.YYYY.A.gHHHHHHH X为主版 ...

  4. 如何在Windows上从源码编译Chromium (CEF3) 加入mp3支持

    一.什么是CEF CEF即Chromium Embeded Framework,由谷歌的开源浏览器项目Chromium扩展而来,可方便地嵌入其它程序中以得到浏览器功能. CEF包括CEF1和CEF3两 ...

  5. 构建基于Chromium的应用程序

    chromium是google chrome浏览器所采用的内核,最开始由苹果的webkit发展而出,由于webkit在发展上存在分歧,而google希望在开发上有更大的自由度,2013年google决 ...

  6. ubuntu中chromium无法播放flash,安装flash

    ubuntu14.0.4中系统自带的chromium无法播放flash,后来查了下,得知chromium已经不支持adobe flash了,用户可使用pepper flash替代.安装pepper f ...

  7. windows下编译chromium浏览器的15个流程整理

    编译chromium 系统为windows, 国内在windows上编译chromium的资料比较少, 我这篇文章只能作为参考, 记录我遇到的一些问题,因为chromium团队也会修改了代码,或者编译 ...

  8. Google之Chromium浏览器源码学习——base公共通用库(二)

    上次提到Chromium浏览器中base公共通用库中的内存分配器allocator,其中用到了三方库tcmalloc.jemalloc:对于这两个内存分配器,个人建议,对于内存,最好是自己维护内存池: ...

  9. 浏览器-10 Chromium 移动版

    移动版 chromium 的iOS版和Android是为两个流行的移动操作系统设计的, UI方面进行了 较大的重新设计; 两者从外观上看颇为相似,但是其内部的渲染引擎的差别非常的大,原因在于iOS对应 ...

  10. 浏览器-09 javascript引擎和Chromium网络栈

    语言的运行 C/C++语言 使用编译器直接将它们编译成本地代码(机器指令),这是由开发人员在代码编写完成之后实施; 用户只是使用这些编译好的本地代码,这些本地代码被系统的加载器加载执行,由操作系统调度 ...

随机推荐

  1. 什么是VSync

    VSync是垂直同期(Vertical Synchronization)的简称.主要的思路是将你的FPS和显示器的刷新率同期起来.其目的是避免一种称之为"撕裂"的现象.再以下我将具 ...

  2. c# in depth 之泛型实参的类型推断

    调用泛型方法时,指定类型实参常常会显得很多余.为简化工作,c#2编译器被赋予了一定的“智能”,让你在调用方法时,不需要显式声明类型实参. 在深入讨论这个主题之前,必须强调一下:类型推断只适用于泛型方法 ...

  3. Java.util.zip adding a new file overwrites entire jar?(转)

    ZIP and TAR fomats (and the old AR format) allow file append without a full rewrite. However: The Ja ...

  4. 依据不同的操作系统读取配置文件/java读取属性文件代码

    package cn.com.css.common.util; /**  * @brief OSEnum.java 操作系统的枚举  * @attention  * @author 涂作权  * @d ...

  5. hdu2112 HDU Today

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2112 题目分类:SPFA算法+map容器 错误点:红色标记部分 代码: #include<bit ...

  6. hdu 4963(中途相遇法)

    题目链接:Dividing a String 题意:给定一个2*n(n<=20)的字符串及每个位置的字符包含的权重,求将该字符串分成两个子序列S1.T1,要求S1=T1且abs(weight1- ...

  7. ArcSDE当关系查询ArcMap与REST查询结果不一致问题的解决

    首先描述来形容什么问题: 周边环境:ArcGIS10.x.Oracle 11g R2,这个问题无关与环境 假设用户使用关联查询(比方一个空间数据与一个属性数据进行关联),在ArcGIS for Des ...

  8. cocos2d-x CCNode类

    文章引用自http://blog.csdn.net/qiurisuixiang/article/details/8763260 1 CCNode是cocos2d-x中一个非常重要的类.CCNode是场 ...

  9. sqlserver安全加固

      sqlserver2012安装好以后必要的安全加固,不然非常多DBA的信息普通账户登录后都能够读取到.  --use [master] --GO --DENY VIEW SERVER STATE ...

  10. TopCoder中插件的用法

    今天弄了一下TopCoder的插件,发现真的很好很强大,插件的下载地址为 : http://community.topcoder.com/tc?module=Static&d1=applet& ...