Multi-process architecture
Chrome is not one program but a small operating system of them: one privileged browser process coordinating a fleet of sandboxed ones. The split is a security decision first and a stability decision second — a tab crashing takes down a process the browser can simply replace.
chrome://process-internals
6 sub-nodes →Site Isolation & the sandbox
Two layers of the same argument. Site Isolation puts every site in its own renderer, so one site’s data is never in another’s address space — the answer to Spectre, where reading your own process’s memory was enough. The sandbox then assumes that renderer is already compromised and takes away the system calls that would let it matter.
one renderer per site (scheme + eTLD+1)
Mojo & IPC
Processes that share nothing still have to talk. Interfaces are declared in .mojom files, and the generated code gives you a Remote on one side and a Receiver on the other, connected by a message pipe that can be passed through other pipes. Every call is asynchronous, and every message crosses a trust boundary that has to validate it.
interface Frame { Navigate(Url url); };
// → Remote<Frame> / Receiver<Frame>The content layer
content/ is the web engine — the process model, navigation, the frame tree, everything needed to display a page — and it has no opinions about bookmarks or a settings dialog. chrome/ is the product built on top of it through content/public. That line is why Electron and Android WebView exist.
chrome/ → content/public/ → content/
Compositing
The last stretch of the pipeline, and the one that decides whether the page feels fast. Painted content becomes textures on layers, layers become quads with transforms, and quads from every process are aggregated into one frame per vsync — most of it on threads that are not running your JavaScript.
paint → raster → quads → aggregate → draw
6 sub-nodes →Threads, sequences & tasks
Almost nothing in Chromium creates a thread. Work is posted to a sequence — an ordered stream of tasks that may hop between physical threads — with a trait saying how urgent it is and whether it may block. The type system carries the rule: a class asserts which sequence it lives on, and violating it fails in a debug build rather than under load.
base::ThreadPool::PostTask(FROM_HERE,
{base::MayBlock()}, std::move(task));