參考文檔:
https://www.chromium.org/developers/shutdown/
配置文件銷燬
本文檔記錄了 Windows、Mac 和 Linux 上的關機步驟。
在 Android 上,系統可以隨時終止 Chrome 應用程序,而無需運行任何關機步驟。
請參閱下文,瞭解該過程在 ChromeOS 上的不同之處。
步驟 0:配置文件銷燬
從 M98 開始,Chrome 可以Profile
與關機分開銷燬對象;在 Windows 和 Linux 上,這發生在多配置文件場景中。在 macOS 上,它也可能發生在單一配置文件的場景中,因爲 Chrome 的生命週期與瀏覽器窗口是分開的。
通常,當所有瀏覽器窗口都關閉時會觸發此邏輯,但其他事情可以保持Profile
活動狀態。
~ScopedProfileKeepAlive
發佈要運行的任務RemoveKeepAliveOnUIThread
。這會減少 中的引用計數ProfileManager
,如果它達到零,則DestroyProfileWhenAppropriate
調用。
ProfileDestroyer::DestroyProfileWhenAppropriate
...
ProfileManager::RemoveProfile
ProfileManager::RemoveKeepAlive
ScopedProfileKeepAlive::RemoveKeepAliveOnUIThread
與常規配置文件不同,OTR 配置文件不會重新計算。相反,~Browser
在刪除自身後檢查配置文件的瀏覽器計數。如果爲零,則DestroyProfileWhenAppropriate
直接調用。
ProfileDestroyer::DestroyProfileWhenAppropriate
Browser::~Browser
您可以使用ProfileManager
日誌記錄來檢查配置文件的保活狀態:
$ ./out/Default/chrome --enable-logging=stderr --v=0 --vmodule=profile_manager=1 [71002:259:0328/133310.430142:VERBOSE1:profile_manager.cc(1489)] AddKeepAlive(Default, kBrowserWindow). keep_alives=[kWaitingForFirstBrowserWindow (1), kBrowserWindow (1)] [71002:259:0328/133310.430177:VERBOSE1:profile_manager.cc(1543)] ClearFirstBrowserWindowKeepAlive(Default). keep_alives=[kBrowserWindow (1)] [71002:259:0328/133314.468135:VERBOSE1:profile_manager.cc(1489)] AddKeepAlive(Default, kExtensionUpdater). keep_alives=[kBrowserWindow (1), kExtensionUpdater (1)] [71002:259:0328/133314.469444:VERBOSE1:profile_manager.cc(1522)] RemoveKeepAlive(Default, kExtensionUpdater). keep_alives=[kBrowserWindow (1)] [71002:259:0328/133315.396614:VERBOSE1:profile_manager.cc(1489)] AddKeepAlive(Default, kOffTheRecordProfile). keep_alives=[kBrowserWindow (1), kOffTheRecordProfile (1)] [71002:259:0328/133417.078148:VERBOSE1:profile_manager.cc(1522)] RemoveKeepAlive(Default, kBrowserWindow). keep_alives=[kOffTheRecordProfile (1)] [71002:259:0328/133442.705250:VERBOSE1:profile_manager.cc(1522)] RemoveKeepAlive(Default, kOffTheRecordProfile). keep_alives=[] [71002:259:0328/133442.705296:VERBOSE1:profile_manager.cc(1567)] Deleting profile Default
第一步:退出主循環
當沒有任何東西可以讓 Chrome 保持活力時,就會開始關機。通常,當所有瀏覽器窗口都關閉時會發生這種情況,但其他事情可以讓 Chrome 保持活動狀態。
當沒有任何東西可以讓 Chrome 保持活動狀態時,BrowserProcessImpl::Unpin
一旦它不再有準備好立即運行的任務,就會要求主線程的消息循環退出。
base::RunLoop::QuitWhenIdle … BrowserProcessImpl::Unpin BrowserProcessImpl::OnKeepAliveStateChanged KeepAliveRegistry::OnKeepAliveStateChanged KeepAliveRegistry::Unregister ScopedKeepAlive::~ScopedKeepAlive ... Browser::UnregisterKeepAlive BrowserList::RemoveBrowser Browser::~Browser
在此請求之後,ChromeBrowserMainParts::MainMessageLoopRun
退出。保證在此之前沒有延遲地發佈到主線程的任務已經運行;此後發佈到主線程的任務將永遠不會運行。
第 2 步:清理,在主循環退出後
BrowserMainRunnerImpl::Shutdown
在主線程上調用。在該方法中,BrowserMainLoop::ShutdownThreadsAndCleanUp
協調主要的關閉步驟。
ChromeBrowserMainParts::PostMainMessageLoopRun
被調用。它調用PostMainMessageLoopRun
每個ChromeBrowserMainExtraParts
實例的方法。這是執行需要 IO 線程ThreadPool
或Profile
仍然可用的組件的關閉步驟的好地方。
ChromeBrowserMainParts::PostMainMessageLoopRun
還調用BrowserProcessImpl::StartTearDown
刪除BrowserProcessImpl
(aka g_browser_process
) 擁有的許多服務。其中一項服務是ProfileManager
. 刪除ProfileManager
刪除Profiles
。作爲刪除 a 的一部分Profile
,它KeyedServices
被刪除,包括:
- 同步服務
- 歷史服務
第 3 步:加入其他線程
IO 線程已加入。在此之後無法收到 IPC 或 Mojo。
ThreadPool
關機開始。此時,沒有新的SKIP_ON_SHUTDOWN
或CONTINUE_ON_SHUTDOWN
任務可以開始運行(它們在沒有運行的情況下被刪除)。主線程阻塞,直到所有在關機開始SKIP_ON_SHUTDOWN
之前開始運行的任務ThreadPool
都完成,並且所有BLOCK_SHUTDOWN
任務都完成(無論它們是在ThreadPool
關機開始之前還是之後發佈)。當沒有SKIP_ON_SHUTDOWN
更多的任務在運行並且沒有更多的BLOCK_SHUTDOWN
任務排隊或運行時,主線程被解除阻塞並且ThreadPool
關閉被認爲是完成的。注意:在關機CONTINUE_ON_SHUTDOWN
前啓動的任務ThreadPool
可能仍在運行。
此時,發佈到 IO 線程或發佈到 IO 線程的新任務ThreadPool
無法運行。BLOCK_SHUTDOWN
將任務發佈到ThreadPool
(由 a 強制執行)是非法的DCHECK
。
第四步:清理,加入其他線程後
ChromeBrowserMainParts::PostDestroyThreads
被調用。它調用BrowserProcessImpl::PostDestroyThreads
. 由於可以保證此時沒有SKIP_ON_SHUTDOWN
任務BLOCK_SHUTDOWN
正在運行,因此最好刪除從這些任務中直接訪問的對象。
然後,如果是新的 Chrome 可執行文件,它會與當前的可執行文件交換(僅限 Windows)。
base::RunLoop::QuitWhenIdle … BrowserProcessImpl::Unpin BrowserProcessImpl::OnKeepAliveStateChanged KeepAliveRegistry::OnKeepAliveStateChanged KeepAliveRegistry::Unregister ScopedKeepAlive::~ScopedKeepAlive ... Browser::UnregisterKeepAlive BrowserList::RemoveBrowser Browser::~Browser
Chrome 操作系統差異
在 ChromeOS 上,ash 瀏覽器應該只在用戶註銷時退出。
當用戶註銷時,瀏覽器會向session_managerStopSession
發送一條消息。session_manager 然後向主瀏覽器進程發送一個 SIGTERM 以導致退出。一旦收到 SIGTERM,它就會開始關閉主循環並按照上述順序進行清理。
與其他桌面平臺不同,關機是有時間限制的。如果瀏覽器進程在某個時間範圍內(通常爲 3 秒)沒有退出,則 session_manager 將 SIGKILL 瀏覽器進程,因爲用戶正在查看一個空白屏幕並且在瀏覽器退出之前無法使用他們的 Chromebook。
瀏覽器進程關閉
BrowserProcess
也被引用,很像Profile
. ScopedKeepAlive
禁止拆卸,並且 refcount 由KeepAliveRegistry
.
停止 UI 消息循環
- 接收到導致
~ScopedKeepAlive
(關閉窗口、關閉最後一個選項卡、應用程序終止的鍵盤快捷鍵等)的 UI 事件。 - 如果 refcount
KeepAliveRegistry
下降到零,那麼我們開始應用程序終止。- 請注意,macOS 通過添加額外
ScopedKeepAlive
的AppController
.
- 請注意,macOS 通過添加額外
- 如果 refcount 達到零,則將任務發佈到消息循環以退出
- 通知
content::NOTIFICATION_APP_TERMINATING
被廣播 - UI 消息循環最終停止運行,我們退出
RunUIMessageLoop()
. 請注意,所有其他主要瀏覽器線程仍在運行它們的消息循環。因此,即使主 (UI) 線程比所有其他加入的瀏覽器線程壽命長,它也會MessageLoop
首先終止。
BrowserProcessImpl 刪除
- 退出 UI 消息循環後,在 BrowserMainParts::RunMainMessageLoopParts 中啓動關閉序列,它調用 PostMainMessageLoopRun。
- 在 ChromeBrowserMainParts::PostMainMessageLoopRun 中:
- ProcessSingleton 被釋放。
- MetricsService(記錄 UMA 指標)已停止,其中:
- 創建所有剩餘指標的日誌(以供將來上傳)。
- 記錄成功關機。
- 磁盤上的持久性指標文件仍然存在,以防在此之後更新其他指標。任何此類值都將在瀏覽器啓動後的某個時間在下次運行期間發送。
- 我們將本地狀態持久化到磁盤。
- 我們刪除 g_browser_process,其中:
- 刪除 ProfileManager(刪除所有配置文件並保持其狀態,例如 Preferences)
- 按順序加入看門狗、IO、CACHE、PROCESS_LAUNCHER 線程
- 關閉 DownloadFileManager 和 SaveFileManager
- 加入 FILE 線程
- 刪除加入 WEBKIT 線程的 ResourceDispatcherHost
- 加入數據庫線程
ContentMain() 退出
- AtExitManager 超出範圍並銷燬所有 Singletons/LazyInstances
渲染器進程關閉
瀏覽器進程通過以下方式觸發關閉:
- 關閉選項卡(解釋從 UI 線程對象到渲染器進程的 IO 線程終止的事件序列)