summaryrefslogtreecommitdiff
path: root/chromium/docs/shutdown.md
blob: 31ec9e0396d1b28e95df9f38bd672ec714f9670f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# Chrome Shutdown

[TOC]

This documents shutdown steps on Windows, Mac and Linux.

On Android, the system can terminate the Chrome app at any point without running
any shutdown step.

See below for how the process differs on ChromeOS.

## Step 1: Exiting the main loop

Shutdown starts when nothing keeps Chrome alive. Typically, this happens when
all browser windows are closed, but other things can [keep Chrome
alive](https://source.chromium.org/chromium/chromium/src/+/main:components/keep_alive_registry/keep_alive_types.h).

When nothing keeps Chrome alive, `BrowserProcessImpl::Unpin` asks the main
thread's message loop to quit as soon as it no longer has tasks ready to run
immediately.

```
base::RunLoop::QuitWhenIdle
…
BrowserProcessImpl::Unpin
BrowserProcessImpl::OnKeepAliveStateChanged
KeepAliveRegistry::OnKeepAliveStateChanged
KeepAliveRegistry::Unregister
ScopedKeepAlive::~ScopedKeepAlive
...
Browser::UnregisterKeepAlive
BrowserList::RemoveBrowser
Browser::~Browser
```

Following this request, `ChromeBrowserMainParts::MainMessageLoopRun` exits. Tasks
posted to the main thread without a delay prior to this point are guaranteed to
have run; tasks posted to the main thread after this point will never run.

## Step 2: Cleaning up, after main loop exit

`BrowserMainRunnerImpl::Shutdown` is called on the main thread. Within that
method, `BrowserMainLoop::ShutdownThreadsAndCleanUp` orchestrates the main
shutdown steps.

`ChromeBrowserMainParts::PostMainMessageLoopRun` is invoked. It invokes the
`PostMainMessageLoopRun` method of each `ChromeBrowserMainExtraParts` instance.
This is a good place to perform shutdown steps of a component that require the
IO thread, the `ThreadPool` or the `Profile` to still be available.

`ChromeBrowserMainParts::PostMainMessageLoopRun` also invokes
`BrowserProcessImpl::StartTearDown` which deletes many services owned by
`BrowserProcessImpl` (aka `g_browser_process`). One of these services is the
`ProfileManager`. Deleting the `ProfileManager` deletes `Profiles`. As part of
deleting a `Profile`, its `KeyedServices` are deleted, including:

* Sync Service
* History Service

## Step 3: Joining other threads

The IO thread is joined. No IPC or Mojo can be received after this.

`ThreadPool` shutdown starts. At this point, no new `SKIP_ON_SHUTDOWN` or
`CONTINUE_ON_SHUTDOWN` task can start running (they are deleted without
running). The main thread blocks until all `SKIP_ON_SHUTDOWN` tasks that started
running prior to `ThreadPool` shutdown start are complete, and all
`BLOCK_SHUTDOWN` tasks are complete (irrespective of whether they were posted
before or after `ThreadPool` shutdown start). When no more `SKIP_ON_SHUTDOWN` is
running and no more `BLOCK_SHUTDOWN` task is queued or running, the main thread
is unblocked and `ThreadPool` shutdown is considered complete. Note:
`CONTINUE_ON_SHUTDOWN` tasks that started before `ThreadPool` shutdown may still
be running.

At this point, new tasks posted to the IO thread or to the `ThreadPool` cannot
run. It is illegal to post a `BLOCK_SHUTDOWN` task to the `ThreadPool` (enforced
by a `DCHECK`).

## Step 4: Cleaning up, after joining other threads

`ChromeBrowserMainParts::PostDestroyThreads` is invoked. It invokes
`BrowserProcessImpl::PostDestroyThreads`. Since it is guaranteed that no
`SKIP_ON_SHUTDOWN` or `BLOCK_SHUTDOWN` task is running at this point, it is a
good place to delete objects accessed directly from these tasks.

Then, if a new Chrome executable, it is swapped with the current one
(Windows-only).

```
upgrade_util::SwapNewChromeExeIfPresent
browser_shutdown::ShutdownPostThreadsStop
ChromeBrowserMainParts::PostDestroyThreads
content::BrowserMainLoop::ShutdownThreadsAndCleanUp
content::BrowserMainLoop::ShutdownThreadsAndCleanUp
content::BrowserMainRunnerImpl::Shutdown
```

## ChromeOS differences
On ChromeOS, the ash browser is only supposed to exit when the user logs out.

When the user logs out, the browser sends a `StopSession` message to the
[session_manager](https://chromium.googlesource.com/chromiumos/platform2/+/refs/heads/main/login_manager/README.md).
The session_manager then sends a SIGTERM to the main browser process to cause an
exit. Once SIGTERM is received, it starts shutting down the main loop and
cleaning up in the sequence described above.

Unlike other desktop platforms, the shutdown is time limited. If the browser
process has not exited within a certain time frame (normally, 3 seconds), the
session_manager will SIGKILL the browser process since the user is looking at
a blank screen and unable to use their Chromebook until the browser exits.