Chromium shutdown

 参考文档:

https://www.chromium.org/developers/shutdown/

https://chromium.googlesource.com/chromium/src.git/+/HEAD/docs/shutdown.md#Step-0_Profile-destruction

 

  1. 配置文件销毁
  2. 浏览器进程关闭
    1. 停止 UI 消息循环
    2. BrowserProcessImpl 删除
    3. ContentMain() 退出
  3. 渲染器进程关闭
    1. 浏览器进程通过以下方式触发关闭:

配置文件销毁

shutdown.md

本文档记录了 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 线程ThreadPoolProfile仍然可用的组件的关闭步骤的好地方。

ChromeBrowserMainParts::PostMainMessageLoopRun还调用BrowserProcessImpl::StartTearDown删除BrowserProcessImpl(aka g_browser_process) 拥有的许多服务。其中一项服务是ProfileManager删除ProfileManager删除Profiles作为删除 a 的一部分Profile,它KeyedServices被删除,包括:

  • 同步服务
  • 历史服务

第 3 步:加入其他线程

IO 线程已加入。在此之后无法收到 IPC 或 Mojo。

ThreadPool关机开始。此时,没有新的SKIP_ON_SHUTDOWNCONTINUE_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也被引用,很像ProfileScopedKeepAlive 禁止拆卸,并且 refcount 由KeepAliveRegistry.

停止 UI 消息循环

  • 接收到导致~ScopedKeepAlive(关闭窗口、关闭最后一个选项卡、应用程序终止的键盘快捷键等)的 UI 事件。
  • 如果 refcountKeepAliveRegistry下降到零,那么我们开始应用程序终止。
    • 请注意,macOS 通过添加额外ScopedKeepAliveAppController.
  • 如果 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 线程终止的事件序列)

 

posted @ 2022-07-01 11:25  冰糖葫芦很乖  阅读(234)  评论(0编辑  收藏  举报