Explore the Magic Behind Google Chrome

Web browser has been regarded as the most popular software to users and an indispensable part of a modern computer. Around 60% of people in the world use Google Chrome in their daily life. Chrome is a proprietary software largely based on Chromium, which is an open source software developed and maintained by The Chromium Project. The primary goal of this project is to build a faster, safer, more stable browser engine for better internet surfing experience. This post attempts to analyze architectural styles of Chromium and explore the magic behind this popular web browser.

Back in the old days, if the user accidentally opens a misbehaving web page, the browser will crash the tab that contains this web page. A crash in tab will often lead to crash to the entire browser. That means the user has to re-open the browser again and all of the previously opened tabs are lost. This is considered as bad user experience. To solve this kind of issue, Chromium now adopts what is known as multi-process architecture. The diagram below shows the high level architectural overview of Chromium.

Chromium Multi-Process Architectural Overview

There are two primary types of processes in Chromium multi-process architecture : the browser process and the render process. Generally speaking, there can be only one browser process and multiple render processes. I will give them more detailed discussions below.

The Browser Process

The Browser process is also known as the browser for short (this is not the same idea as the Browser we generally speak of, which refers to an program on your computer that allows to interact with information from internet). This process is mainly responsible for managing all render processes and displaying UI.

The browser process maintains two threads: main/UI thread and I/O thread. Main/UI thread is largely responsible for rendering web pages on screen. I/O thread takes care of IPC communication between the browser process and render processes, and any network communication is also handled in this thread. Each thread runs several different objects. In the section below, I will explain details of all major objects categorized by the thread they belong to.

RenderProcessHost: the browser process might have more than one RenderProcessHost. Each one connects to a render process with one-to-one relationship. The primary responsibility of RenderProcessHost is to dispatch view-specific messages to RenderViewHost and digest the rest non-view-specific messages. This object is also needed to uniquely identify a RenderView along with a RenderView Id because a render process might have more than one RenderView and the Id is only unique inside a render process but not within the browser process.

RenderViewHost: as I mentioned above, RenderViewHost receives view-specific messages from RenderProcessHost. The relationship between RenderProcessHost and RenderViewHost is one-to-many because a render process might generate more than one RenderView (e.g. a web page and a popup in the same tab) and RenderProcessHost needs to pass that information to corresponding RenderViewHost. This object is responsible for navigational commands, receiving input events, and painting web pages.

WebContents: this object represents a tab with a web page in it. It is responsible for displaying a web page in a rectangular view.

Browser: this object represents a browser window and might contain multiple WebContents.

Channel: this object defines methods for communicating across pipes. Its main responsibility is to communicate with render processes over IPC.

ResourceDispatcherHost: this object is responsible for sending network request to the internet. It acts as a gate to the internet. If a render process wants to send a request to the wild, it needs to send this request to RenderProcessHost first. Then RenderProcessHost forwards this request to ResourceDispatcherHost to actually send the request.

The Render Process

The render process is also known as the renderer for short. This process maintains two thread: main thread and render thread, and is responsible for constructing a web page.

The render process maintains two threads: main thread and render thread. Main thread has only one object RenderProcess whose solely responsibility is to facilitate cross-thread communication between render thread in which RenderView lives and I/O thread of the browser process. Render thread, on the other hand, takes care of generating web pages. In the section below, I will illustrate major objects in the render process.

RenderProcess: as I mentioned above, RenderProcess is mainly used for facilitating cross-thread communication.

ResourceDispatcher: sometimes a web page needs to make request to server to fetch content. The render process does not have access to the internet. It has to rely on ResourceDispatcher to forward a request to the browser via IPC.

Webkit: this is the rendering engine used in Chromium. It is used for constructing DOM and laying out web pages. Webkit consists of two primary components: WebCore which contains core layout functionality and JavaScriptCore where JavaScript interpreter V8 lives.

Components Communication

So far, I have discussed some major components in Chromium Architecture. In this section, I am going to to briefly talk about major connectors or communication pathways in the system.

IPC: the communication between the browser process and multiple render processes is via inter-process communication, which is based on the asynchronous named pipe created for each render process. The pipe serves as a communication bridge for passing messages between Channel in the browser and RenderProcess in the renderer. Because the communication is often bidirectional, the provided and required interfaces can be both IPC Listener interface. This kind of communication is achieved through implicit invocation because messages are sent to the system, and the system will invoke appropriate function on another component.

ChannelProxy: messages from and to the render process is not communicating directly on the main/UI thread of the browser process. Instead, it delegates the work to ChannelProxy which sits on I/O thread. This is because Channels are not thread safe. The ChannelProxy provides safety for the cross-thread communication between main/UI thread and I/O thread when sending and receiving messages. This ChannelProxy also has a MessageFilter that intercepts any resource requests (e.g. network requests) and forward them directly to the ResourceDispatcherHost. With this ChannelProxy, all of the performance critical messages are handled entirely on I/O thread and thus will not have any negative impact on main/UI thread of the browser process.

LPC: local procedure call is probably the most used connectors in the Chromium multi-process architecture. A number of components communicate via LPC. For example, Browser stores references to many WebContents which stores references to many RenderViewHost, when a function is invoked in the Browser, it sends messages to all of its referenced components by invoking functions on them. The provided and required interfaces are often parameters and arguments on a specific invoked function.

Information Flow

How does information flow move through various components and connectors? To answer this question, I am going to take a life of a “mouse click” message from Chromium official documentation as an example. When a mouse click event is received by main/UI thread of the browser process, it sends to RenderViewHost, which in turn tells RenderProcessHost to send the message to ChannelProxy. Then, ChannelProxy will proxy the message to I/O thread of the browser process and send it to the render process via IPC pipe. In the render process, the message is received by RenderView, which in turns hand this message to WebKit. Finally, WebKit JavaScriptCore will trigger appropriate callback function that handles this mouse click event.

Architecture Analysis

Client-Server Architecture: If we zoom out and look at the overall multi-process architecture from a higher level perspective, it primarily consists of one browser process and many render processes. The browser process can communicate to render processes via IPC, but there is no communication between render processes. The browser process does not really care about details of a render process as long as it follows certain requirements. These are core characteristics in client-server architecture. The server is the browser process; the clients are the render processes; the connector is IPC instead of HTTP.

Layered Architecture: From the perspective of how a web page is generated, the multi-process architecture can also fit to layered architecture. The architecture can be roughly divided into 7 application layers: WebKit, RenderView, RenderProcess, RenderProcessHost, RenderViewHost, WebContents, and Browser (bottom-to-up order). Each layer has its own responsibility. Layers do not have knowledge or dependent on any higher-level layers.

With multi-process architecture, each render process is sandboxed and thus has restricted access to system resources. If a render process wants to make a network request, it has to communicate with the browser process first. This sandbox technique engenders better security because even if a render process is compromised, it limits the damage that attackers can cause to the operating system. Sandboxing each render process also results in better stability because a crash in one render process (tab) will not have any impact on other render processes (tabs). Because multi-process architecture is client-server like from a high level perspective, it also engenders qualities of client-server architecture such as scalability, and maintainability.

The most noticeable benefit of multi-process architecture is the ability to modify the entire software easily. This is partially resulted from the client-server architecture where the render process represents the client and the browser process represents the server. More importantly, it is the event-driven system that largely contributes to the modifiability. The browser process and the render process communicate via IPC. Specifically speaking, components involved in this communication are equipped with the IPC Channel Listener interface. This decouples sender component from listener component because they do not need to know the existence of each other. The sender component can just broadcast the message to the system. The message bus will then hand it to any components who are interested in this message. With this event-driven system, we can easily add or remove render processes.

References

Chromium multi-process architectural overview: https://www.figma.com/file/KBTjp1Xe9ejFHChmq1El31zf/Chromium-Architecture

“Browser Market Share Worldwide.” StatCounter Global Stats,

http://gs.statcounter.com/browser-market-share.

“The Chromium Projects.” The Chromium Projects, www.chromium.org/.

I aim to save people from the overwhelming tsunami of information.

I aim to save people from the overwhelming tsunami of information.