[Note]ChromiumOS | Out of Box Experience流程

2021 06 11, Fri

之前提到Chrome启动后会由ChromeBrowserMainPartsChromeos初始化SessionManager并进入OOBE流程。

OobeUI

OOBE流程主要是OobeUI展示,WizardController控制流程,各个Handler处理逻辑。

界面跳转

在之前构建完成以后,我们通过执行chrome时带上–login-manager参数,启动了OobeUI,大约是类似于这样:

Chromium started with Ash

这一屏叫WelcomeScreen,是在SessionManager初始化时,发现没有执行过Oobe流程、或者本地没有用户,所以直接AdvanceToScreenAfterHIDDetection(OobeScreen::SCREEN_UNKNOWN)。AdvanceToScreen在没有保存Oobe进度的时候,使用WelcomeView::kScreenId作为actual first screen,启动这个界面。

整个流程的控制都又WizardController控制,加载资源由OobeUI完成,状态保存在LoginDisplayHost{,Mojo,WebUI}中。第一次启动时启动Oobe流程会使用LoginDisplayHostWebUI,不过第二次开始会使用LoginDisplayHostMojo。WizardController会注册很多的ScreenHandler类,主要是处理网页发给chrome的消息。WizardController在WizardController::CreateScreens函数中记录了都有哪些Handler处理网页的消息。

阅读代码以后大致能看出来有很多的OnXXXScreenExit这样的函数,用来处理一屏流程处理完成后,跳转到下一个屏的逻辑。由此可以分析Oobe的顺序:

  • WelcomeScreen
  • NetowrkScreen
  • EulaScreen
  • OobeUpdateScreen
  • AutoEnrollmentCheckScreen
    • EnrollmentScreen
  • PackagedLicenseScreen
  • UserCreationScreen
  • 加载Gaia的网页以及逻辑

加载的逻辑

OobeUI继承自MojoWebUIController,是一类加载网页来加载界面的类。加载网页的逻辑一般在构造函数中。

检查OobeUI的构造函数,有很多个AddWebUIHAndler,我们还看到有两个函数:ConfigureOobeDisplayCreateOobeUIDataSource

顾名思义一个配置Oobe显示屏,一个创建数据源。简单看一下源码,果然不出我所料,一个注册了各种Handler处理各个页面的消息,一个创建了一个DataSource并且把资源的ID都放进DataSource里面。

资源文件

登陆有关的资源文件,通过搜索CreateOobeUIDataSource中的ID,可以找到对应的grdp文件,以及对应的资源文件,都在目录chrome/browser/resources/chromeos/login/中。

根据内容和构建结果猜测,grd可以包含grdp文件,以减小单个xml文件的大小,方便人维护。构建后产生一个pack文件存储资源,.h头文件来标志资源文件在pack文件中的标号。如果我们需要增加资源文件,那么应该同时新建或者修改grdp文件,并且把新的grdp文件包含到grd文件中,这样就可以在C++中使用资源文件的标号来加载本地的文件了。

观察目录,阅读代码,可以看到这个目录中大都是xx.html以及有关的css和js文件。可以看到比较有趣的地方是,structure目录中,有一个screens_common.html,可以看到有非常多的自定义tag,而这些tag都在某个其他的html中定义过,比如说gaia-signin-element是在screen_gaia_signin.html中定义的,同时在screen_gaia_signin.js中通过Polymer指定了gaia-signin-element中各个生命周期函数以及属性一类的。大致来说功能上非常像React或者Vue代码分割以后按需加载组件。类似的,我们要增加web组件,那就用类似的方法定义html和js就好,需要的话加上css,用polymer组装成组件,需要的话加到某个screen中即可。Screen中的组件默认都有hidden CSS类。

WizardController

WizardController主要负责了Oobe流程控制。非常明显的特征就是在CreateScreens中注册了各种Screen的ID,在各种Screen的OnXXXScreenExit函数中会通过AdvanceToScreen跳转到各个Screen。

Oobe登陆流

根据之前找到的起点WelcomesScreen,在WizardController中找到WelcomeScreen结束对应的OnWelcomeScreenExit函数中,看到结束时如果点了继续,那么会跳转到NetworkScreen。以此类推,我们找到了这样的flow:

  • WelcomeScreen完成后
    • 继续:NetworkScreen
    • 安装系统:OsInstallScreenView
    • Demo:DemoModeSetup
    • 调试:EnableDebuggingScreen
  • NetworkScreen完成后
    • 返回
      • 如果有DemoModeController:DemoModePreferencesScreen
      • 否则:WelcomeScreen
    • Demo:
    • 完成
      • 需要显示Eula或者ARC的Tos:ShowEulaOrArcTosAfterNetworkScreen
      • 继续:OobeUpdate
  • EulaScreen完成后
    • OobeUpdate
  • OobeUpdate完成后
    • AutoEnrollmentCheckScreen
  • AutoEnrollmentCheckScreen完成后/OnDeviceDisabledChecked
    • 如果设备已经被禁用了:DeviceDisabledScreen
    • 如果在 Demo Mode ( ) 下:DemoModeSetupScreen
    • 需要尽早注册的情况:EnrollmentScreen
    • PackagedLicenseScreen
  • PackagedLicenseScreen完成后
    • 需要注册:EnrollmentScreen
    • LoginScreen
  • EnrollmentScreen完成后
    • 一部分设备注册后,为了浏览器能正确读取策略配置,系统会重启
    • 如果需要启动Chrome/Kiosk/ARC应用时,启动应用
    • 企业设备则是从WebUI切换为Mojo登陆界面
    • 否则ShowLoginScreen:GaiaScreen

我可能是有哪里有疏忽,没有找到UserCreationScreen。但是实际上是走到这里了的,也就是下来会选择是创建普通用户还是儿童用户,最后进入GaiaScreen。

GaiaScreen最后在Webview中加载在线的登陆页面,由页面完成登陆,并且通过JS发送用户账户信息给C++。C++尝试创建用户,最后完成设备初始化。