Multi-Process Architecture
Reprint Please specify source: Https://ahangchen.gitbooks.io/chromium_doc_zh/content/zh//Start_Here_Background_Reading/Multi-process_ Architecture.html
This document describes the high-level architecture of the chromium
Problem
It is almost impossible to build a rendering engine that will never hang or crash. It is almost impossible to build a completely secure rendering engine.
To some extent, the current state of the Web browser is like a separate user who worked with the past multitasking operating system. As in one such operating system the error program will let the whole system hang up, so a wrong web page can also let a modern browser hang out. Just need a browser or plug-in bug, hungry to let the entire browser and all the running tabs stop running.
Modern operating systems are more robust because they divide the application into separate threads that are isolated from each other. Crash in one program usually does not affect other programs or the entire operating system, and each user's access to user data is limited.
Architecture Overview
We use separate processes for the browser's tabs to protect the entire application from bugs and failures in the rendering engine. We also limit mutual access to each render engine process, as well as their access to other parts of the system. To some extent, this provides memory protection for Web browsing and provides access control for the operating system.
We call the process that runs the UI the main process (main), which is called the "browser process" or "browser (Browser)" of the plug-in process. Similarly, a tab-related process is called a "render thread" or "renderer (renderer)". The renderer uses the WebKit open Source engine to implement the layout of interrupts and HTML.
Managing the rendering process
Each rendering process has a global renderprocess object that manages the communication between it and the parent browser process, maintaining the global state. The browser maintains a corresponding renderviewhost for each rendering process to manage the browser state and communicate with the renderer. The browser communicates with the renderer using the chromium's IPC system.
Manage view
Each rendering process has more than one Renderview object, which is managed by renderprocess (it is related to the contents of the tab page). The corresponding Renderprocesshost maintains a renderviewhost associated with each view in the renderer. Each view is given a view ID to distinguish between different view in the same renderer. These IDs are unique within each renderer, but not in the browser, so distinguishing a view requires a renderprocesshost and a view ID.
The communication between a browser and a specific tab containing content is done through these renderviewhost objects, and they know how to send messages to renderprocess and Renderview through their renderprocesshost.
Components and Interfaces
In the rendering process:
renderprocess handles communication with the corresponding renderprocesshost in the browser. Each rendering process has a unique renderprocess object. This is how the interaction between all browsers-renderers occurs.
The Renderview object communicates with the Renderviewhost and our WebKit embedded layer (via renderprocess) that corresponds to it in the browser process. This object represents the content of a Web page in a tab or a pop-up window.
In the browser process:
- The browser object represents the top-level browser window
- The Renderprocesshost object represents the IPC connection of the browser-side browser to the renderer. In the browser process, each render process has a Renderprocesshost object.
- The Renderviewhost object encapsulates the communication with the remote browser, renderwidgethost processing the input and drawing the Renderwidget in the browser.
For more information on how this embedding works, you can see how Chromium displays Web pages design document.
Shared Paint Process
Typically, each new window or tab is opened in a new process. The browser will generate a new process and then instruct it to create a renderview.
Sometimes, there is a need or desire to share the rendering process between tabs or Windows. A Web application opens a new window when it is expected to synchronize, for example, using window.open in JavaScript. In this case, when we create a new window or tab, we need to reuse the process that opens the window. We also have some strategies for assigning new tabs to the existing processes (if the total number of processes is too large, or if the user has opened a process for the domain name). These strategies are also described in the process models.
Detection of crash or error rendering
Each IPC connection to the browser process observes the process handle. If these handles are signaled (signaled), then the rendering process is dead and the tab gets a notification. From this point on, we will show a "sad tab" screen to inform the user that the renderer has been hung up. This page can be reloaded by pressing the refresh button or by opening a new navigation. At this point, we will notice that there is no corresponding process and then create a new one.
Sandbox in the renderer
The given WebKit is run in a separate process, so we have the opportunity to limit its access to system resources. For example, we can make sure that the renderer's unique network permissions are implemented through its parent browser process. Similarly, we can restrict its access to the file system to use the permissions built into the host operating system.
In addition to restricting the renderer's access to the file system and the network, we can also limit its permissions on the user's display and related things. We run each process in a separate Windows desktop (not visible to users). This avoids letting the renderer compromise between a new tab or a snap button.
Return memory
Having the renderer run in a separate process makes it more straightforward to give the hidden tabs a lower priority. Typically, the minimized processes on the Windows platform will put their memory automatically into the host in a "Free memory" pool. In the case of low memory, Windows will swap this portion of memory to higher priority memory before swapping them to disk to ensure that the user-visible program is more responsive. We can use the same policy for hidden tabs. When the renderer process does not have a top-level tab, we can release the "Working set" space of the process as a signal to the system, giving it priority to swap the memory to disk if necessary. Because we found that when a user switches between two tabs, reducing the working set size also reduces the tab switching performance, so we are gradually releasing this part of the memory. This means that if the user switches back to the most recently used tab, the memory for this tab is more likely to be swapped in than the most recently accessed tab page. Users with enough memory will not notice this process when they run all their programs: In fact, Windows will only re-declare the data when needed, so there is no performance bottleneck when there is sufficient memory.
This can help us get the best memory trajectory in low memory situations. The memory associated with almost unused background tabs can be completely swapped out, and the data from the Foreground tab can be fully loaded into memory. Conversely, a single-process browser randomly allocates data from all tabs in its memory, and it is not possible to isolate used and unused data so clearly, resulting in memory and performance waste.
Plug - ins
The firefox-style Npapi plugin runs in their own process and is isolated from the renderer. This is described in plugin architecture.
How to add a new feature (without expanding the renderview/renderviewhost/webcontents) issue
In the past, new features, such as AutoFill sample samples, could be imported into the Renderview class (in the renderer process) and the Renderviewhost class (in the browser process) by importing the code for the new feature. If a new feature is processed in the IO line thread of the browser process, then its IPC information is dispatched by the Browsermessagefilter. Renderviewhost will invoke the IPC information only to invoke the WebContent object process, which calls another piece of code. The IPC information between all browsers and Renderers is declared in a huge render_messages_internal.h, and modifying all of these files for each new feature means that these classes become bloated.
Solution Solutions
We have added a mechanism for helper classes and filtering of IPC information on each of the threads above. This makes it easier to write self-consistent features.
Renderer side
If you want to filter and send IPC information, implement the Renderviewobserver Interface (CONTENT/RENDERER/RENDER_VIEW_OBSERVER.H). The Renderviewobserver base class holds a Renderview class that manages the life cycle of an object and binds it to Renderview (which is overridable). This class can filter and send IPC messages, in addition to the many features required for page loading and closing notifications. As an example, you can view Chromeextensionhelper (chrome/renderer/extensions/chrome_extension_helper.h).
If your feature has a portion of the code inside the WebKit, avoid callbacks through the Webviewclient interface, so that we don't make webviewclient huge. Consider creating a new WebKit interface for the WebKit code call, and let the renderer-side class implement it. As an example, view Webautofillclient (webkit/chromium/public/webautofillclient.h).
Browser UI Thread
The Webcontentsobserver (Content/public/browser/web_contents_observer.h) interface allows the UI thread's objects to filter IPC information and give notifications about page navigation. As an example: View Tabhelper (Chrome/browser/extensions/tab_helper.h).
Browser Other threads
In order to filter and send IPC information to other browser threads, such as Io/file/webkit and so on, implement the Browsermessagefilter Interface (CONTENT/BROWSER/BROWSER_MESSAGE_FILTER.H). The Browserrenderprocesshost object creates and adds a filter in its createmessagefilters function.
Typically, if an attribute has many IPC messages, these messages should be moved to a separate file (for example, not added to Render_messages_internal.h). This is also helpful for filtering threads (in addition to IO threads). As an example, view content/common/pepper_file_messages.h. This allows their filters to pepperfilemessagefilter easily send files to the file thread without specifying their IDs in many places.
void pepperfilemessagefilter::overridethreadformessage ( const ipc::message& Message, browserthread::id* thread) { if (Ipc_message_class (MESSAGE) = = Pepperfilemsgstart) *thread = browserthread::file;}
"Translation" chromium multi-process architecture