Chrome设计文档-多进程架构

时间:2021-09-24 08:59:50

chromium multi-process architecture

本文档从high-level的角度描述Chromium的多进程架构。

问题

要构建一个决不崩溃或挂起的渲染引擎几乎是不可能的。同样的,要构建一个100%安全的渲染引擎也是不可能的。

从某些角度来看,当今的web浏览器有点类似于过去的单用户,多任务操作系统。正如一个异常的程序会导致整个系统down掉,一个异常的网页也会导致一个现代浏览器挂掉。

现代操作系统之所以更加健壮利益于它们把应用放到隔离的进程中。一个应用的崩溃不会影响其它的应用或者操作系统本身。任一用户对其它用户的数据操作都是严格受限的。

架构概述

我们针对浏览器的tab使用隔离的进程。这种方案可以保护应用本身完整,不受渲染引擎的bugs或小差错的影响。同时,我们也严格限制从渲染引擎到其它进程的访问。从某些方面来看,这给网页浏览带来了内存保护和访问控制的收益。而这两点均借鉴自操作系统。

我们把主进程称为“browser process(浏览进程)或browser”。该进程负责UI的运行和tab的管理工作,同时,也负责插件进程的管理工作。类似的,tab特定的进程被称为“render process”或者“renderer”。Renderers使用”WebKit”开源引擎解析并布局HTML文档。

Chrome设计文档-多进程架构

管理渲染进程(Rendering process / Renderer)

每一个Renderer对应一个全局的RenderProcess对象。该对象管理Renderer与父进程Browser process间的通信,并维护全局状态。Browser则维护多个RenderProcessHost对象。每个RenderProcessHost对应一个Renderer。Browser负责策略浏览状态以及与Renderer的通信。Browser与Renderers间的通信由Chromium的IPC系统承担

管理Views

每个Renderer有一个或多个RenderView对象。一个Renderer相当于一个tab。相应的,RenderProcessHost维护一个RenderViewHost。一个RenderViewHost对应于Renderer中的一个view。同一个Renderer中,为了区分不同的view,每个view会被分配一个ID。这些ID在同一个Renderer里是唯一的,但在browser里并不是。所以,要标识一个view,需要RenderProcessHost和一个view ID。

组件和接口

在Render进程里:

  • RenderProcess负责处理与RenderProcessHost间的IPC。RenderProcessHost位于Browser中。每一个Render进程仅一个RenderProcess。所有的browser和renderer间的通信都是这样子的。
  • RenderView对象与browser进程中的RenderViewHost通信(当然,是通过RenderProcess完成的)。RenderView代表一个网页上的内容或弹出窗口中的网页内容。

在Browser进程中:

  • Browser对象代表一个顶层的browser窗口
  • RenderProcessHost代表browser端的browser<->renderer ipc连接。在browser里,每一个render进程对应一个RenderProcessHost。
  • RenderViewHost封装了与远端的RenderView间的通信流程。RenderWidgetHost处理输入和RenderWidget的绘制。

共享Renderer

通常,一个新窗口或新tab打开一个新的进程。浏览器会生成一个新进程,然后,指令它去创建一个单独的RenderView。

有时,tabs或windows间共享Renderer也是必须的或者非常有必要的。比如,一个web应用使用window.open打开一个同步模式的新窗口。这种情况下,当我们创建一个新窗口或tab时,我们需要复用原进程,即窗口打开者所在的进程。对于进程数过多的情况,我们也有相应的策略把新tab交给已存在的进程。这些策略参见Process Models

崩溃探测或渲染异常

每一个到browser进程IPC链接会监控渲染进程(renderer)的句柄。如果这些句柄收到信号,那么渲染进程已经崩溃,tab页收到崩溃通知。从今开始,当Renderer崩溃时,我们会显示一个”sad tab“屏来通知用户。当前页面可以通过点击”preload“按钮重新加载。

Renderer沙盒化

假设WebKit在一个分离的进程中运行,我们有机会控制它对系统资源的访问。比如,我们可以限定renderer的网络操作只能通过其父进程完成。类似的,我们也可以严格限制它对文件系统的访问。

Plug-ins

NPAPI插件运行在自己的进程中,与renderers分离。详情参见Plugin Architecture