chromium启动流程(一)-browser进程启动流程

前面通过一些列文章,我们了解清楚了chromium的线程模型和ipc通信框架ipcz。 接下来我们分析一下chromium的启动流程。
本篇以browser进程启动为例进行分析。

chromium的启动入口在chrome/app/chrome_exe_main_aura.cc中。

这里面Aura是Chromium项目中用于窗口管理的底层框架。它负责管理用户界面的窗口和其他图形元素。Aura提供了一个跨平台的框架,用于构建Chromium浏览器的用户界面组件。
Aura框架被引入以取代Chromium项目中早期使用的称为“views”的窗口系统。Aura提供更好的性能和更大的灵活性,更容易支持多个平台。
值得注意的是,软件项目可能随时间发展而发生变化,因此自我在2022年1月进行更新以来,Chromium和Aura可能已经有了变化或更新。如果有重大变化或新的发布,请查阅官方的Chromium项目文档或发布说明以获取最新信息。

整理流程

废话不多说我们直接看代码

int main(int argc, const char** argv) {
  return ChromeMain(argc, argv);
}

函数直接调用ChromeMain函数。
chrome/app/chrome_main.cc

int ChromeMain(int argc, const char** argv) {
  int64_t exe_entry_point_ticks = 0;
,,,,,,

  ChromeMainDelegate chrome_main_delegate(
      base::TimeTicks::FromInternalValue(exe_entry_point_ticks));
  content::ContentMainParams params(&chrome_main_delegate);

#if BUILDFLAG(IS_WIN)
 ......
#else
  params.argc = argc;
  params.argv = argv;
  base::CommandLine::Init(params.argc, params.argv);
#endif  // BUILDFLAG(IS_WIN)
  base::CommandLine::Init(0, nullptr);
  [[maybe_unused]] base::CommandLine* command_line(
      base::CommandLine::ForCurrentProcess());
......

  // Chrome-specific process modes.
  if (headless::IsHeadlessMode()) {
    ......
  }
......

  int rv = content::ContentMain(std::move(params));

  if (chrome::IsNormalResultCode(static_cast<chrome::ResultCode>(rv)))
    return content::RESULT_CODE_NORMAL_EXIT;
  return rv;
}

函数主要准备参数, 并且处理Headless模式启动,我们不多分析,准备好参数之后调用ContentMain函数。
content/app/content_main.cc

int NO_STACK_PROTECTOR ContentMain(ContentMainParams params) {
  auto runner = ContentMainRunner::Create();
  return RunContentProcess(std::move(params), runner.get());
}

函数先创建ContentMainRunner类,实例为ContentMainRunnerImpl。
ContentMain函数调用RunContentProcess 函数。继续往下看
content/app/content_main.cc

178 int NO_STACK_PROTECTOR
179 RunContentProcess(ContentMainParams params,
180                   ContentMainRunner* content_main_runner) {
181   base::FeatureList::FailOnFeatureAccessWithoutFeatureList();
      ......
        // 初始化CommandLine
238     base::CommandLine::Init(argc, argv);
239 
240 #if BUILDFLAG(IS_POSIX)
        // 初始化文件描述符表
241     PopulateFileDescriptorStoreFromFdTable();
242 #endif
       ...... 
247 #endif  // !BUILDFLAG(IS_ANDROID)
248 
       ......

300     ui::RegisterPathProvider();
        // 初始化content_main_runner
301     exit_code = content_main_runner->Initialize(std::move(params));
302 
303     if (exit_code >= 0) {
304       return exit_code;
305     }
306 
       ......

324   if (IsSubprocess())
325     CommonSubprocessInit();
326   exit_code = content_main_runner->Run();
327 
      ......
335 
336   return exit_code;
337 }

ContentMainRunnerImpl 主要用于启动浏览器, 301 行先初始化,326行调用ContentMainRunnerImpl.Run() 方法启动浏览器。
我们先看ContentMainRunnerImpl的初始化函数。

784 int ContentMainRunnerImpl::Initialize(ContentMainParams params) {
 785   // ContentMainDelegate is used by this class, not forwarded to embedders.
       ......
 821 
 822   is_initialized_ = true;
       ......
 847 
       // 创建ContentClient
 848   if (!GetContentClient())
 849     ContentClientCreator::Create(delegate_);
       ......
 878   
       // 初始化ContentClient
 879   ContentClientInitializer::Set(process_type, delegate_);
 880 
       ......
       // 加载V8引擎快照 
 953   LoadV8SnapshotIfNeeded(command_line, process_type);
 954 
      ......
1034   // Return -1 to indicate no early termination.
1035   return -1;
1036 }

848创建ContentClient实例子。在Chromium项目中,ContentClient 是一个接口类,它定义了与内容(Content)相关的一些回调和功能。具体来说,ContentClient 提供了一个接口,允许浏览器的不同部分(比如渲染进程)与内容相关的操作进行通信。
889行初始化ContentClient。我们看先ContentClient的初始化。

class ContentClientInitializer {
 public:
  static void Set(const std::string& process_type,
                  ContentMainDelegate* delegate) {
    ContentClient* content_client = GetContentClient();
    if (process_type.empty())
      content_client->browser_ = delegate->CreateContentBrowserClient();

    base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
    if (process_type == switches::kGpuProcess ||
        cmd->HasSwitch(switches::kSingleProcess) ||
        (process_type.empty() && cmd->HasSwitch(switches::kInProcessGPU)))
      content_client->gpu_ = delegate->CreateContentGpuClient();

    if (process_type == switches::kRendererProcess ||
        cmd->HasSwitch(switches::kSingleProcess))
      content_client->renderer_ = delegate->CreateContentRendererClient();

    if (process_type == switches::kUtilityProcess ||
        cmd->HasSwitch(switches::kSingleProcess))
      content_client->utility_ = delegate->CreateContentUtilityClient();
  }
};

函数主要初始化了如下成员变量

  • browser_: 创建类型为ChromeContentBrowserClient, 用于和browser 进程交互。(只有browser进程里面有)
  • gpu_:创建类型为ChromeContentGpuClient。只存在与gpu进程中。
  • chrome_content_utility_client_:创建类型为ChromeContentUtilityClient。只存在Utility进程中。
  • renderer_:创建类型为ChromeContentRendererClient。 只存在render进程中。

接下来我们继续看启动流程ContentMainRunnerImpl.Run().

1046 // This function must be marked with NO_STACK_PROTECTOR or it may crash on
1047 // return, see the --change-stack-guard-on-fork command line flag.
1048 int NO_STACK_PROTECTOR ContentMainRunnerImpl::Run() {
       ......
1052   const base::CommandLine* command_line =
1053       base::CommandLine::ForCurrentProcess();
       // 获取进程类型
1054   std::string process_type =
1055       command_line->GetSwitchValueASCII(switches::kProcessType);
1056 
       // 等待调试器
1057   if (command_line->HasSwitch(switches::kWaitForDebugger)) {
1058     DVLOG(1) << "Start WaitForDebugger1";
1059     base::debug::WaitForDebugger(600, true);
1060     DVLOG(1) << "End WaitForDebugger1";
1061   }
1062 
        ......
1067   // Run this logic on all child processes.
1068   if (!process_type.empty()) { 
          // process_type 不为空,表示非browser进程
1069     if (process_type != switches::kZygoteProcess) {
             // 非browser进程,非zygote进程做的一些初始化工作
             ......
1086     }
1087 
1088 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
1089     // If dynamic Mojo Core is being used, ensure that it's loaded very early in
1090     // the child/zygote process, before any sandbox is initialized. The library
1091     // is not fully initialized with IPC support until a ChildProcess is later
1092     // constructed, as initialization spawns a background thread which would be
1093     // unsafe here.
         // 加载mojo库
1094     if (IsMojoCoreSharedLibraryEnabled()) {
1095       CHECK_EQ(mojo::LoadCoreLibrary(GetMojoCoreSharedLibraryPath()),
1096                MOJO_RESULT_OK);
1097     }
1098 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
1099   }
1100 
       // 准备启动参数
1101   MainFunctionParams main_params(command_line);
1102   main_params.ui_task = std::move(content_main_params_->ui_task);
1103   main_params.created_main_parts_closure =
1104       std::move(content_main_params_->created_main_parts_closure);
1105   main_params.needs_startup_tracing_after_mojo_init =
1106       needs_startup_tracing_after_mojo_init_;
      ......

1123 
1124   if (process_type.empty()) // 启动浏览器进程
1125     return RunBrowser(std::move(main_params), start_minimal_browser);
1126 
       // 启动其他进程
1127   return RunOtherNamedProcessTypeMain(process_type, std::move(main_params),
1128                                       delegate_);
1129 }

1054-1055行代码根据启动参数获取进程启动类型。
1057-1061行代码 如果启动参数里面有–wait-for-debugger,则等待调试器。
1068-1099行如果不是browser进程做一些初始化操作,这里不详细分析。
1125 行如果启动的进程类型为browser,则调用RunBrowser启动浏览器。
1127-1128行启动其他类型的进程。

我们这篇文章分析浏览器类型进程启动。 所以看下RunBrowser函数。

1131 int ContentMainRunnerImpl::RunBrowser(MainFunctionParams main_params,
1132                                       bool start_minimal_browser) {
         ......
         // 创建BrowserTaskExecutor, 用于管理ui线程和io线程
1182     BrowserTaskExecutor::Create();
1183 
         ......
1204     if (has_thread_pool) {
1205       // The FeatureList needs to create before starting the ThreadPool.
           // 启动线程池
1206       StartBrowserThreadPool();
1207     }
1208 
        ......
1271   return RunBrowserProcessMain(std::move(main_params), delegate_);
1272 }

函数做了一些初始化工作,包括创建BrowserTaskExceutor 用于管理io线程和ui线程的调度。 启动线程池,然后调用RunBrowserProcessMain函数进一步启动。

int RunBrowserProcessMain(MainFunctionParams main_function_params,
                          ContentMainDelegate* delegate) {
 .......
  return BrowserMain(std::move(absl::get<MainFunctionParams>(exit_code)));
}

RunBrowserProcessMain 函数比较简单,直接调用了BrowserMain函数。

content/browser/browser_main.cc

// Main routine for running as the Browser process.
int BrowserMain(MainFunctionParams parameters) {
 ......

  base::CurrentProcess::GetInstance().SetProcessType(
      base::CurrentProcessType::PROCESS_BROWSER);
  ......
  std::unique_ptr<BrowserMainRunnerImpl> main_runner(
      BrowserMainRunnerImpl::Create());

  int exit_code = main_runner->Initialize(std::move(parameters));
 ......

  exit_code = main_runner->Run();
......

  return exit_code;
}

函数先创建BrowserMainRunnerImpl实例,然后执行它的Initialize函数进行初始化,最后调用它的Run方法进入到Looper消息循环。我们先看Initialize方法。
content/browser/browser_main_runner_impl.cc

71 int BrowserMainRunnerImpl::Initialize(MainFunctionParams parameters) {
        ......
        // 初始化Skia 相关Grphic 功能
 83     SkGraphics::Init();
 84 
        .....
 94 
        // 创建通知服务
 95     notification_service_ = std::make_unique<NotificationServiceImpl>();
 96 
       ......

        // 初始化字体      
105     gfx::InitializeFonts();
106 
107     auto created_main_parts_closure =
108         std::move(parameters.created_main_parts_closure);
109 
        // 创建Browser进程的主循环对象
110     main_loop_ = std::make_unique<BrowserMainLoop>(
111         std::move(parameters), std::move(scoped_execution_fence_));
112 
113     main_loop_->Init();
114 
115     if (created_main_parts_closure) {
116       std::move(created_main_parts_closure).Run(main_loop_->parts());
117     }
118 
        // 执行早期初始化
119     const int early_init_error_code = main_loop_->EarlyInitialization();
120     if (early_init_error_code > 0) {
121       main_loop_->CreateMessageLoopForEarlyShutdown();
122       return early_init_error_code;
123     }
124 
125     // Must happen before we try to use a message loop or display any UI.
        // 初始化工具套件
126     if (!main_loop_->InitializeToolkit()) {
127       main_loop_->CreateMessageLoopForEarlyShutdown();
128       return 1;
129     }
130 
        // 创建MainLoop前执行操作
131     main_loop_->PreCreateMainMessageLoop();
         // 创建MainLoop
132     main_loop_->CreateMainMessageLoop();
        // 创建MainLoop后执行操作
133     main_loop_->PostCreateMainMessageLoop();
134 
135     // WARNING: If we get a WM_ENDSESSION, objects created on the stack here
136     // are NOT deleted. If you need something to run during WM_ENDSESSION add it
137     // to browser_shutdown::Shutdown or BrowserProcess::EndSession.
138 
        // 初始化输入法相关
139     ui::InitializeInputMethod();
140   }
      // 执行启动任务。
141   main_loop_->CreateStartupTasks();
142   int result_code = main_loop_->GetResultCode();
143   if (result_code > 0) {
144     return result_code;
145   }
146 
147   // Return -1 to indicate no early termination.
148   return -1;
149 }
150 

函数使用BrowserMainLoop 包装线程模型里面的Looper。
110-111行创建BrowserMainLoop实例。
113行执行main_loop_的初始化。
119 行执行浏览器的早期初始化工作。
126 行初始化toolkit。
131-133行执行main_loop_ 初始化方法,在Looper前、中、后执行对应方法。
139行初始化输入法相关。
141行执行启动相关任务。

我们来看一下BrowserMainLoop的init方法。
content/browser/browser_main_loop.cc

void BrowserMainLoop::Init() {
  TRACE_EVENT0("startup", "BrowserMainLoop::Init");

  if (parameters_.startup_data) {
        ......
  }

  parts_ = GetContentClient()->browser()->CreateBrowserMainParts(
      !!parameters_.ui_task);
}

函数比较简单,这里创建了BrowserMainParts。 BrowserMainParts 是浏览器的主要部分,是通过不同part来实现浏览器的不同功能。我们来看一下它实现了哪些part。
chrome/browser/chrome_content_browser_client.cc

681 std::unique_ptr<content::BrowserMainParts>
1682 ChromeContentBrowserClient::CreateBrowserMainParts(bool is_integration_test) {
1683   std::unique_ptr<ChromeBrowserMainParts> main_parts;
1684   // Construct the Main browser parts based on the OS type.
1685 #if BUILDFLAG(IS_WIN)
      ......
1697 #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
       // 创建main_parts 实例子, 是平台相关的
1698   main_parts = std::make_unique<ChromeBrowserMainPartsLinux>(
1699       is_integration_test, &startup_data_);
       ......
1709 #else
       ......
1713 #endif
1714 
       // 线程通知相关
1715   main_parts->AddParts(
1716       std::make_unique<ChromeBrowserMainExtraPartsThreadNotifier>(
1717           base::BindOnce(&ChromeContentBrowserClient::InitOnUIThread,
1718                          weak_factory_.GetWeakPtr())));
1719 
1720   bool add_profiles_extra_parts = true;
        ......
1736 #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
       // 增加LinuxViews 相关的Part
1737   main_parts->AddParts(
1738       std::make_unique<ChromeBrowserMainExtraPartsViewsLinux>());
1739 #else
1740   main_parts->AddParts(std::make_unique<ChromeBrowserMainExtraPartsViews>());
1741 #endif
1742 #endif
1743 
     ......
1756 
1757 #if BUILDFLAG(IS_LINUX)
       // 添加Linux平台特有的Part
1758   main_parts->AddParts(std::make_unique<ChromeBrowserMainExtraPartsLinux>());
1759 #elif BUILDFLAG(IS_OZONE)
1760   main_parts->AddParts(std::make_unique<ChromeBrowserMainExtraPartsOzone>());
1761 #endif
1762 
       // 性能监控相关part
1763   main_parts->AddParts(
1764       std::make_unique<ChromeBrowserMainExtraPartsPerformanceMonitor>());
1765 
       // 性能管理相关part
1766   main_parts->AddParts(
1767       std::make_unique<ChromeBrowserMainExtraPartsPerformanceManager>());
1768 
      // Profiling(性能优化)相关的part
1769   main_parts->AddParts(
1770       std::make_unique<ChromeBrowserMainExtraPartsProfiling>());
1771 
       // 内存相关
1772   main_parts->AddParts(std::make_unique<ChromeBrowserMainExtraPartsMemory>());
       ......
1796 
1797   return main_parts;
1798 }
	

这个函数创建了ChromeBrowserMainPartsLinux这个main_parts, 又向这个main_parts 添加了多个extra_main_part. 下面给出MainParts 和ExtrasMainParts的数据结构。

chromium启动流程(一)-browser进程启动流程_第1张图片

ChromeBrowserMainPartsLinux 继承自ChromeBrowserMainPartsix,ChromeBrowserMainPartsPosix继承自ChromeBrowserParts, ChromeBrowserParts继承自BrowserMainParts。 ChromeBrowserParts的成员变量chrome_extra_parts_ 指向多个ChromeBrowserMainExtraParts。 BrowserMainParts实现了多个方法,在Chrom的启动周期调用,ChromeBrowserMainExtraParts也实现了这些方法,在调用BrowserMainParts这些方法的时候也会调用ChromeBrowserMainExtraParts的这些方法。我们后面会看到。

在BrowserMainParts定义的注释中给出了它的虚方法的调用时机,我们来看一下。
content/public/browser/browser_main_parts.h

// This class contains different "stages" to be executed by |BrowserMain()|.
//
// Stages:
//
//  ** Cross-platform startup stages.
//  ** Invoked during BrowserMainRunnerImpl::Initialize(), after
//     ContentMainRunner's full initialization.
//
//  - PreEarlyInitialization: things to be be done as soon as possible on
//    program start (such as setting up signal handlers; checking auto-restarts
//    on update; etc.). Core APIs like base::FeatureList,
//    base::SingleThreadTaskRunner::CurrentDefaultHandle, and base::ThreadPool
//    are already functional at this point (ThreadPool will accept but not run
//    tasks until PostCreateThreads).
//
//  - PostEarlyInitialization: things to be be done as soon as possible but that
//    can/must wait until after the few things in BrowserMainLoop's own
//    EarlyInitialization have completed.
//
//  - ToolkitInitialized: similar to PostEarlyInitialization but for the UI
//    toolkit. Allows an embedder to do any extra toolkit initialization.
//
//  - PreCreateMainMessageLoop: things to be done at some generic time before
//    the creation of the main message loop.
//
//  - PostCreateMainMessageLoop: things to be done as early as possible but that
//    need the main message loop to be around (i.e. BrowserThread::UI is up).
//
//  - PreCreateThreads: things that don't need to happen super early but still
//    need to happen during single-threaded initialization (e.g. immutable
//    Singletons that are initialized once and read-only from all threads
//    thereafter).
//    Note: other threads might exist before this point but no child threads
//    owned by content. As such, this is still "single-threaded" initialization
//    as far as content and its embedders are concerned and the right place to
//    initialize thread-compatible objects:
//    https://chromium.googlesource.com/chromium/src/+/main/docs/threading_and_tasks.md#threading-lexicon
//
//  - PostCreateThreads: things that should be done as early as possible but
//    need browser process threads to be alive (i.e. BrowserThread::IO is up and
//    base::ThreadPool is running tasks).
//
//  - PreMainMessageLoopRun: IN DOUBT, PUT THINGS HERE. At this stage all core
//    APIs have been initialized. Services that must be initialized before the
//    browser is considered functional can be initialized from here. Ideally
//    only the frontend is initialized here while the backend takes advantage of
//    a base::ThreadPool worker to come up asynchronously. Things that must
//    happen on the main thread eventually but don't need to block startup
//    should post a BEST_EFFORT task from this stage.
//
//  ** End of cross-platform startup stages.
//  ** Stages above are run as part of startup stages in
//  ** BrowserMainLoop::CreateStartupTasks() and can even be run eagerly (e.g.
//  ** Android app warmup attempts to run these async.
//
//  - WillRunMainMessageLoop: The main thread's RunLoop will be run
//    *immediately* upon returning from this method. While PreMainMessageLoopRun
//    gives that impression, in practice it's part of initialization phases
//    which are triggered independently from MainMessageLoopRun (and can even
//    happen async). In browser tests, PreMainMessageLoopRun() will run before
//    entering test bodies whereas WillRunMainMessageLoop() won't (the control
//    is given to the test rather running the loop). Furthermore, this is only
//    called on platforms where BrowserMainLoop::RunMainMessageLoop is called.
//    Thus, very few things should be done at this stage. It's mostly intended
//    as a way for embedders to override or cancel the default RunLoop if
//    needed.
//
//  - OnFirstIdle: The main thread reached idle for the first time since
//    WillRunMainMessageLoop(). In other words, it's done running any tasks
//    posted as part of the above phases and anything else posted from these.
//
//  - PostMainMessageLoopRun: stop and cleanup things that can/should be cleaned
//    up while base::ThreadPool and BrowserThread::IO are still running.
//    Note: Also see BrowserMainLoop::ShutdownThreadsAndCleanUp() which is often
//    a good fit to stop services (PostMainMessageLoopRun() is called from it).
//
//  - PostDestroyThreads: stop and cleanup things that need to be cleaned up in
//    the single-threaded teardown phase (i.e. typically things that had to
//    created in PreCreateThreads()).
//
//
// How to add stuff (to existing parts):
//  - Figure out when your new code should be executed. What must happen
//    before/after your code is executed? Are there performance reasons for
//    running your code at a particular time? Document these things!
//  - Split out any platform-specific bits. Please avoid #ifdefs it at all
//    possible. You have two choices for platform-specific code: (1) Execute it
//    from one of the |Pre/Post...()| methods in an embedder's platform-specific
//    override (e.g., ChromeBrowserMainPartsWin::PreCreateMainMessageLoop()); do
//    this if the code is unique to an embedder and platform type. Or (2)
//    execute it from one of the "stages" (e.g.,
//    |BrowserMainLoop::EarlyInitialization()|) and provide platform-specific
//    implementations of your code (in a virtual method); do this if you need to
//    provide different implementations across most/all platforms.
//  - Unless your new code is just one or two lines, put it into a separate
//    method with a well-defined purpose. (Likewise, if you're adding to an
//    existing chunk which makes it longer than one or two lines, please move
//    the code out into a separate method.)
//

总结一下:
**跨平台启动部分

  • PreEarlyInitialization: 尽早在程序启动时执行的任务(例如设置信号处理程序;检查更新时的自动重启等)。在此时,核心 API 如 base::FeatureList、base::SingleThreadTaskRunner::CurrentDefaultHandle 和 base::ThreadPool 已经可用(ThreadPool 会接受任务但不运行任务,直到 PostCreateThreads 阶段)。
  • PostEarlyInitialization: 尽早执行的任务,但必须等到 BrowserMainLoop 的 EarlyInitialization 阶段的一些任务完成后才能执行。
  • ToolkitInitialized: 类似于 PostEarlyInitialization,但用于 UI 工具包。允许嵌入程序执行任何额外的工具包初始化。
  • PreCreateMainMessageLoop: 在创建主消息循环之前的一些通用时机执行的任务。
  • PostCreateMainMessageLoop: 在尽早执行的任务,但需要主消息循环存在(即 BrowserThread::UI 已启动)。
  • PreCreateThreads: 不需要非常早执行的任务,但仍需要在单线程初始化期间执行的任务(例如,初始化一次且在此后所有线程中只读取的不可变单例)。注意:在此之前可能存在其他线程,但不包括 content 拥有的子线程。因此,就 content 及其嵌入者而言,这仍然是 “单线程” 初始化,也是初始化线程兼容对象的正确位置:https://chromium.googlesource.com/chromium/src/+/main/docs/threading_and_tasks.md#threading-lexicon
  • PostCreateThreads: 尽早执行的任务,但需要浏览器进程线程存在(即 BrowserThread::IO 已启动,base::ThreadPool 在运行任务)。
  • PreMainMessageLoopRun: 存在疑问时,请将任务放在这里。在此阶段,所有核心 API 都已初始化。必须在浏览器被视为可用之前初始化的服务可以从这里初始化。理想情况下,只有前端在此处初始化,而后端则利用 base::ThreadPool 的工作线程异步启动。必须最终在主线程上发生但不需要阻塞启动的任务应该从此阶段发布 BEST_EFFORT 任务。

**跨平台启动阶段结束。
**以上阶段作为 BrowserMainLoop::CreateStartupTasks() 启动阶段的一部分运行,甚至可以急切地运行(例如,Android 应用程序预热尝试异步运行这些阶段)。

  • WillRunMainMessageLoop: 从此方法返回后,主线程的 RunLoop 将立即运行。虽然 PreMainMessageLoopRun 给出了这种印象,但实际上它是初始化阶段的一部分,与 MainMessageLoopRun 触发的独立触发的(甚至可能是异步的)。在浏览器测试中,PreMainMessageLoopRun() 将在进入测试体之前运行,而 WillRunMainMessageLoop() 不会(控制权交给测试,而不是运行循环)。此外,仅在调用 BrowserMainLoop::RunMainMessageLoop 的平台上调用。因此,在这个阶段应该尽量少做事情。它主要用于嵌入者覆盖或取消默认的 RunLoop(如果需要的话)。

  • OnFirstIdle: 主线程自 WillRunMainMessageLoop() 以来首次达到空闲。换句话说,它已完成执行上述阶段和从中发布的任何其他任务。

  • PostMainMessageLoopRun: 在 base::ThreadPool 和 BrowserThread::IO 仍在运行时停止和清理可以/应该被清理的事物。注意:还请参阅 BrowserMainLoop::ShutdownThreadsAndCleanUp(),通常适用于停止服务(PostMainMessageLoopRun() 是从其中调用的)。

  • PostDestroyThreads: 在单线程拆卸阶段停止和清理需要在其中创建的事物(通常是在 PreCreateThreads() 中创建的事物)。

注释描写的很细致,生命周期也很细致,但是基于我们当前对chrome的了解,还不能详细说明, 请读者用到的时候再加以分析。

BrowserMainLoop 的parts_成员变量指向BrowserMainParts, BrowserMainLoop也提供对应的生命周期方法,它会调用到BrowserMainParts的对应方法。

我们以BrowserMainLoop::EarlyInitialization() 为例进行说明。
content/browser/browser_main_loop.cc

532 int BrowserMainLoop::EarlyInitialization() {
 533   TRACE_EVENT0("startup", "BrowserMainLoop::EarlyInitialization");
 534 
       ......
       // 调用BrowserMainParts->PreEarlyInitialization() 方法
 560   if (parts_) {
 561     const int pre_early_init_error_code = parts_->PreEarlyInitialization();
 562     if (pre_early_init_error_code != RESULT_CODE_NORMAL_EXIT)
 563       return pre_early_init_error_code;
 564   }
 565 
       ......
 571 
 572   // SetCurrentThreadType relies on CurrentUIThread on some platforms. The
 573   // MessagePumpForUI needs to be bound to the main thread by this point.
 574   DCHECK(base::CurrentUIThread::IsSet());
 575   base::PlatformThread::SetCurrentThreadType(base::ThreadType::kCompositing);
 576 
       ......
 617 
 618   if (parsed_command_line_->HasSwitch(switches::kRendererProcessLimit)) {
 619     std::string limit_string = parsed_command_line_->GetSwitchValueASCII(
 620         switches::kRendererProcessLimit);
 621     size_t process_limit;
 622     if (base::StringToSizeT(limit_string, &process_limit)) {
 623       RenderProcessHost::SetMaxRendererProcessCount(process_limit);
 624     }
 625   }
 626 
       // 调用BrowserMainParts->PostEarlyInitialization() 方法
 627   if (parts_)
 628     parts_->PostEarlyInitialization();
 629 
 630   return RESULT_CODE_NORMAL_EXIT;
 631 }

我们可以看到在BrowserMainLoop::EarlyInitialization()方法中分别调用了 BrowserMainParts的PreEarlyInitialization() 方法和PostEarlyInitialization() 方法。 由此可推断BrowserMainLoop的其他生命周期方法也会调用BrowserMainParts的其他生命周期方法,请读者自行验证。

我们分析在linux的实例parts_的相应方法。 ChromeBrowserMainPartsLinux 并没有实现PreEarlyInitialization方法,我们看它父类ChromeBrowserMainPartsPosix的实现。
chrome/browser/chrome_browser_main_posix.cc

int ChromeBrowserMainPartsPosix::PreEarlyInitialization() {
  const int result = ChromeBrowserMainParts::PreEarlyInitialization();
  if (result != content::RESULT_CODE_NORMAL_EXIT)
    return result;

  // We need to accept SIGCHLD, even though our handler is a no-op because
  // otherwise we cannot wait on children. (According to POSIX 2001.)
  struct sigaction action;
  memset(&action, 0, sizeof(action));
  action.sa_handler = SIGCHLDHandler;
  CHECK_EQ(0, sigaction(SIGCHLD, &action, nullptr));

  return content::RESULT_CODE_NORMAL_EXIT;
}

这里调用了父类ChromeBrowserMainParts的PreEarlyInitialization方法并设置了信号处理程序。 我们看ChromeBrowserMainParts->PreEarlyInitialization() 方法的实现。

729 int ChromeBrowserMainParts::PreEarlyInitialization() {
 730   TRACE_EVENT0("startup", "ChromeBrowserMainParts::PreEarlyInitialization");
 731   for (auto& chrome_extra_part : chrome_extra_parts_)
 732     chrome_extra_part->PreEarlyInitialization();
 733 
       ......
 776 
 777   return load_local_state_result;
 778 }

这里有调用了chrome_extra_parts_中的每个extra_part 的PreEarlyInitialization 方法。

关于ChromeBrowserMainParts的基本逻辑和调用流程我们分析完了。 回到BrowserMainRunnerImpl::Initialize() 函数中, 完成各个ChromeBrowserMainParts的初始化工作,就可以执行启动任务了, BrowserMainLoop::CreateStartupTasks() 函数正式这个作用, 创建启动任务。

 838 void BrowserMainLoop::CreateStartupTasks() {
 839   TRACE_EVENT0("startup", "BrowserMainLoop::CreateStartupTasks");
 840 
 841   DCHECK(!startup_task_runner_);
 842 #if BUILDFLAG(IS_ANDROID)
      ......
 851 #else
       // 创建StartupTaskRunner
 852   startup_task_runner_ = std::make_unique<StartupTaskRunner>(
 853       base::OnceCallback<void(int)>(),
 854       base::SingleThreadTaskRunner::GetCurrentDefault());
 855 #endif
 856   StartupTask pre_create_threads = base::BindOnce(
 857       &BrowserMainLoop::PreCreateThreads, base::Unretained(this));
       // 添加任务调用BrowserMainLoop::PreCreateThreads
 858   startup_task_runner_->AddTask(std::move(pre_create_threads));
 859 
 860   StartupTask create_threads =
 861       base::BindOnce(&BrowserMainLoop::CreateThreads, base::Unretained(this));
       // 添加任务调用BrowserMainLoop::CreateThreads
 862   startup_task_runner_->AddTask(std::move(create_threads));
 863 
 864   StartupTask post_create_threads = base::BindOnce(
 865       &BrowserMainLoop::PostCreateThreads, base::Unretained(this));
       // 添加任务调用BrowserMainLoop::PostCreateThreads
 866   startup_task_runner_->AddTask(std::move(post_create_threads));
 867 
 868   StartupTask pre_main_message_loop_run = base::BindOnce(
 869       &BrowserMainLoop::PreMainMessageLoopRun, base::Unretained(this));
       // 添加任务调用BrowserMainLoop::PreMainMessageLoopRun
 870   startup_task_runner_->AddTask(std::move(pre_main_message_loop_run));
 871 
      ......
 887 
 888 #if BUILDFLAG(IS_ANDROID)
         ......
 890 #else
 891   startup_task_runner_->RunAllTasksNow();
 892 #endif
 893 }

函数创建StartupTaskRunner结构,我们知道TaskRunner 一般用于投递任务,StartupTaskRunner也是如此,所以就不深分析StartupTaskRunner了, 它就是向当先线程投递任务。 在CreateStartupTasks函数中分别投递了PreCreateThreads、CreateThreads、PostCreateThreads、PreMainMessageLoopRun 四个函数。CreateStartupTasks函数891行调用startup_task_runner_->RunAllTasksNow()函数会依次调用上述四个函数。 从这四个函数名称还看是在创建线程过程中执行的操作,由于chromium 启动过程中初始化了太多的组件,我们无法依依去分析,所以只看一下CreateThreads了解下启动了哪些线程。
content/browser/startup_task_runner.cc

 919 int BrowserMainLoop::CreateThreads() {
 920   TRACE_EVENT0("startup,rail", "BrowserMainLoop::CreateThreads");
 921 
 922   // Release the ThreadPool's threads.
 923   scoped_execution_fence_.reset();
 924 
 925   // The |io_thread| can have optionally been injected into Init(), but if not,
 926   // create it here. Thre thread is only tagged as BrowserThread::IO here in
 927   // order to prevent any code from statically posting to it before
 928   // CreateThreads() (as such maintaining the invariant that PreCreateThreads()
 929   // et al. "happen-before" BrowserThread::IO is "brought up").
 930   if (!io_thread_) {
 931     io_thread_ = BrowserTaskExecutor::CreateIOThread();
 932   }
 933   io_thread_->RegisterAsBrowserThread();
 934   BrowserTaskExecutor::InitializeIOThread();
 935 
 936   // TODO(https://crbug.com/863341): Replace with a better API
 937   GetContentClient()->browser()->PostAfterStartupTask(
 938       FROM_HERE, base::SequencedTaskRunner::GetCurrentDefault(),
 939       base::BindOnce(
 940           [](BrowserMainLoop* browser_main_loop) {
 941             // Informs BrowserTaskExecutor that startup is complete.
 942             content::BrowserTaskExecutor::OnStartupComplete();
 943             browser_main_loop->scoped_best_effort_execution_fence_.reset();
 944           },
 945           // Main thread tasks can't run after BrowserMainLoop destruction.
 946           // Accessing an Unretained pointer to BrowserMainLoop from a main
 947           // thread task is therefore safe.
 948           base::Unretained(this)));
 949 
 950   created_threads_ = true;
 951   return result_code_;
 952 }

929-934行,将io_thread_注册为BrowserThread。 并初始化BrowserTaskExecutor的iothread, 我们在分析线程的时候已经知道BrowserTaskExecutor 管理浏览器的ui线程和io线程,这里初始化了io线程,ui线程则是浏览器进程的主线程,在作为初始化后会被设置为BrowserTaskExecutor的ui线程。

上面浏览器进程的启动大致流程我们已经分析了,但是我们只看到的进程启动框架,用户要想使用浏览器,必须要将ui展现在屏幕上,并且通过操作ui来执行网页访问,所以我们分析一下ui的初始化过程, 在这个过程中也能看到浏览器实例的创建。

Broswer实例创建

chrome/browser/chrome_browser_main.cc

int ChromeBrowserMainParts::PreMainMessageLoopRun() {
  TRACE_EVENT0("startup", "ChromeBrowserMainParts::PreMainMessageLoopRun");

  result_code_ = PreMainMessageLoopRunImpl();

  for (auto& chrome_extra_part : chrome_extra_parts_)
    chrome_extra_part->PreMainMessageLoopRun();

  return result_code_;
}

在PreMainMessageLoopRun 调用时,会调用ChromeBrowserMainParts::PreMainMessageLoopRun() 方法, 该方法会调用PreMainMessageLoopRunImpl() 方法。 PreMainMessageLoopRunImpl方法会启动浏览器实例。我们来具体分析。

// PreMainMessageLoopRun calls these extra stages in the following order:
//  PreMainMessageLoopRunImpl()
//   ... initial setup, including browser_process_ setup.
//   PreProfileInit()
//   ... additional setup, including CreateProfile()
//   PostProfileInit()
//   ... additional setup
//   PreBrowserStart()
//   ... browser_creator_->Start
//   PostBrowserStart()
1388 int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() {
      ......
1401 
1402   // Do any initializating in the browser process that requires all threads
1403   // running.
1404   browser_process_->PreMainMessageLoopRun();
1405 
1406   // Record last shutdown time into a histogram.
1407   browser_shutdown::ReadLastShutdownInfo();
1408 
      ......
 
1617   // Desktop construction occurs here, (required before profile creation).
1618   PreProfileInit();
1619 
        ......
1627   // This step is costly and is already measured in Startup.CreateFirstProfile
1628   // and more directly Profile.CreateAndInitializeProfile.
1629   StartupProfileInfo profile_info = CreateInitialProfile(
1630       /*cur_dir=*/base::FilePath(), *base::CommandLine::ForCurrentProcess());
1631   base::UmaHistogramEnumeration(
1632       "ProfilePicker.StartupMode.CreateInitialProfile", profile_info.mode);
1633 
1634   if (profile_info.mode == StartupProfileMode::kError)
1635     return content::RESULT_CODE_NORMAL_EXIT;
1636 
        ......
1685 
1686   // `profile` may be nullptr if the profile picker is shown.
1687   Profile* profile = profile_info.profile;
1688   // Call `PostProfileInit()`and set it up for profiles created later.
1689   profile_init_manager_ = std::make_unique<ProfileInitManager>(this, profile);
1690 
1691 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
1692   // Execute first run specific code after the PrefService has been initialized
1693   // and preferences have been registered since some of the import code depends
1694   // on preferences.
1695   if (first_run::IsChromeFirstRun()) {
1696     // `profile` may be nullptr even on first run, for example when the
1697     // "BrowserSignin" policy is set to "Force". If so, skip the auto import.
1698     if (profile) {
1699       first_run::AutoImport(profile, master_prefs_->import_bookmarks_path);
1700     }
1701 
1702     // Note: This can pop-up the first run consent dialog on Linux & Mac.
1703     first_run::DoPostImportTasks(master_prefs_->make_chrome_default_for_user);
1704 
1705     // The first run dialog is modal, and spins a RunLoop, which could receive
1706     // a SIGTERM, and call chrome::AttemptExit(). Exit cleanly in that case.
1707     if (browser_shutdown::IsTryingToQuit())
1708       return content::RESULT_CODE_NORMAL_EXIT;
1709   }
1710 #endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
1711 
      ......
     
1782   PreBrowserStart();
1783 
1784   variations::VariationsService* variations_service =
1785       browser_process_->variations_service();
1786   variations_service->PerformPreMainMessageLoopStartup();
1787 
       ......

1817       browser_creator_->Start(*base::CommandLine::ForCurrentProcess(),
1818                               base::FilePath(), profile_info,
1819                               last_opened_profiles);
       .......
1855 
1856   PostBrowserStart();
1857 
     ......
1869 
1870   return result_code_;
1871 }

函数的主题流程如下:

  • PreProfileInit(): 初始化profile
  • PostProfileInit() : profile 初始化后执行的操作
  • browser_creator_->Start() 启动浏览器
  • PreBrowserStart() 浏览器启动前工作

我们直接看浏览器的启动。
chrome/browser/ui/startup/startup_browser_creator.cc


bool StartupBrowserCreator::Start(const base::CommandLine& cmd_line,
                                  const base::FilePath& cur_dir,
                                  StartupProfileInfo profile_info,
                                  const Profiles& last_opened_profiles) {
  TRACE_EVENT0("startup", "StartupBrowserCreator::Start");
  SCOPED_UMA_HISTOGRAM_TIMER("Startup.StartupBrowserCreator_Start");
  return ProcessCmdLineImpl(cmd_line, cur_dir,
                            chrome::startup::IsProcessStartup::kYes,
                            profile_info, last_opened_profiles);
}

函数直接调用了ProcessCmdLineImpl函数。
chrome/browser/ui/startup/startup_browser_creator.cc

909 bool StartupBrowserCreator::ProcessCmdLineImpl(
 910     const base::CommandLine& command_line,
 911     const base::FilePath& cur_dir,
 912     chrome::startup::IsProcessStartup process_startup,
 913     StartupProfileInfo profile_info,
 914     const Profiles& last_opened_profiles) {
         ......
1260 
1261   // Launch the browser if the profile is unable to open web apps.
1262   if (!CanOpenWebApp(privacy_safe_profile)) {
         // 不能启动webapp则直接启动chrome浏览器主页
1263     LaunchBrowserForLastProfiles(command_line, cur_dir, process_startup,
1264                                  is_first_run, profile_info,
1265                                  last_opened_profiles);
1266     return true;
1267   }
1268 
1269   // Try a platform app launch.
       // 启动webapp
1270   if (MaybeLaunchExtensionApp(command_line, cur_dir, is_first_run,
1271                               privacy_safe_profile)) {
1272     return true;
1273   }
1274 
       ......
1296 
       //启动webapp失败,则直接启动chrome浏览器主页
1297   LaunchBrowserForLastProfiles(command_line, cur_dir, process_startup,
1298                                is_first_run, profile_info,
1299                                last_opened_profiles);
1300   return true;
1301 }
1302 

我们不关注webapp。所以直接看使用profiles启动浏览器的过程。
chrome/browser/ui/startup/startup_browser_creator.cc

1303 void StartupBrowserCreator::ProcessLastOpenedProfiles(
1304     const base::CommandLine& command_line,
1305     const base::FilePath& cur_dir,
1306     chrome::startup::IsProcessStartup process_startup,
1307     chrome::startup::IsFirstRun is_first_run,
1308     Profile* last_used_profile,
1309     const Profiles& last_opened_profiles) {
1310   base::CommandLine command_line_without_urls(command_line.GetProgram());
1311   for (auto& switch_pair : command_line.GetSwitches()) {
1312     command_line_without_urls.AppendSwitchNative(switch_pair.first,
1313                                                  switch_pair.second);
1314   }
1315 
1316   // Launch the profiles in the order they became active.
1317   for (Profile* profile : last_opened_profiles) {
1318     DCHECK(!profile->IsGuestSession());
1319 
          ......
1333 
1334     // Don't launch additional profiles which would only open a new tab
1335     // page. When restarting after an update, all profiles will reopen last
1336     // open pages.
1337     SessionStartupPref startup_pref =
1338         GetSessionStartupPref(command_line, profile);
1339     if (profile != last_used_profile &&
1340         startup_pref.type == SessionStartupPref::DEFAULT &&
1341         !HasPendingUncleanExit(profile)) {
1342       continue;
1343     }
1344     // Only record a launch mode histogram for |last_used_profile|. Pass a
1345     // null launch_mode_recorder for other profiles.
         // 为每个profile 启动一个浏览器实例。
1346     LaunchBrowser((profile == last_used_profile) ? command_line
1347                                                  : command_line_without_urls,
1348                   profile, cur_dir, process_startup, is_first_run,
1349                   profile == last_used_profile
1350                       ? std::make_unique<OldLaunchModeRecorder>()
1351                       : nullptr);
1352     // We've launched at least one browser.
1353     process_startup = chrome::startup::IsProcessStartup::kNo;
1354   }
1355 
      // 设置活跃的profile
1356 // Set the |last_used_profile| to activate if a browser is launched for at
1357 // least one profile. Otherwise, show UserManager.
1358 // Note that this must be done after all profiles have
1359 // been launched so the observer knows about all profiles to wait before
1360 // activation this one.
1361 #if !BUILDFLAG(IS_CHROMEOS_ASH)
1362   if (process_startup == chrome::startup::IsProcessStartup::kYes) {
1363     ProfilePicker::Show(ProfilePicker::Params::FromEntryPoint(
1364         ProfilePicker::EntryPoint::kOnStartup));
1365   } else  // NOLINT
1366 #endif
1367   {
1368     profile_launch_observer.Get().set_profile_to_activate(last_used_profile);
1369   }
1370 }

在chrome中,使用Profile 代表用户,关联一份用户数据,所以这里对每个Profile 启动一个浏览器实例,启动浏览器实例的函数为LaunchBrowser。 在所有浏览器实例都启动后,要求设置活跃profile,有两种方式,一种是直接设置最后使用的profile为活跃的,或者弹出弹框要求用户选择。 我们只关注浏览器实例的启动过程,所以继续分析LaunchBrowser函数。

652 void StartupBrowserCreator::LaunchBrowser(
 653     const base::CommandLine& command_line,
 654     Profile* profile,
 655     const base::FilePath& cur_dir,
 656     chrome::startup::IsProcessStartup process_startup,
 657     chrome::startup::IsFirstRun is_first_run,
 658     std::unique_ptr<OldLaunchModeRecorder> launch_mode_recorder) {
       .....

 686     StartupBrowserCreatorImpl lwp(cur_dir, command_line, this, is_first_run);
 687     lwp.Launch(profile,
 688                in_synchronous_profile_launch_
 689                    ? chrome::startup::IsProcessStartup::kYes
 690                    : chrome::startup::IsProcessStartup::kNo,
 691                std::move(launch_mode_recorder));
 692   }
 693   in_synchronous_profile_launch_ = false;
 694   profile_launch_observer.Get().AddLaunched(profile);
 695 }

686 行创建StartupBrowserCreatorImpl 函数门用于启动单profile对应的Browser。 687-692行调用StartupBrowserCreatorImpl->launch方法启动浏览器.
chrome/browser/ui/startup/startup_browser_creator_impl.cc

182 void StartupBrowserCreatorImpl::Launch(
183     Profile* profile,
184     chrome::startup::IsProcessStartup process_startup,
185     std::unique_ptr<OldLaunchModeRecorder> launch_mode_recorder) {
186   DCHECK(profile);
187   profile_ = profile;
188 
189   LaunchResult launch_result = DetermineURLsAndLaunch(process_startup);
      ......
224 }

函数调用DetermineURLsAndLaunch 启动浏览器。

53 StartupBrowserCreatorImpl::LaunchResult
354 StartupBrowserCreatorImpl::DetermineURLsAndLaunch(
355     chrome::startup::IsProcessStartup process_startup) {
      ......

      // 确定要启动的tab
422   auto result = DetermineStartupTabs(
423       StartupTabProviderImpl(), process_startup, is_incognito_or_guest,
424       is_post_crash_launch, has_incompatible_applications,
425       promotional_tabs_enabled, welcome_enabled, whats_new_enabled,
426       privacy_sandbox_dialog_required);
427   StartupTabs tabs = std::move(result.tabs);
428 
      .......
      // 启动浏览器,并开tabs
463   Browser* browser = RestoreOrCreateBrowser(
464       tabs, behavior, restore_options, process_startup, is_post_crash_launch);
465 
      ......
469   return result.launch_result;
470 }

422-478行决定打开哪些tabs, 如果参数里面没有url默认情况只打开一个主tab, 如果启动参数里面有一个url或者从崩溃中恢复,可以打开多个tab。我们日常使用chrome是这样的,所以DetermineURLsAndLaunch就不用分析了。 这里主要分析RestoreOrCreateBrowser函数。

653 Browser* StartupBrowserCreatorImpl::RestoreOrCreateBrowser(
654     const StartupTabs& tabs,
655     BrowserOpenBehavior behavior,
656     SessionRestore::BehaviorBitmask restore_options,
657     chrome::startup::IsProcessStartup process_startup,
658     bool is_post_crash_launch) {
659   Browser* browser = nullptr;
      ......
683   browser = OpenTabsInBrowser(
684       browser, process_startup,
685       (tabs.empty()
686            ? StartupTabs({StartupTab(GURL(chrome::kChromeUINewTabURL))})
687            : tabs));
688 
       ......
697   return browser;
698 }

683-659行启动浏览器并打开tabs。

35 Browser* StartupBrowserCreatorImpl::OpenTabsInBrowser(
236     Browser* browser,
237     chrome::startup::IsProcessStartup process_startup,
238     const StartupTabs& tabs) {
239   DCHECK(!tabs.empty());
240 
      ......
246 
247   if (!browser || !browser->is_type_normal()) {
        ......
        // 准备创建参数
256     // Startup browsers are not counted as being created by a user_gesture
257     // because of historical accident, even though the startup browser was
258     // created in response to the user clicking on chrome. There was an
259     // incomplete check on whether a user gesture created a window which looked
260     // at the state of the MessageLoop.
261     Browser::CreateParams params = Browser::CreateParams(profile_, false);
262     params.creation_source = Browser::CreationSource::kStartupCreator;
263 #if BUILDFLAG(IS_LINUX)
264     params.startup_id =
265         command_line_->GetSwitchValueASCII("desktop-startup-id");
266 #endif
267     if (command_line_->HasSwitch(switches::kWindowName)) {
268       params.user_title =
269           command_line_->GetSwitchValueASCII(switches::kWindowName);
270     }
271 
        // 创建浏览器实例
272     browser = Browser::Create(params);
273   }
274 
275   bool first_tab = true;
276   custom_handlers::ProtocolHandlerRegistry* registry =
277       profile_ ? ProtocolHandlerRegistryFactory::GetForBrowserContext(profile_)
278                : nullptr;
279   for (auto& tab : tabs) {
        .......
        // 准备启动tab参数
306     NavigateParams params(browser, tab.url, ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
307     params.disposition = first_tab ? WindowOpenDisposition::NEW_FOREGROUND_TAB
308                                    : WindowOpenDisposition::NEW_BACKGROUND_TAB;
309     params.tabstrip_add_types = add_types;
        ......
        // 导航到tab
319     Navigate(&params);
320     first_tab = false;
321   }
       // 设置活跃tab
322   if (!browser->tab_strip_model()->GetActiveWebContents()) {
323     // TODO(sky): this is a work around for 110909. Figure out why it's needed.
324     if (!browser->tab_strip_model()->count())
325       chrome::AddTabAt(browser, GURL(), -1, true);
326     else
327       browser->tab_strip_model()->ActivateTabAt(0);
328   }
329 
      .....
      // 显示window
348   browser->window()->Show();
349 
350   return browser;
351 }

247-273行准备browser创建的参数, 并创建browser。
279-321行 通过Navigate创建tab。
348行 一切准备就绪,显示浏览器页面。

我们先来浏览器实例的创建,导航的过程会比较复杂,也是浏览器的核心功能,会单独分析。
chrome/browser/ui/browser.cc

// static
Browser* Browser::Create(const CreateParams& params) {
 ......
  return new Browser(params);
}

函数只是创建了Browser 实例。

 458 Browser::Browser(const CreateParams& params)
 459     : create_params_(params),
 460       type_(params.type),
 461       profile_(params.profile),
 462       window_(nullptr),
 463       tab_strip_model_delegate_(
 464           std::make_unique<chrome::BrowserTabStripModelDelegate>(this)),
           // tab标签模型
 465       tab_strip_model_(std::make_unique<TabStripModel>(
 466           tab_strip_model_delegate_.get(),
 467           params.profile,
 468           params.are_tab_groups_enabled ? TabGroupModelFactory::GetInstance()
 469                                         : nullptr)),
           // tab menu 模型
 470       tab_menu_model_delegate_(
 471           std::make_unique<chrome::BrowserTabMenuModelDelegate>(this)),
 472       app_name_(params.app_name),
 473       is_trusted_source_(params.trusted_source),
 474       session_id_(SessionID::NewUnique()),
 475       omit_from_session_restore_(params.omit_from_session_restore),
 476       should_trigger_session_restore_(params.should_trigger_session_restore),
 477       cancel_download_confirmation_state_(NOT_PROMPTED),
 478       override_bounds_(params.initial_bounds),
 479       initial_show_state_(params.initial_show_state),
 480       initial_workspace_(params.initial_workspace),
 481       initial_visible_on_all_workspaces_state_(
 482           params.initial_visible_on_all_workspaces_state),
 483       creation_source_(params.creation_source),
 484       unload_controller_(this),
 485       content_setting_bubble_model_delegate_(
 486           new BrowserContentSettingBubbleModelDelegate(this)),
 487       location_bar_model_delegate_(new BrowserLocationBarModelDelegate(this)),
 488       live_tab_context_(new BrowserLiveTabContext(this)),
 489       synced_window_delegate_(new BrowserSyncedWindowDelegate(this)),
 490       app_controller_(web_app::MaybeCreateAppBrowserController(this)),
 491       bookmark_bar_state_(BookmarkBar::HIDDEN),
 492       command_controller_(new chrome::BrowserCommandController(this)),
 493       window_has_shown_(false),
 494       user_title_(params.user_title),
 495       signin_view_controller_(this),
 496       breadcrumb_manager_browser_agent_(
 497           breadcrumbs::IsEnabled()
 498               ? std::make_unique<BreadcrumbManagerBrowserAgent>(this)
 499               : nullptr)
 500 #if BUILDFLAG(ENABLE_EXTENSIONS)
 501       ,
 502       extension_browser_window_helper_(
 503           std::make_unique<extensions::ExtensionBrowserWindowHelper>(this))
 504 #endif
 505 {
 506   if (!profile_->IsOffTheRecord()) {
 507     profile_keep_alive_ = std::make_unique<ScopedProfileKeepAlive>(
 508         params.profile->GetOriginalProfile(),
 509         ProfileKeepAliveOrigin::kBrowserWindow);
 510   }
 511 
 512   tab_strip_model_->AddObserver(this);
 513 
       // 导航栏模型
 514   location_bar_model_ = std::make_unique<LocationBarModelImpl>(
 515       location_bar_model_delegate_.get(), content::kMaxURLDisplayChars);
       .......
       // 书签状态
 533   UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_INIT);
 534 
 535   ProfileMetrics::LogProfileLaunch(profile_);
 536 
 537   if (params.skip_window_init_for_testing)
 538     return;
 539 
       // 创建浏览器窗口
 540   window_ = params.window ? params.window.get()
 541                           : CreateBrowserWindow(std::unique_ptr<Browser>(this),
 542                                                 params.user_gesture,
 543                                                 params.in_tab_dragging);
 544 
       ......
 552   SessionServiceBase* service =
 553       GetAppropriateSessionServiceForSessionRestore(this);
 554 
 555   if (service)
 556     service->WindowOpened(this);
 557 
       .....
       // 添加到浏览器列表。(可以打开多个窗口)
 567   BrowserList::AddBrowser(this);
 568 }

函数初始化了tab标签模型、menu模型、导航栏模型、和书签条。 并在540-544行创建浏览器窗口。 我们接下来分析窗口的创建。
chrome/browser/ui/browser.cc

BrowserWindow* CreateBrowserWindow(std::unique_ptr<Browser> browser,
                                   bool user_gesture,
                                   bool in_tab_dragging) {
  return BrowserWindow::CreateBrowserWindow(std::move(browser), user_gesture,
                                            in_tab_dragging);
}																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																					

函数调用CreateBrowserWindow创建BrowserWindow。
chrome/browser/ui/views/frame/browser_window_factory.cc

35 // static
 36 BrowserWindow* BrowserWindow::CreateBrowserWindow(
 37     std::unique_ptr<Browser> browser,
 38     bool user_gesture,
 39     bool in_tab_dragging) {
      ......
 47   // Create the view and the frame. The frame will attach itself via the view
 48   // so we don't need to do anything with the pointer.
 49   BrowserView* view = new BrowserView(std::move(browser));
 50   BrowserFrame* browser_frame = nullptr;
       ......
 58   if (!browser_frame)
 59     browser_frame = new BrowserFrame(view);
 60   if (in_tab_dragging)
 61     browser_frame->SetTabDragKind(TabDragKind::kAllTabs);
 62   browser_frame->InitBrowserFrame();
 63 
      ......
 86 
 87   return view;
 88 }

函数49行创建BrowserView, BrowserView 用于描述供浏览器窗口的内容,包括标签栏(TabStrip)、工具栏、下载架(download shelves)、内容区域等。50-59行创建BrowserFrame,BrowserFrame是真正负责ui管理的类。

我们先看BrowserView的创建。

796 BrowserView::BrowserView(std::unique_ptr<Browser> browser)
 797     : views::ClientView(nullptr, nullptr),
 798       browser_(std::move(browser)),
 799       accessibility_mode_observer_(
 800           std::make_unique<AccessibilityModeObserver>(this)) {
       // 设置显示的icon
 801   SetShowIcon(
 802       ::ShouldShowWindowIcon(browser_.get(), AppUsesWindowControlsOverlay()));
 803 
      ......
       // 创建顶部容器view
 865   top_container_ = AddChildView(std::make_unique<TopContainerView>(this));
 866 
       .....
       // 向顶部容器增加tab栏view
 876   tab_strip_region_view_ = top_container_->AddChildView(
 877       std::make_unique<TabStripRegionView>(std::move(tabstrip)));
 878 
 879   ColorProviderBrowserHelper::CreateForBrowser(browser_.get());
 880 
       // 设置开发者调试窗口
 881   // Create WebViews early so |webui_tab_strip_| can observe their size.
 882   auto devtools_web_view =
 883       std::make_unique<views::WebView>(browser_->profile());
 884   devtools_web_view->SetID(VIEW_ID_DEV_TOOLS_DOCKED);
 885   devtools_web_view->SetVisible(false);
 886 
      // 创建网页内容窗口
887   auto contents_web_view =
 888       std::make_unique<ContentsWebView>(browser_->profile());
 889   contents_web_view->SetID(VIEW_ID_TAB_CONTAINER);
 890 
       // 调试窗口添加到内容窗口中
 891   auto contents_container = std::make_unique<views::View>();
 892   devtools_web_view_ =
 893       contents_container->AddChildView(std::move(devtools_web_view));
        // 添加网页内容窗口到内容窗口
 894   contents_web_view_ =
 895       contents_container->AddChildView(std::move(contents_web_view));
 896   contents_web_view_->set_is_primary_web_contents_for_window(true);
       // 设置布局管理器
 897   contents_container->SetLayoutManager(std::make_unique<ContentsLayoutManager>(
 898       devtools_web_view_, contents_web_view_));
 899 
       // 添加工具栏到顶部窗口
 900   toolbar_ = top_container_->AddChildView(
 901       std::make_unique<ToolbarView>(browser_.get(), this));
 902 
       // 添加内容分割线,用于分割顶部栏和内容栏
 903   contents_separator_ =
 904       top_container_->AddChildView(std::make_unique<ContentsSeparator>());
 905 
 906   web_contents_close_handler_ =
 907       std::make_unique<WebContentsCloseHandler>(contents_web_view_);
 908 
       // 添加内容容器到当前顶部布局
 909   contents_container_ = AddChildView(std::move(contents_container));
 910   set_contents_view(contents_container_);
 911 
       // 添加分割线
 912   right_aligned_side_panel_separator_ =
 913       AddChildView(std::make_unique<ContentsSeparator>());
 914 
 915   const bool is_right_aligned = GetProfile()->GetPrefs()->GetBoolean(
      ......
 954 }

BrowserView的构造主要初始化窗口内容和布局。

我们再看BrowserFrame的 构造。
chrome/browser/ui/views/frame/browser_frame.cc

BrowserFrame::BrowserFrame(BrowserView* browser_view)
    : native_browser_frame_(nullptr),
      root_view_(nullptr),
      browser_frame_view_(nullptr),
      browser_view_(browser_view) {
  browser_view_->set_frame(this);
  set_is_secondary_widget(false);
  // Don't focus anything on creation, selecting a tab will set the focus.
  set_focus_on_creation(false);
}

非常简单。 再来看一下BrowserFrame的初始化,InitBrowserFrame函数。
chrome/browser/ui/views/frame/browser_view.h

 91 void BrowserFrame::InitBrowserFrame() {
 92   native_browser_frame_ =
 93       NativeBrowserFrameFactory::CreateNativeBrowserFrame(this, browser_view_);
 94   views::Widget::InitParams params = native_browser_frame_->GetWidgetParams();
 95   params.name = "BrowserFrame";
 96   params.delegate = browser_view_;
 97   params.headless_mode = headless::IsHeadlessMode();
 98 
      .....
139 
140   Init(std::move(params));
141   SelectNativeTheme();
142 
143   if (!native_browser_frame_->UsesNativeSystemMenu()) {
144     DCHECK(non_client_view());
145     non_client_view()->set_context_menu_controller(this);
146   }
147 }

函数创建NativeBrowserFrame,也就是和本地平台相关的Frame。然后调用Init函数进行初始化。 141行选择本地主题。 143-146行 设置menu。NativeBrowserFrame 实际上创建的是 DesktopBrowserFrameAuraLinux。我们直接看初始化过程Init。Widget 是NativeBrowserFrame的父类, Init函数是Widget实现的。

 345 void Widget::Init(InitParams params) {
       // 创建根View
 434   root_view_.reset(CreateRootView());
 435 
 436   // Copy the elements of params that will be used after it is moved.
 437   const InitParams::Type type = params.type;
 438   const gfx::Rect bounds = params.bounds;
 439   const ui::WindowShowState show_state = params.show_state;
 440   WidgetDelegate* delegate = params.delegate;
 441   
       // 初始化Widget
 442   native_widget_->InitNativeWidget(std::move(params));
 443   if (type == InitParams::TYPE_MENU)
 444     is_mouse_button_pressed_ = native_widget_->IsMouseButtonDown();
 445   if (RequiresNonClientView(type)) {
         // 设置内容视图
 446     non_client_view_ =
 447         new NonClientView(widget_delegate_->CreateClientView(this));
 448     non_client_view_->SetFrameView(CreateNonClientFrameView());
 449     non_client_view_->SetOverlayView(widget_delegate_->CreateOverlayView());
 450 
 451     // Bypass the Layout() that happens in Widget::SetContentsView(). Layout()
 452     // will occur after setting the initial bounds below. The RootView's size is
 453     // not valid until that happens.
 454     root_view_->SetContentsView(non_client_view_);
 455 
 456     // Initialize the window's icon and title before setting the window's
 457     // initial bounds; the frame view's preferred height may depend on the
 458     // presence of an icon or a title.
         // 更新icon、title等
 459     UpdateWindowIcon();
 460     UpdateWindowTitle();
 461     non_client_view_->ResetWindowControls();
 462     SetInitialBounds(bounds);
 463 
 464     // Perform the initial layout. This handles the case where the size might
 465     // not actually change when setting the initial bounds. If it did, child
 466     // views won't have a dirty Layout state, so won't do any work.
         // 执行布局
 467     root_view_->Layout();
 468 
 469     if (show_state == ui::SHOW_STATE_MAXIMIZED) {
 470       Maximize();
 471     } else if (show_state == ui::SHOW_STATE_MINIMIZED) {
 472       Minimize();
 473       saved_show_state_ = ui::SHOW_STATE_MINIMIZED;
 474     }
 475   } else if (delegate) {
 476     SetContentsView(delegate->TransferOwnershipOfContentsView());
 477     SetInitialBoundsForFramelessWindow(bounds);
 478   }
 479 
       ......
 494 }

函数创建RootView, 初始化widget, 并设置内容视图, 然后更新icon和ttitle。 最后执行布局。
我们先看RootView的创建。

internal::RootView* Widget::CreateRootView() {
  return new internal::RootView(this);
}
RootView::RootView(Widget* widget)
    : widget_(widget),
      pre_dispatch_handler_(
          std::make_unique<internal::PreEventDispatchHandler>(this)),
      post_dispatch_handler_(
          std::make_unique<internal::PostEventDispatchHandler>()) {
  AddPostTargetHandler(post_dispatch_handler_.get());
  SetEventTargeter(
      std::unique_ptr<ViewTargeter>(new RootViewTargeter(this, this)));
}

函数实现比较简单。 不不要展开分析。 再来看看Widget的初始化. native_widget_ 指向DesktopBrowserFrameAuraLinux, DesktopBrowserFrameAuraLinux的父类是DesktopBrowserFrameAura, DesktopBrowserFrameAura 实现了InitNativeWidget。 我们来看一下它的实现。
chrome/browser/ui/views/frame/desktop_browser_frame_aura.cc

548 
 549 // DesktopNativeWidgetAura, internal::NativeWidgetPrivate implementation:
 550 void DesktopNativeWidgetAura::InitNativeWidget(Widget::InitParams params) {
 551   ownership_ = params.ownership;
 552   widget_type_ = params.type;
 553   name_ = params.name;
 554 
       ......

       // 初始化桌面窗口树
 576   desktop_window_tree_host_->Init(params);
 577 
       // 增加子Window
 578   host_->window()->AddChild(content_window_);
 579   host_->window()->SetProperty(kDesktopNativeWidgetAuraKey, this);
 580 
 581   host_->window()->AddObserver(new RootWindowDestructionObserver(this));
 582 
      ......
 626 
 627   host_->window()->SetName(params.name);
 628   content_window_->SetName("DesktopNativeWidgetAura - content window");
 629   desktop_window_tree_host_->OnNativeWidgetCreated(params);
 630 
       ......
       // 事件处理
 683   event_client_ = std::make_unique<DesktopEventClient>();
 684   aura::client::SetEventClient(host_->window(), event_client_.get());
 685 
 686   shadow_controller_ = std::make_unique<wm::ShadowController>(
 687       wm::GetActivationClient(host_->window()), nullptr);
 688 
 689   OnSizeConstraintsChanged();
 690 
 691   window_reorderer_ = std::make_unique<WindowReorderer>(
 692       content_window_, GetWidget()->GetRootView());
 693 }

576行初始化桌面window 树。 578行将内容串口添加到window树中 683 创建事件处理相关结构。
我们继续看desktop_window_tree_host_的初始化。desktop_window_tree_host_是BrowserDesktopWindowTreeHostLinux的实例子。
chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.cc

void BrowserDesktopWindowTreeHostLinux::Init(
    const views::Widget::InitParams& params) {
  DesktopWindowTreeHostLinux::Init(std::move(params));
......
}

它调用了父类DesktopWindowTreeHostLinux的Init方法

void DesktopWindowTreeHostLinux::Init(const Widget::InitParams& params) {
  DesktopWindowTreeHostPlatform::Init(params);
 ......
}

DesktopWindowTreeHostLinux又调用了父类DesktopWindowTreeHostPlatform的Init方法。
ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc

  258 void DesktopWindowTreeHostPlatform::Init(const Widget::InitParams& params) {
       .....
 293 
       // 创建平台window
 294   CreateAndSetPlatformWindow(std::move(properties));
 295 
 296   // Disable compositing on tooltips as a workaround for
 297   // https://crbug.com/442111.
       // 创建合成器
 298   CreateCompositor(params.force_software_compositing ||
 299                    params.type == Widget::InitParams::TYPE_TOOLTIP);
 300 
 301   WindowTreeHost::OnAcceleratedWidgetAvailable();
       // 初始化
 302   InitHost();
       // 显示widnow
 303   window()->Show();
 304 }

我们看一下平台窗口的创建。最终图像都要渲染在平台窗口。
ui/aura/window_tree_host_platform.cc

void WindowTreeHostPlatform::CreateAndSetPlatformWindow(
    ui::PlatformWindowInitProperties properties) {
  // Cache initial size used to create |platform_window_| so that it does not
  // end up propagating unneeded bounds change event when it is first notified
  // through OnBoundsChanged, which may lead to unneeded re-layouts, etc.
  size_in_pixels_ = properties.bounds.size();
#if BUILDFLAG(IS_OZONE)
  platform_window_ = ui::OzonePlatform::GetInstance()->CreatePlatformWindow(
      this, std::move(properties));
......
}

Ozone 是chrome用于实现gui的库, 它抽象了各平台gui管理给上层使用。在linux平台上OzonePlatform为OzonePlatformX11。
ui/ozone/platform/x11/ozone_platform_x11.cc

  std::unique_ptr<PlatformWindow> CreatePlatformWindow(
      PlatformWindowDelegate* delegate,
      PlatformWindowInitProperties properties) override {
    auto window = std::make_unique<X11Window>(delegate);
    window->Initialize(std::move(properties));
    return std::move(window);
  }

这里创建了X11Window,并执行了初始化, 我们先来看下X11Window的创建。
ui/ozone/platform/x11/x11_window.cc

X11Window::X11Window(PlatformWindowDelegate* platform_window_delegate)
    : platform_window_delegate_(platform_window_delegate),
      connection_(x11::Connection::Get()),
      x_root_window_(GetX11RootWindow()) {
    ......
}

再来看一下X11Window的初始化过程我们就不深入分析了,它主要请求创建X-Server创建window。
好了我们下面看一下怎么通过layout 更新布局
ui/views/view.cc

void View::Layout() {
  needs_layout_ = false;

  // If we have a layout manager, let it handle the layout for us.
  if (HasLayoutManager())
    GetLayoutManager()->Layout(this);

  // Make sure to propagate the Layout() call to any children that haven't
  // received it yet through the layout manager and need to be laid out. This
  // is needed for the case when the child requires a layout but its bounds
  // weren't changed by the layout manager. If there is no layout manager, we
  // just propagate the Layout() call down the hierarchy, so whoever receives
  // the call can take appropriate action.
  internal::ScopedChildrenLock lock(this);
  for (auto* child : children_) {
    if (child->needs_layout_ || !HasLayoutManager()) {
      TRACE_EVENT1("views", "View::LayoutChildren", "class",
                   child->GetClassName());
      child->needs_layout_ = false;
      child->Layout();
    }
  }
}

函数比较简单,先调用LyoutManager->Layout() 方法,再调用每一个子View的Layout方法, layout方法主要确定view的大小位置,这里就不具体分析了。 我们继续看view是怎么绘制的。 回到StartupBrowserCreatorImpl::OpenTabsInBrowser()函数,最后一行是调用browser->window()->Show();
chrome/browser/ui/views/frame/browser_view.cc

1226 void BrowserView::Show() {
       ......
1248   frame_->Show();
1249 
1250   browser()->OnWindowDidShow();
1251 
       ......
1268 }

这里调用了frame->Show() 方法。
ui/views/widget/widget.cc

795 void Widget::Show() {
 796   if (!native_widget_)
 797     return;
 798   const ui::Layer* layer = GetLayer();
 799   TRACE_EVENT1("views", "Widget::Show", "layer",
 800                layer ? layer->name() : "none");
 801   ui::WindowShowState preferred_show_state =
 802       CanActivate() ? ui::SHOW_STATE_NORMAL : ui::SHOW_STATE_INACTIVE;
 803   if (non_client_view_) {
 804     // While initializing, the kiosk mode will go to full screen before the
 805     // widget gets shown. In that case we stay in full screen mode, regardless
 806     // of the |saved_show_state_| member.
 807     if (saved_show_state_ == ui::SHOW_STATE_MAXIMIZED &&
 808         !initial_restored_bounds_.IsEmpty() && !IsFullscreen()) {
              .....
 810     } else {
 811       native_widget_->Show(
 812           IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN : saved_show_state_,
 813           gfx::Rect());
 814     }
 815     // |saved_show_state_| only applies the first time the window is shown.
 816     // If we don't reset the value the window may be shown maximized every time
 817     // it is subsequently shown after being hidden.
 818     saved_show_state_ = preferred_show_state;
 819   } else {
 820     native_widget_->Show(preferred_show_state, gfx::Rect());
 821   }
 822 
 823   HandleShowRequested();
 824 }

函数调用native_widget_->Show方法去显示页面.
ui/views/widget/desktop_aura/desktop_native_widget_aura.cc

void DesktopNativeWidgetAura::Show(ui::WindowShowState show_state,
                                   const gfx::Rect& restore_bounds) {
  if (!desktop_window_tree_host_)
    return;

  desktop_window_tree_host_->Show(show_state, restore_bounds);
}

native_widget_->Show 方法调用desktop_window_tree_host_->Show 方法。desktop_window_tree_host_类型为BrowserDesktopWindowTreeHostLinux, Show方法如下:
chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.cc

void BrowserDesktopWindowTreeHostLinux::Show(ui::WindowShowState show_state,
                                             const gfx::Rect& restore_bounds) {
  DesktopWindowTreeHostLinux::Show(show_state, restore_bounds);

  ......
}

函数调用父类DesktopWindowTreeHostLinux::Show 方法。
ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc

413 void DesktopWindowTreeHostPlatform::Show(ui::WindowShowState show_state,
 414                                          const gfx::Rect& restore_bounds) {
 415   if (compositor())
 416     SetVisible(true);
 417 
       // 请求x-server 显示window
 418   platform_window()->Show(DetermineInactivity(show_state));
 419 
       ......
 439   if (native_widget_delegate_->CanActivate()) {
 440     if (show_state != ui::SHOW_STATE_INACTIVE)
           // 激活窗口
 441       Activate();
 442 
 443     // SetInitialFocus() should be always be called, even for
 444     // SHOW_STATE_INACTIVE. If the window has to stay inactive, the method will
 445     // do the right thing.
 446     // Activate() might fail if the window is non-activatable. In this case, we
 447     // should pass SHOW_STATE_INACTIVE to SetInitialFocus() to stop the initial
 448     // focused view from getting focused. See https://crbug.com/515594 for
 449     // example.
 450     native_widget_delegate_->SetInitialFocus(
 451         IsActive() ? show_state : ui::SHOW_STATE_INACTIVE);
 452   }
 453 
       // 显示内容
 454   GetContentWindow()->Show();
 455 }

函数先请求x-server 显示窗口,然后激活窗口, 最后调用GetContentWindow()->Show() 绘制窗口内容。
ui/aura/window.cc

void Window::Show() {
   ......
  SetVisibleInternal(true);
}

Window::Show 方法调用SetVisibleInternal

 985 void Window::SetVisibleInternal(bool visible) {
       ......
       // 请求绘制
1001   SchedulePaint();
       ......
1009 }

函数调用SchedulePaint() 请求绘制

void Window::SchedulePaint() {
  SchedulePaintInRect(gfx::Rect(0, 0, bounds().width(), bounds().height()));
}

void Window::SchedulePaintInRect(const gfx::Rect& rect) {
  layer()->SchedulePaint(rect);
}

函数调用layer()->SchedulePaint() 方法完成绘制。我们查看SchedulePaint方法。
ui/compositor/layer.cc

bool Layer::SchedulePaint(const gfx::Rect& invalid_rect) {
   .....
  if (!content_layer_ || !deferred_paint_requests_)
    ScheduleDraw();
  return true;
}

如果需要绘制,调用ScheduleDraw 方法

void Layer::ScheduleDraw() {
  // Do not schedule draw if this layer does not contribute the content.
  if (type_ == LAYER_NOT_DRAWN && children_.size() == 0) {
    return;
  }
  Compositor* compositor = GetCompositor();
  if (compositor) {
    compositor->ScheduleDraw();
  }
}

调用compositor->ScheduleDraw() 进行绘制。

void Compositor::ScheduleDraw() {
  host_->SetNeedsCommit();
}
void LayerTreeHost::SetNeedsCommit() {
  DCHECK(IsMainThread());
  proxy_->SetNeedsCommit();
......
}

void SingleThreadProxy::SetNeedsCommit() {
  DCHECK(task_runner_provider_->IsMainThread());
   ......
  if (scheduler_on_impl_thread_)
    scheduler_on_impl_thread_->SetNeedsBeginMainFrame();
}
void Scheduler::SetNeedsBeginMainFrame() {
  state_machine_.SetNeedsBeginMainFrame();
  ProcessScheduledActions();
}

函数最终调用到Scheduler::SetNeedsBeginMainFrame() 方法,设置了状态机状态, 然后调用ProcessScheduledActions()处理新状态。
Scheduler类是ui渲染的调度器。
关于schedule 调度器比较复杂,这里不进行深入分析。

void Scheduler::ProcessScheduledActions() {
  ......
  do {
    action = state_machine_.NextAction();
    TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
                "SchedulerStateMachine", [this](perfetto::EventContext ctx) {
                  this->AsProtozeroInto(ctx,
                                        ctx.event()->set_cc_scheduler_state());
                });
    base::AutoReset<SchedulerStateMachine::Action> mark_inside_action(
        &inside_action_, action);
    switch (action) {
      case SchedulerStateMachine::Action::NONE:
        break;
      case SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME:
        compositor_timing_history_->WillBeginMainFrame(begin_main_frame_args_);
        compositor_frame_reporting_controller_->WillBeginMainFrame(
            begin_main_frame_args_);
        state_machine_.WillSendBeginMainFrame();
        client_->ScheduledActionSendBeginMainFrame(begin_main_frame_args_);
        last_dispatched_begin_main_frame_args_ = begin_main_frame_args_;
        break;
      case SchedulerStateMachine::Action::
       
......
}

SEND_BEGIN_MAIN_FRAME 这个action 用于请求新的一帧绘制,client_->ScheduledActionSendBeginMainFrame(begin_main_frame_args_) 函数调度绘制。
cc/trees/single_thread_proxy.cc

 965 void SingleThreadProxy::ScheduledActionSendBeginMainFrame(
 966     const viz::BeginFrameArgs& begin_frame_args) {
 967   DebugScopedSetImplThread impl(task_runner_provider_);
      ......
 980 
 981   host_impl_->WillSendBeginMainFrame();
 982   task_runner_provider_->MainThreadTaskRunner()->PostTask(
 983       FROM_HERE, base::BindOnce(&SingleThreadProxy::BeginMainFrame,
 984                                 weak_factory_.GetWeakPtr(), begin_frame_args));
 985   host_impl_->DidSendBeginMainFrame(begin_frame_args);
 986 }

异步调用BeginMainFrame

1010 void SingleThreadProxy::BeginMainFrame(
       ......
       // 新的一帧开始之前的准备工作
1062   DoBeginMainFrame(begin_frame_args);
1063 
1064   // New commits requested inside UpdateLayers should be respected.
1065   commit_requested_ = false;
1066 
      .....
      // 执行绘制
1081   DoPainting(begin_frame_args);
1082   layer_tree_host_->RecordEndOfFrameMetrics(frame_start_time,
1083                                             /* trackers */ 0u);
1084 }

我们看DoPainting 绘制页面。

void SingleThreadProxy::DoPainting(const viz::BeginFrameArgs& commit_args) {
  layer_tree_host_->UpdateLayers();
  ......
}

函数调用layer_tree_host->UpdateLayers()

bool LayerTreeHost::UpdateLayers() {
  ......
  client_->WillUpdateLayers();
  bool result = DoUpdateLayers();
  client_->DidUpdateLayers();
  micro_benchmark_controller_.DidUpdateLayers();

.......
  return result;
}

DoUpdateLayers更新layer。
cc/trees/layer_tree_host.cc

bool LayerTreeHost::DoUpdateLayers() {
  ......
  LayerList update_layer_list;
  draw_property_utils::FindLayersThatNeedUpdates(this, &update_layer_list);
  // 执行绘制
  bool did_paint_content = PaintContent(update_layer_list);
  return did_paint_content;
}

调用PainContent绘制。

bool LayerTreeHost::PaintContent(const LayerList& update_layer_list) {
  DCHECK(IsMainThread());
  base::AutoReset<bool> painting(&in_paint_layer_contents_, true);
  bool did_paint_content = false;
  for (const auto& layer : update_layer_list) {
    did_paint_content |= layer->Update();
  }
  return did_paint_content;
}

绘制没一个Layer。
cc/layers/picture_layer.cc

130 bool PictureLayer::Update() {
      ......
159   if (updated) {
160     {
161       auto old_display_list = std::move(picture_layer_inputs_.display_list);
          //绘制内容到displayList
162       picture_layer_inputs_.display_list =
163           picture_layer_inputs_.client->PaintContentsToDisplayList();
164       if (old_display_list &&
165           picture_layer_inputs_.display_list
166               ->NeedsAdditionalInvalidationForLCDText(*old_display_list)) {
167         last_updated_invalidation_.Write(*this) = gfx::Rect(bounds());
168       }
169     }
170 
        .....
188     recording_source->UpdateDisplayItemList(
189         picture_layer_inputs_.display_list,
190         layer_tree_host()->recording_scale_factor());
191 
192     SetNeedsPushProperties();
193     IncreasePaintCount();
194   } else {
195     // If this invalidation did not affect the recording source, then it can be
196     // cleared as an optimization.
197     last_updated_invalidation_.Write(*this).Clear();
198   }
199 
200   return updated;
201 }

162-163行更新displaylist。
ui/compositor/layer.cc

1433 scoped_refptr<cc::DisplayItemList> Layer::PaintContentsToDisplayList() {
1434   TRACE_EVENT1("ui", "Layer::PaintContentsToDisplayList", "name", name_);
1435   gfx::Rect local_bounds(bounds().size());
1436   gfx::Rect invalidation(
1437       gfx::IntersectRects(paint_region_.bounds(), local_bounds));
1438   paint_region_.Clear();
1439   auto display_list = base::MakeRefCounted<cc::DisplayItemList>();
1440   if (delegate_) {
1441     delegate_->OnPaintLayer(PaintContext(display_list.get(),
1442                                          device_scale_factor_, invalidation,
1443                                          GetCompositor()->is_pixel_canvas()));
1444   }
1445   display_list->Finalize();
1446   // TODO(domlaskowski): Move mirror invalidation to Layer::SchedulePaint.
1447   for (const auto& mirror : mirrors_)
1448     mirror->dest()->SchedulePaint(invalidation);
1449   return display_list;
1450 }

1441 行执行真正的绘制
ui/aura/window.cc

void Window::OnPaintLayer(const ui::PaintContext& context) {
  Paint(context);
}

void Window::Paint(const ui::PaintContext& context) {
  if (delegate_)
    delegate_->OnPaint(context);
}

最终调用到Widget绘制
ui/views/widget/desktop_aura/desktop_native_widget_aura.cc

void DesktopNativeWidgetAura::OnPaint(const ui::PaintContext& context) {
  if (native_widget_delegate_) {
    desktop_window_tree_host_->UpdateWindowShapeIfNeeded(context);
    native_widget_delegate_->OnNativeWidgetPaint(context);
  }
}

调用到Widget::OnNativeWidgetPaint
ui/views/widget/widget.cc


void Widget::OnNativeWidgetPaint(const ui::PaintContext& context) {
  // On Linux Aura, we can get here during Init() because of the
  // SetInitialBounds call.
  if (!native_widget_initialized_)
    return;
  GetRootView()->PaintFromPaintRoot(context);
}

到用到rootview的PaintFromPaintRoot方法,表示从根节点开始绘制
ui/views/view.cc

void View::PaintFromPaintRoot(const ui::PaintContext& parent_context) {
  PaintInfo paint_info = PaintInfo::CreateRootPaintInfo(
      parent_context, layer() ? layer()->size() : size());
  Paint(paint_info);
   ......
}

查看Paint方法。

void View::Paint(const PaintInfo& parent_paint_info) {
  CHECK_EQ(life_cycle_state_, LifeCycleState::kAlive);

  if (!ShouldPaint())
    return;

 .....
  ui::ClipRecorder clip_recorder(parent_paint_info.context());
  if (!layer()) {
    ......
    OnPaint(canvas);
  }

  CHECK_EQ(life_cycle_state_, LifeCycleState::kAlive);

  // View::Paint() recursion over the subtree.
  PaintChildren(paint_info);
}

函数先调用OnPaint绘制自身,再调用PaintChildren 绘制子view。

void View::OnPaint(gfx::Canvas* canvas) {
  TRACE_EVENT1("views", "View::OnPaint", "class", GetClassName());
  OnPaintBackground(canvas);
  OnPaintBorder(canvas);
}

对于普通view, OnPaint绘制背景和边框即可。

void View::PaintChildren(const PaintInfo& paint_info) {
  TRACE_EVENT1("views", "View::PaintChildren", "class", GetClassName());
  RecursivePaintHelper(&View::Paint, paint_info);
}

绘制子view调用RecursivePaintHelper 方法绘制。


void View::RecursivePaintHelper(void (View::*func)(const PaintInfo&),
                                const PaintInfo& info) {
  View::Views children = GetChildrenInZOrder();
  DCHECK_EQ(children_.size(), children.size());
  for (auto* child : children) {
    if (!child->layer())
      (child->*func)(info);
  }
}

按照zorder 绘制子view。

chromium启动流程(一)-browser进程启动流程_第2张图片

你可能感兴趣的:(chromium,chromium,chrome)