[Note]ChromiumOS | 从启动Chrome到进入Out of Box Experience

2021 06 8, Tue

CrOS要做定制,其中第一个任务就是需要定制登录,有了自己的凭证才能用自己的服务。最容易追踪的就是oobe的过程。

这篇并不是讲解性的内容,只是个人阅读代码的记录。幕布:https://mubu.com/app/edit/home/iyQPBdWUie

Chrome启动

ChromeMain

ChromeOS启动以后图形界面全部由Chrome完成,入口和Linux桌面Chrome入口都在chrome\app\chrome_exe_main_aura.cc,main函数直接启动ChromeMain,ChromeMain在同目录的chrome_main.cc中定义,也是一个比较简单的函数。

主要是解析了命令行参数

  params.argc = argc;
  params.argv = argv;
  base::CommandLine::Init(params.argc, params.argv);

如果是headless chromium那就直接返回headless::HeadlessShellMain(params),否则用content::ContentMain(params)

#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC) || \
    defined(OS_WIN)
  if (command_line->HasSwitch(switches::kHeadless)) {
    return headless::HeadlessShellMain(params);
  }
#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC) ||
        // defined(OS_WIN)

  int rv = content::ContentMain(params);

content::ContentMain && RunContentProcess && ContentMainRunnerImpl::Run

ContentMain实际上是启动了RunContentProcess和ContentMainRunnerImpl的一个实例的Run函数。

RunContentProcess

大致来说还是解析命令行,然后处理fd啊、设置进程标题啊、设置信号啊、启动子进程啊这些事情。比较长,不贴代码凑字数了。

ContentMainRunnerImpl::Run && ContentMainRunnerImpl::RunBrowser

经过解析命令行,各个进程都知道了自己的职责。下来就是根据需求加载库,准备执行浏览器的逻辑。

大部分的逻辑都是配置各种各样的服务,创建消息循环,加载Locale,创建线程池。

完成这些以后就开始运行BrowserMain的部分了。

RunBrowserProcessMain && BrowserMain

类似于ContentMain,RunBrowserProcessMain也是代理到了BrowserMain,BrowserMain。BrowserMain则是创建了一个BrowserMainRunnerImpl,然后执行这个Runner。

BrowserMainRunnerImpl && BrowserMainRunnerImpl::Run

BrowserMainRunner没啥好说的,就是初始化然后启动MainLoop的过程。

但是在BrowserMainRunnerImpl::Init中,有一个BrowserMainParts:

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

  // |startup_data| is optional. If set, the thread owned by the data
  // will be registered as BrowserThread::IO in CreateThreads() instead of
  // creating a brand new thread.
  if (parameters_.startup_data) {
    StartupDataImpl* startup_data =
        static_cast<StartupDataImpl*>(parameters_.startup_data);
    // This is always invoked before |io_thread_| is initialized (i.e. never
    // resets it).
    io_thread_ = std::move(startup_data->io_thread);
    mojo_ipc_support_ = std::move(startup_data->mojo_ipc_support);
  }

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

而CreateBrowserMainParts就是注册Browser要用的各种类的函数。具体的实现在 https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/chrome_content_browser_client.cc?q=CreateBrowserMainParts&ss=chromium&start=11

不同的目标会加入不同的parts,也就会有不同的视图,会有不同的视图入口。

ChromeOS中使用到了一个ChromeBrowserMainPartsChromeosChromeBrowserMainExtraPartsAsh

其中ChromeBrowserMainPartsChromeos在登陆这一方面为我们做的最重要的几个事情是:

  • 启动并初始化SessionManager
  • 初始化UserManager 而ChromeBrowserMainExtraPartsAsh主要是提供了Ash窗口管理器

最终SessionManager在 初始化 ( Initialize ) 时,执行StartLoginOOBESession,在其中执行ShowLoginWizard(OobeScreen::SCREEN_UNKNOWN)。如果是完成了OOBE流程且有用户存在时,执行LoginDisplayHostMojo的StartSigninScreen,否则执行LoginDisplayHostWebUI的StartWizard,由WizardController控制进入本地保存的OOBE流程所在Screen或者WelcomeScreen。