软重启

Android 11 支持软重启,即在运行时重启用户空间中的进程,以便应用要求重新启动的更新(例如对 APEX 软件包的更新)。目前,软重启仅适用于在 userdata 装载后启动的进程。

您可以采用以下方式请求软重启:

  • 通过 PowerManager 调用 PowerManager.reboot(PowerManager.REBOOT_USERSPACE)

  • 从 shell 中使用 adb shell svc power reboot userspaceadb reboot userspace 命令

软重启后,凭据加密存储空间仍保持解锁状态。

如果设备支持软重启,那么 PowerManager.isRebootingUserspace() API 方法会返回 true,系统属性 init.userspace_reboot.is_supported 的值则等于 1

如果设备不支持软重启,那么对 PowerManager.reboot(PowerManager.REBOOT_USERSPACE)adb reboot userspaceadb shell svc power reboot userspace 的调用会失败。

软重启的执行

通过 PowerManager 或从 shell 中请求软重启后,init 会执行以下步骤:

  1. 接收 sys.powerctl=reboot,userspace

  2. 复刻一个单独的 UserspaceRebootWatchdogThread() 进程来监控软重启。

  3. 触发 userspace-reboot-requested 操作,该操作会重置可能影响软重启的所有系统属性。受影响的属性如下:

    • sys.usb.config
    • sys.usb.state
    • sys.boot_completed
    • dev.bootcomplete
    • sys.init.updatable_crashing
    • sys.init.updatable_crashing_process_name
    • apexd.status
    • sys.user.0.ce_available
    • sys.shutdown.requested
    • service.bootanim.exit

    上述属性应在启动序列执行期间重新设置。如果需要,您还可以重置其他属性。如需查看示例,请参阅 rootdir/init.rc 中的 on userspace-reboot-requested 操作。

  4. 运行 DoUserspaceReboot 函数,该函数会执行以下操作:

    1. SIGTERM 发送到在 userdata 装载后启动的进程,并等待这些进程停止。
    2. 达到超时时间后,发送 SIGKILL 以终止任何还在运行的进程。
    3. 调用 /system/bin/vdc volume reset
    4. 卸载 zRAM 后备设备。
    5. 卸载处于活动状态的 APEX 软件包。
    6. 切换回引导装载命名空间。
    7. 触发 userspace-reboot-resume 操作。

如果在软重启之前请求了创建文件系统检查点,userspace-reboot-fs-remount 操作执行期间会将 userdata 重新装载到检查点模式下(详见下一部分)。在 sys.boot_completed property 被设为 1 之后,即认为软重启完成。软重启结束时,屏幕会保持关闭状态,需要有明确的用户互动才能唤醒屏幕。

文件系统检查点的创建

如果在软重启之前请求了文件系统检查点,软重启期间会将 userdata 重新装载到检查点模式下。重新装载逻辑在 fs_mgr_remount_userdata_into_checkpointing 函数中实现,而且因检查点创建方法而异。具体而言,当 userdata 支持:

  • 创建文件系统级检查点(例如 f2fs)时,使用 checkpoint=disable 选项重新装载 userdata

  • 创建块级检查点(例如 ext4)时,就会卸载 /data 并销毁装载了它的所有父设备映射器设备。然后,使用正常检查点启动时所用的代码路径装载 userdata

如果使用了文件系统级密钥环来管理凭据加密 (CE) 和设备加密 (DE) 密钥,那么在 userdata 卸载后,密钥会丢失。为了让密钥能够恢复,在将密钥安装到文件系统密钥环时,vold 还会将类型为 fscrypt-provisioning 的相同密钥安装到会话级密钥环。当 init_user0 被调用时,vold 会将这些密钥重新安装到文件系统密钥环中。

回退到硬重启

为确保软重启不会使设备处于无法使用的状态,Android 11 中包含回退到硬重启的机制,满足以下任一条件即触发该机制:

  • 设备未能在指定的超时时间内启动软重启(即 sys.init.userspace_reboot.in_progress=1)。
  • 进程未能在指定的超时时间内停止。
  • /system/bin/vdc volume reset 操作失败。
  • 卸载 zRAM 设备失败。
  • 处于活动状态的 APEX 软件包卸载时出错。
  • 尝试将 userdata 重新装载到检查点模式下失败。
  • 设备未能在指定的超时时间内成功启动(即 sys.boot_completed=1)。

按设备进行配置

您可以通过更改以下属性的值,对软重启进行某些方面的调整:

  • init.userspace_reboot.is_supported 用于控制设备何时可以执行软重启。如果此属性的值为 false0 或未指定,尝试重启就会被拒绝。
  • init.userspace_reboot.sigkill.timeoutmillis 用于控制超时时间(以毫秒为单位),收到 SIGKILL 信号的进程必须在该时间内停止。如果其中某一个进程未能在指定的超时时间内停止,就会触发回退到硬重启的机制。
  • init.userspace_reboot.sigterm.timeoutmillis 用于控制超时时间(以毫秒为单位),收到 SIGTERM 信号的进程必须在该时间内终止。未能在指定的超时时间内终止的所有进程都会收到 SIGKILL 信号。
  • init.userspace_reboot.started.timeoutmillis 用于控制超时时间(以毫秒为单位),软重启必须在该时间内启动,即 sys.init.userspace_reboot.in_progress=1。如果设备未能在指定的超时时间内启动软重启,就会触发回退到硬重启的机制。
  • init.userspace_reboot.userdata_remount.timeoutmillis 用于控制卸载 userdata 的超时时间(以毫秒为单位)。如果设备未能在指定的超时时间内卸载 userdata,就会触发回退到硬重启的机制。
  • init.userspace_reboot.watchdog.timeoutmillis 用于控制设备成功启动(即 sys.boot_completed=1)的超时时间。如果设备未能在指定的超时时间内启动,就会触发回退到硬重启的机制。

自定义软重启期间的动画

软重启的参考实现方案包括一项用于自定义软重启期间显示的动画的功能。

userspace-reboot-fs-remount 操作结束时,init 会启动 bootanim 服务。此服务会按以下动画文件列出的顺序查找其是否存在,并播放找到的第一个动画:

  • /product/media/userspace-reboot.zip
  • /oem/media/userspace-reboot.zip
  • /system/media/userspace-reboot.zip

如果未指定软重启的专用动画文件,bootanim 会显示默认的 android 动画。

测试

Android 11 包含软重启的一个参考实现方案。此外,您还可以使用 UserspaceRebootHostTest 中的 CTS 测试来验证软重启。