Chromium的多进程资源加载

时间:2022-08-28 22:01:30

【欢迎转载,转载时,请注明出处http://blog.csdn.net/yl02520/article/details/21285745

原文出自Chromium的官方文档Multi-processResource Loading,本文一部分来自对原文的翻译,另外也对原文某些部分做了必要的修改和补充,也添加了一些自己的理解。

在阅读本文之前,建议先阅读另外一篇博文“Chromium浏览器的多进程架构”。

背景知识

Chromium采用多进程架构,本文主要介绍浏览器进程和渲染进程,由于渲染进程是运行在沙盒中,没有直接访问系统资源的能力(如网络资源)。渲染进程中的WebKit/Blink在渲染网页时,首先需要从网络上加载相应的资源文件,比如HTML文档以及文档中的图片、JS脚本、CSS脚本等子资源文件,那么渲染进程就需要先把这些请求通过IPC(进程间通信)的方式发送给浏览器进程,由浏览器进程统一管理和网络数据传输。

这样做有一下几个好处:1. 浏览器可以统一管理所有的资源请求;2. 浏览器进程可以缓存已经下载完毕的资源文件和Cookie,当有新的请求到达时,如果请求的资源以及存在于缓存中,就直接从缓存中提取,没必须要重新从网络上下载,这样可以节省网络带宽和资源下载的时间。3. 自从HTTP/1.1之后,浏览器要求不能为同一域名的主机打开太多的连接,因为如果一个标签页打开太多的Socket链接,可能会导致系统资源消耗过多,这可能会影响到其他标签页或者其他应用程序的运行,这在资源受限的移动平台上显得尤为重要。Chromium目前允许同一主机最多打开6个Socket链接。

总体架构

Chromium的多进程资源加载

从上图可知,我们把Chromium资源文件加载的流程大致分为三层,最下面一层是WebKit/Blink层,它运行在渲染进程中的渲染线程中,负责HTML文档的解析、JavaScript/CSS脚本的解析执行和页面的布局等功能;中间一层是渲染进程中与浏览器进程通信的模块,它在渲染进程中的主线程中,负责把WebKit发出的资源请求,转发给浏览器进程;最上面一层就是浏览器进程,它负责控制所有的网络连接和通信,该模块运行在浏览器进程中的IO线程里。

WebKit/Blink

在WebKit/Blink中包括HTML文档在内的所有资源文件都是通过ResourceFetcher类来获取的,现在最新的实现对以前的WebKit资源加载流程做了改进,更多内容请参看另一篇博文“WebKit/Blink如何加载网页资源”。ResourceFethcer类中提供了获取不同资源文件的方法,例如:fetchMainResource方法获取Frame资源,由该方法发送的请求具备最高优先级;fetchImage方法获取图片文件;fetchScript方法获取JavaScript脚本文件资源等等。这些获取资源的方法通过创建和调用ResourceLoader来发送请求。

渲染进程

渲染进程对类ResourceLoaderBridge进行了实现,我们称为IPCResourceLoaderBridge,该类是在content/child/resource_dispatcher.cc中实现的(Chromium后来移动了该文件的位置),该类通过ResourceDispatcher类发送网络资源请求,每个渲染进程中有且之存在一个ResourceDispatcher对象,所有从WebKit发出的网络请求,最后都交给ResourceDispatcher处理,ResourceDispatcher先给每个请求分配一个唯一的ID号,用来区别其他请求,并且组装成一个IPC的信息包ResourceHostMsg_RequestResource,然后把该请求消息交给主线程,由主线程统一与浏览器进程进行IPC。

浏览器进程

浏览器进程中的IO线程的ResourceDispatcherHost会对渲染进程发过来的资源请求消息进行处理,ResourceDispatcherHostImpl::OnRequestResource方法来处理ResourceHostMsg_RequestResource消息,然后把每个消息请求的数据结构变换成chromium中net模块的URLRequest对象,并转发给net模块内部的URLRequestJob类,该对象负责具体网络协议的实现。当URLRequest得到数据或通知时,ResourceDispatcherHost就会收到相应消息,并根据渲染进程中创建的资源请求ID号找到相应的RenderProcessHost,最后把消息发送给渲染进程。

Cookies

在Chromium中Cookies存放在浏览器进程中,为所有的渲染进程共享,这就是为什么我们在一个标签页中登录了某个网站,打开一个新的标签页时就不用再重新输入密码登录了(手动打开一个新的标签页时使用一个新的渲染进程)。在网页中我们可以通过JavaScritpt脚本document.cookie来访问该网站的cookie值,此时渲染进程需要发送一个同步的IPC给浏览器进程,由于是同步的IPC,所以渲染进程中的渲染线程(WebKit的主循环)就会被阻塞,直到收到浏览器进程的数据返回为止,然后把获取的结果返回给JavaScript引擎,让JavaScript继续执行。