Android系统底层Reboot流程源码解读

  目录

  Framework 中 Reboot 流程

  Reboot 在 Android 系统中主要通过物理按键或UI菜单进行触发,最终由 PowerManager 执行 Reboot 流程。下图描述了 Reboot 执行时,Framework 中相关线程的状态,最终将 Reboot 相关信息设置到属性 中。Framework 中的具体流程本文不再描述。

  Init 中 Reboot 流程

  Android framework 处理完 Reboot 流程后,更新了属性 。Init 正是依靠该属性来执行底层 Reboot 动作。Init 对 Reboot 的处理主要为以下几个方面:

  1,进程监控属性 sys.powerctl 的改变

  /system/core/init/init.cpp

  void PropertyChanged(const std::string& name, const std::string& value) {

  // If the property is sys.powerctl, we bypass the event queue and immediately handle it.

  // This is to ensure that init will always and immediately shutdown/reboot, regardless of

  // if there are other pending events to process or if init is waiting on an exec service or

  // waiting on a property.

  // In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific

  // commands to be executed.

  // sys.powerctl 做为特殊属性来处理,直接触发 shutdown/reboot 流程。

  if (name == "sys.powerctl") {

  trigger_shutdown(value);

  }

  if (property_triggers_enabled) {

  ActionManager::GetInstance().QueuePropertyChange(name, value);

  WakeMainInitThread();

  }

  prop_waiter_state.CheckAndResetWait(name, value);

  }

  2,HandlePowerctlMessage()对属性 sys.powerctl 进行解析

  真正 shutdown/reboot 的流程在 HandlePowerctlMessage(),对属性 进行解析,并存储相关信息。

  /system/core/init/reboot.cpp

  void HandlePowerctlMessage(const std::string& command) {

  unsigned int cmd = 0;

  std::vector cmd_params = Split(command, ",");

  std::string reboot_target = "";

  bool run_fsck = false;

  bool command_invalid = false;

  bool userspace_reboot = false;

  // 解析 shutdown 参数

  if (cmd_params[0] == "shutdown") {

  cmd = ANDROID_RB_POWEROFF;

  if (cmd_params.size() >= 2) {

  if (cmd_params[1] == "userrequested") { // shutdown,userrequested

  // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.

  // Run fsck once the file system is remounted in read-only mode.

  run_fsck = true;

  } else if (cmd_params[1] == "thermal") { // shutdown,thermal

  // Turn off sources of heat immediately.

  TurnOffBacklight();

  // run_fsck is false to avoid delay

  cmd = ANDROID_RB_THERMOFF;

  }

  }

  // 解析 reboot 参数

  } else if (cmd_params[0] == "reboot") {

  cmd = ANDROID_RB_RESTART2;

  if (cmd_params.size() >= 2) {

  reboot_target = cmd_params[1];

  if (reboot_target == "userspace") { // reboot,userspace

  LOG(INFO) << "Userspace reboot requested";

  userspace_reboot = true;

  }

  // adb reboot fastboot should boot into bootloader for devices not

  // supporting logical partitions.

  if (reboot_target == "fastboot" &&

  !android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {

  reboot_target = "bootloader"; // 在非动态分区的系统上,reboot后进入bootloader

  }

  // When rebooting to the bootloader notify the bootloader writing

  // also the BCB.

  if (reboot_target == "bootloader") { // reboot,bootloader

  std::string err;

  if (!write_reboot_bootloader(&err)) { // 更新BCB

  LOG(ERROR) << "reboot-bootloader: Error writing "

  "bootloader_message: "

  << err;

  }

  } else if (reboot_target == "recovery") { // reboot,recovery

  bootloader_message boot = {};

  if (std::string err; !read_bootloader_message(&boot, &err)) {

  LOG(ERROR) << "Failed to read bootloader message: " << err;

  }

  // Update the boot command field if it's empty, and preserve

  // the other arguments in the bootloader message.

  if (!CommandIsPresent(&boot)) { // 更新BCB

  strlcpy(boot.command, "boot-recovery", sizeof(boot.command));

  if (std::string err; !write_bootloader_message(boot, &err)) {

  LOG(ERROR) << "Failed to set bootloader message: " << err;

  return;

  }

  }

  } else if (reboot_target == "sideload" || reboot_target == "sideload-auto-reboot" ||

  reboot_target == "fastboot") { // reboot,fastboot

  std::string arg = reboot_target == "sideload-auto-reboot" ? "sideload_auto_reboot"

  : reboot_target;

  const std::vector options = {

  "--" + arg,

  };

  std::string err;

  if (!write_bootloader_message(options, &err)) { // 更新BCB

  LOG(ERROR) << "Failed to set bootloader message: " << err;

  return;

  }

  reboot_target = "recovery"; // reboot后进入recovery

  }

  // If there are additional parameter, pass them along

  for (size_t i = 2; (cmd_params.size() > i) && cmd_params[i].size(); ++i) {

  reboot_target += "," + cmd_params[i];

  }

  }

  } else {

  command_invalid = true;

  }

  if (command_invalid) {

  LOG(ERROR) << "powerctl: unrecognized command '" << command << "'";

  return;

  }

  // We do not want to process any messages (queue'ing triggers, shutdown messages, control

  // messages, etc) from properties during reboot.

  StopSendingMessages(); // 停止所有的属性处理

  if (userspace_reboot) { // reboot,userspace 执行用户空间重启,并不重启整个系统

  HandleUserspaceReboot();

  return;

  }

  LOG(INFO) << "Clear action queue and start shutdown trigger";

  ActionManager::GetInstance().ClearQueue(); // 清空init action队列

  // Queue shutdown trigger first

  ActionManager::GetInstance().QueueEventTrigger("shutdown"); // 执行init中的shutdown action

  // Queue built-in shutdown_done

  auto shutdown_handler = [cmd, command, reboot_target, run_fsck](const BuiltinArguments&) {

  DoReboot(cmd, command, reboot_target, run_fsck); // 执行 shutdown/reboot 动作

  return Result{};

  };

  ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done");

  EnterShutdown(); // 清理相关资源

  }

  3,DoReboot() 执行 shutdown/reboot 动作

  /system/core/init/reboot.cpp

  static void DoReboot(unsigned int cmd, const std::string& reason, const std::string& reboot_target,

  bool run_fsck) {

  Timer t;

  LOG(INFO) << "Reboot start, reason: " << reason << ", reboot_target: " << reboot_target;

  bool is_thermal_shutdown = cmd == ANDROID_RB_THERMOFF;

  // 配置shutdown timeout时间,缺省是6秒

  auto shutdown_timeout = 0ms;

  if (!SHUTDOWN_ZERO_TIMEOUT) {

  constexpr unsigned int shutdown_timeout_default = 6;

  constexpr unsigned int max_thermal_shutdown_timeout = 3;

  auto shutdown_timeout_final = android::base::GetUintProperty("ro.build.shutdown_timeout",

  shutdown_timeout_default);

  if (is_thermal_shutdown && shutdown_timeout_final > max_thermal_shutdown_timeout) {

  shutdown_timeout_final = max_thermal_shutdown_timeout;

  }

  shutdown_timeout = std::chrono::seconds(shutdown_timeout_final);

  }

  ......

  // Start a thread to monitor init shutdown process

  // 启动一个reboot监控线程

  LOG(INFO) << "Create reboot monitor thread.";

  bool reboot_monitor_run = true;

  std::thread reboot_monitor_thread(&RebootMonitorThread, cmd, reboot_target, &reboot_semaphore,

  shutdown_timeout, &reboot_monitor_run);

  reboot_monitor_thread.detach();

  ......

  // 保存reboot原因到属性中

  std::vector reasons = Split(reason, ",");

  if (reasons.size() >= 2 && reasons[0] == "reboot" &&

  (reasons[1] == "recovery" || reasons[1] == "bootloader" || reasons[1] == "cold" ||

  reasons[1] == "hard" || reasons[1] == "warm")) {

  skip = strlen("reboot,");

  }

  PersistRebootReason(reason.c_str() + skip, true);

  ......

  // 安全关闭watchdogd

  const std::set to_starts{"watchdogd"};

  std::set stop_first;

  for (const auto& s : ServiceList::GetInstance()) {

  ......

  }

  // remaining operations (specifically fsck) may take a substantial duration

  if (cmd == ANDROID_RB_POWEROFF || is_thermal_shutdown) {

  TurnOffBacklight(); // 先关背光

  }

  // 显示shutdown animation

  Service* boot_anim = ServiceList::GetInstance().FindService("bootanim");

  Service* surface_flinger = ServiceList::GetInstance().FindService("surfaceflinger");

  if (boot_anim != nullptr && surface_flinger != nullptr && surface_flinger->IsRunning()) {

  ......

  }

  // optional shutdown step

  // 1. terminate all services except shutdown critical ones. wait for delay to finish

  if (shutdown_timeout > 0ms) { // 使用SIGTERM终止所有非关键服务

  StopServicesAndLogViolations(stop_first, shutdown_timeout / 2, true /* SIGTERM */);

  }

  // Send SIGKILL to ones that didn't terminate cleanly.

  StopServicesAndLogViolations(stop_first, 0ms, false /* SIGKILL */); // 使用SIGKILL终止所有非关键服务

  SubcontextTerminate();

  // Reap subcontext pids.

  ReapAnyOutstandingChildren();

  // 3. send volume abort_fuse and volume shutdown to vold

  Service* vold_service = ServiceList::GetInstance().FindService("vold");

  if (vold_service != nullptr && vold_service->IsRunning()) {

  // Manually abort FUSE connections, since the FUSE daemon is already dead

  // at this point, and unmounting it might hang.

  CallVdc("volume", "abort_fuse");

  CallVdc("volume", "shutdown");

  vold_service->Stop(); // 关闭vold服务

  } else {

  LOG(INFO) << "vold not running, skipping vold shutdown";

  }

  // logcat stopped here

  StopServices(kDebuggingServices, 0ms, false /* SIGKILL */);

  // 4. sync, try umount, and optionally run fsck for user shutdown

  {

  Timer sync_timer;

  LOG(INFO) << "sync() before umount...";

  sync(); // 同步文件系统

  LOG(INFO) << "sync() before umount took" << sync_timer;

  }

  // 5. drop caches and disable zram backing device, if exist

  KillZramBackingDevice(); // kill ZRAM服务

  LOG(INFO) << "Ready to unmount apexes. So far shutdown sequence took " << t;

  // 6. unmount active apexes, otherwise they might prevent clean unmount of /data.

  if (auto ret = UnmountAllApexes(); !ret.ok()) {

  LOG(ERROR) << ret.error();

  }

  UmountStat stat = // unmount

  TryUmountAndFsck(cmd, run_fsck, shutdown_timeout - t.duration(), &reboot_semaphore);

  // Follow what linux shutdown is doing: one more sync with little bit delay

  {

  Timer sync_timer;

  LOG(INFO) << "sync() after umount...";

  sync(); // 再次同步文件系统

  LOG(INFO) << "sync() after umount took" << sync_timer;

  }

  if (!is_thermal_shutdown) std::this_thread::sleep_for(100ms);

  LogShutdownTime(stat, &t);

  // Send signal to terminate reboot monitor thread.

  reboot_monitor_run = false;

  sem_post(&reboot_semaphore);

  // Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.

  RebootSystem(cmd, reboot_target); // 执行系统reboot

  abort();

  }

  4,通过RebootSystem() 执行系统 Reboot 调用

  /system/core/init/reboot_utils.cpp

  void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget) {

  LOG(INFO) << "Reboot ending, jumping to kernel";

  if (!IsRebootCapable()) {

  // On systems where init does not have the capability of rebooting the

  // device, just exit cleanly.

  exit(0);

  }

  switch (cmd) {

  case ANDROID_RB_POWEROFF: // 执行关机

  reboot(RB_POWER_OFF);

  break;

  case ANDROID_RB_RESTART2: // 执行重启

  syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,

  LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());

  break;

  case ANDROID_RB_THERMOFF: // 过热保护,根据属性来执行关机或重起

  if (android::base::GetBoolProperty("ro.thermal_warmreset", false)) {

  LOG(INFO) << "Try to trigger a warm reset for thermal shutdown";

  static constexpr const char kThermalShutdownTarget[] = "shutdown,thermal";

  syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,

  LINUX_REBOOT_CMD_RESTART2, kThermalShutdownTarget);

  } else {

  reboot(RB_POWER_OFF);

  }

  break;

  }

  // In normal case, reboot should not return.

  PLOG(ERROR) << "reboot call returned";

  abort();

  }

  属性 的值决定了shutdown/reboot的行为,其格式为:。mode 为 reboot 或 shutdown,常见reason如下:

  shutdown,[reason]userrequestedthermal用户请求关机,需要运行fsck检查温度异常引起的关机执行基本关机流程

  reboot,[reason]userspacefastbootbootloaderrecoverysideloadsideload-auto-rebootcold / warm / hard / 用户空间软重启,用于更新应用重启到fastboot模式。不支持逻辑分区时,重启到bootloader模式。写入BCB重启到bootloader模式。写入BCB重启进入recvoery。写入BCB重启进入recovery,执行sideload,用于本地升级系统。写入BCBsideload完成后自动重启。写入BCB执行基本重启流程

  内核中 Reboot 流程

  内核中的入口

  Android Native 中最终执行了 reboot 系统调用,对应在内核中的入口为:

  /kernel/reboot.c

  SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,

  void __user *, arg)

  {

  ......

  mutex_lock(&system_transition_mutex);

  switch (cmd) {

  case LINUX_REBOOT_CMD_RESTART:

  kernel_restart(NULL);

  break;

  ........

  case LINUX_REBOOT_CMD_POWER_OFF: // 关机

  kernel_power_off();

  do_exit(0);

  break;

  case LINUX_REBOOT_CMD_RESTART2: // 重启

  ret = strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1);

  if (ret < 0) {

  ret = -EFAULT;

  break;

  }

  buffer[sizeof(buffer) - 1] = '0';

  kernel_restart(buffer);

  break;

  ........

  }

  kernel_restart() 完成重启

  内核通过 kernel_power_off() 完成关机动作,通过 kernel_restart() 完成重启动作。

  /kernel/reboot.c

  void kernel_restart(char *cmd)

  {

  kernel_restart_prepare(cmd); // 执行重启的准备工作:调用reboot通知队列,关闭usermodehelper,关闭所有设备

  migrate_to_reboot_cpu(); // 迁移所有任务到cpu0上

  syscore_shutdown(); // 关闭syscore设备

  if (!cmd)

  pr_emerg("Restarting system

  ");

  else

  pr_emerg("Restarting system with command '%s'

  ", cmd);

  kmsg_dump(KMSG_DUMP_SHUTDOWN);

  machine_restart(cmd); // 调用machine_restart()

  }

  EXPORT_SYMBOL_GPL(kernel_restart);

  ......

  void kernel_power_off(void)

  {

  kernel_shutdown_prepare(SYSTEM_POWER_OFF); // 执行重启的准备工作:调用reboot通知队列,关闭usermodehelper,关闭所有设备

  if (pm_power_off_prepare)

  pm_power_off_prepare();

  migrate_to_reboot_cpu(); // 迁移所有任务到cpu0上

  syscore_shutdown(); // 关闭syscore设备

  pr_emerg("Power down

  ");

  kmsg_dump(KMSG_DUMP_SHUTDOWN);

  machine_power_off(); // 调用machine_power_off()

  }

  EXPORT_SYMBOL_GPL(kernel_power_off);

  Reboot 和 Power Off 的大致流程

  Reboot 和 Power Off 的大致流程是一样的,主要区别在调用reboot通知队列的传参不同和machine执行函数不同。这里简单看一下 ARM64 的 machine_restart() 函数。

  /arch/arm64/kernel/process.c

  void machine_restart(char *cmd)

  {

  /* Disable interrupts first */

  local_irq_disable(); // 关闭中断

  smp_send_stop(); // 停止当前处理器外的所有处理器

  /*

  * UpdateCapsule() depends on the system being reset via

  * ResetSystem().

  */

  if (efi_enabled(EFI_RUNTIME_SERVICES))

  efi_reboot(reboot_mode, NULL); // EFI系统时

  /* Now call the architecture specific reboot code. */

  do_kernel_restart(cmd); // 调用restart处理队列

  /*

  * Whoops - the architecture was unable to reboot.

  */

  printk("Reboot failed -- System halted

  ");

  while (1);

  }

  /kernel/reboot.c

  /**

  * do_kernel_restart - Execute kernel restart handler call chain

  *

  * Calls functions registered with register_restart_handler.

  *

  * Expected to be called from machine_restart as last step of the restart

  * sequence.

  *

  * Restarts the system immediately if a restart handler function has been

  * registered. Otherwise does nothing.

  */

  void do_kernel_restart(char *cmd)

  {

  atomic_notifier_call_chain(&restart_handler_list, reboot_mode, cmd);

  }

  内核中的 Reboot 流程比较简单,核心就是处理内核、芯片、外设的状态,然后进行重启。

  Reboot 后的流程

  重启后,硬件相当于重新上电,最先进入 Bootloader,Bootloader 会根据 Reboot Reason 进入到不同的系统状态。通常来说,Bootloader 会分为多级,每家芯片原厂的实现都会有些区别,这里不去分析客制化的代码,只看一下 Android 在 U-boot 中对 Reboot 的处理。

  /u-boot/common/android_bootloader.c

  int android_bootloader_boot_flow(const char* iface_str,

  const char* dev_str,

  struct blk_desc *dev_desc,

  const struct disk_partition *misc_part_info,

  const char *slot,

  bool verify,

  unsigned long kernel_address,

  struct blk_desc *persistant_dev_desc)

  {

  ......

  /* Determine the boot mode and clear its value for the next boot if

  * needed.

  */

  // 根据misc分区信息获取启动模式

  mode = android_bootloader_load_and_clear_mode(dev_desc, misc_part_info);

  printf("ANDROID: reboot reason: "%s"

  ", android_boot_mode_str(mode));

  // TODO (rammuthiah) fastboot isn't suported on cuttlefish yet.

  // Once it is, these lines can be removed.

  if (mode == ANDROID_BOOT_MODE_BOOTLOADER) {

  mode = ANDROID_BOOT_MODE_NORMAL;

  }

  bool normal_boot = (mode == ANDROID_BOOT_MODE_NORMAL);

  switch (mode) {

  case ANDROID_BOOT_MODE_NORMAL: // 正常启动

  #ifdef CONFIG_ANDROID_SYSTEM_AS_ROOT

  /* In normal mode, we load the kernel from "boot" but append

  * "skip_initramfs" to the cmdline to make it ignore the

  * recovery initramfs in the boot partition.

  */

  mode_cmdline = "skip_initramfs"; // System-as-root时跳过boot分区中的initramfs

  #endif

  break;

  case ANDROID_BOOT_MODE_RECOVERY: // 进入recovery

  #if defined(CONFIG_ANDROID_SYSTEM_AS_ROOT) || defined(CONFIG_ANDROID_USES_RECOVERY_AS_BOOT)

  /* In recovery mode we still boot the kernel from "boot" but

  * don't skip the initramfs so it boots to recovery.

  * If on Android device using Recovery As Boot, there is no

  * recovery partition.

  */

  // System-as-root时使用boot分区中的initramfs,Recovery-as-root时没有recovery分区

  #else

  boot_partition = ANDROID_PARTITION_RECOVERY;

  #endif

  break;

  case ANDROID_BOOT_MODE_BOOTLOADER: // 进入bootloader·

  /* Bootloader mode enters fastboot. If this operation fails we

  * simply return since we can't recover from this situation by

  * switching to another slot.

  */

  return android_bootloader_boot_bootloader(); // 启动进入bootloader

  }

  ......

  /* Load the kernel from the desired "boot" partition. */

  // 获取boot分区信息,用于加载kernel

  boot_part_num =

  android_part_get_info_by_name_suffix(dev_desc, boot_partition,

  slot_suffix, &boot_part_info);

  /* Load the vendor boot partition if there is one. */

  // 获取vendor boot分区信息。当使用GKI时,boot分区存储GKI kernel,vendor boot供应商客制化的boot代码

  vendor_boot_part_num =

  android_part_get_info_by_name_suffix(dev_desc, vendor_boot_partition,

  slot_suffix,

  &vendor_boot_part_info);

  struct disk_partition *bootconfig_part_info_ptr = NULL;

  ......

  // 加载boot镜像

  struct andr_boot_info* boot_info = android_image_load(dev_desc, &boot_part_info,

  vendor_boot_part_info_ptr,

  kernel_address, slot_suffix, normal_boot, avb_bootconfig,

  persistant_dev_desc, bootconfig_part_info_ptr,

  verified_boot_img, verified_vendor_boot_img);

  ......

  /* Assemble the command line */

  // 整合boot信息到command line中,传递给kernel

  command_line = android_assemble_cmdline(slot_suffix, mode_cmdline, normal_boot,

  android_image_get_kernel_cmdline(boot_info),

  android_image_is_bootconfig_used(boot_info),

  avb_cmdline);

  env_set("bootargs", command_line);

  debug("ANDROID: bootargs: "%s"

  ", command_line);

  android_bootloader_boot_kernel(boot_info); // 启动进入kernel

  ......

  }

  Bootloader 的启动流程也比较清晰,先解析启动需要的信息,然后加载镜像进行启动。启动信息是通过 MISC 分区读取的,MISC 分区存储的正是 Android 系统关机过程中需要更新的 BCB。

  BCB(Bootloader Control Block)是 Android 系统中定义的一个启动控制区域,以 RAW 格式进行存储,用于在 Android 用户空间和 Android 兼容的 bootloader 之间交换交换信息。在 Bootloader 中,BCB 的读写代码如下,

  /u-boot/common/android_bootloader.c

  static int android_bootloader_message_load(

  struct blk_desc *dev_desc,

  const struct disk_partition *part_info,

  struct bootloader_message *message)

  {

  ulong message_blocks = sizeof(struct bootloader_message) /

  part_info->blksz;

  if (message_blocks > part_info->size) {

  printf("misc partition too small.

  ");

  return -1;

  }

  if (blk_dread(dev_desc, part_info->start, message_blocks, message) !=

  message_blocks) {

  printf("Could not read from misc partition

  ");

  return -1;

  }

  debug("ANDROID: Loaded BCB, %lu blocks.

  ", message_blocks);

  return 0;

  }

  static int android_bootloader_message_write(

  struct blk_desc *dev_desc,

  const struct disk_partition *part_info,

  struct bootloader_message *message)

  {

  ulong message_blocks = sizeof(struct bootloader_message) /

  part_info->blksz;

  if (message_blocks > part_info->size) {

  printf("misc partition too small.

  ");

  return -1;

  }

  if (blk_dwrite(dev_desc, part_info->start, message_blocks, message) !=

  message_blocks) {

  printf("Could not write to misc partition

  ");

  return -1;

  }

  debug("ANDROID: Wrote new BCB, %lu blocks.

  ", message_blocks);

  return 0;

  }

  ......

  static enum android_boot_mode android_bootloader_load_and_clear_mode(

  struct blk_desc *dev_desc,

  const struct disk_partition *misc_part_info)

  {

  struct bootloader_message bcb;

  #ifdef CONFIG_FASTBOOT

  char *bootloader_str;

  /* Check for message from bootloader stored in RAM from a previous boot.

  */

  bootloader_str = (char *)CONFIG_FASTBOOT_BUF_ADDR; // fastboot模式先先检查RAM中的boot信息

  if (!strcmp("reboot-bootloader", bootloader_str)) {

  bootloader_str[0] = '0';

  return ANDROID_BOOT_MODE_BOOTLOADER;

  }

  #endif

  /* Check and update the BCB message if needed. */

  // 从Misc分区中加载BCB信息

  if (android_bootloader_message_load(dev_desc, misc_part_info, &bcb) <

  0) {

  printf("WARNING: Unable to load the BCB.

  ");

  return ANDROID_BOOT_MODE_NORMAL;

  }

  // bootonce-bootloader意味着要启动计入bootloader,此时擦除BCB内容。

  if (!strcmp("bootonce-bootloader", bcb.command)) {

  /* Erase the message in the BCB since this value should be used

  * only once.

  */

  memset(bcb.command, 0, sizeof(bcb.command));

  android_bootloader_message_write(dev_desc, misc_part_info,

  &bcb);

  return ANDROID_BOOT_MODE_BOOTLOADER;

  }

  if (!strcmp("boot-recovery", bcb.command))

  return ANDROID_BOOT_MODE_RECOVERY;

  return ANDROID_BOOT_MODE_NORMAL;

  }

  BCB在 Android bootloader 中定义为一个结构体数据,在 Flash 中以 RAW 格式存储。其结构定义为,

  /u-boot/include/android_bootloader_message.h

  // Spaces used by misc partition are as below:

  // 0 - 2K For bootloader_message

  // 2K - 16K Used by Vendor's bootloader (the 2K - 4K range may be optionally used

  // as bootloader_message_ab struct)

  // 16K - 64K Used by uncrypt and recovery to store wipe_package for A/B devices

  // Note that these offsets are admitted by bootloader,recovery and uncrypt, so they

  // are not configurable without changing all of them.

  static const size_t BOOTLOADER_MESSAGE_OFFSET_IN_MISC = 0;

  static const size_t WIPE_PACKAGE_OFFSET_IN_MISC = 16 * 1024;

  /* Bootloader Message (2-KiB)

  *

  * This structure describes the content of a block in flash

  * that is used for recovery and the bootloader to talk to

  * each other.

  *

  * The command field is updated by linux when it wants to

  * reboot into recovery or to update radio or bootloader firmware.

  * It is also updated by the bootloader when firmware update

  * is complete (to boot into recovery for any final cleanup)

  *

  * The status field was used by the bootloader after the completion

  * of an "update-radio" or "update-hboot" command, which has been

  * deprecated since Froyo.

  *

  * The recovery field is only written by linux and used

  * for the system to send a message to recovery or the

  * other way around.

  *

  * The stage field is written by packages which restart themselves

  * multiple times, so that the UI can reflect which invocation of the

  * package it is. If the value is of the format "#/#" (eg, "1/3"),

  * the UI will add a simple indicator of that status.

  *

  * We used to have slot_suffix field for A/B boot control metadata in

  * this struct, which gets unintentionally cleared by recovery or

  * uncrypt. Move it into struct bootloader_message_ab to avoid the

  * issue.

  */

  struct bootloader_message {

  char command[32];

  char status[32];

  char recovery[768];

  // The 'recovery' field used to be 1024 bytes. It has only ever

  // been used to store the recovery command line, so 768 bytes

  // should be plenty. We carve off the last 256 bytes to store the

  // stage string (for multistage packages) and possible future

  // expansion.

  char stage[32];

  // The 'reserved' field used to be 224 bytes when it was initially

  // carved off from the 1024-byte recovery field. Bump it up to

  // 1184-byte so that the entire bootloader_message struct rounds up

  // to 2048-byte.

  char reserved[1184];

  };

  BCB主要的功能如下

  Android 用户空间(normal / recovery) 也是读写BCB来控制启动行为,如上文中 Init 的 Reboot 过程中就会更新BCB。BCB的读写函数如下,

  /bootable/recovery/bootloader_message/bootloader_message.cpp

  bool read_bootloader_message_from(bootloader_message* boot, const std::string& misc_blk_device,

  std::string* err) {

  return read_misc_partition(boot, sizeof(*boot), misc_blk_device,

  BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err);

  }

  // 从Misc分区读取BCB

  bool read_bootloader_message(bootloader_message* boot, std::string* err) {

  std::string misc_blk_device = get_misc_blk_device(err);

  if (misc_blk_device.empty()) {

  return false;

  }

  return read_bootloader_message_from(boot, misc_blk_device, err);

  }

  bool write_bootloader_message_to(const bootloader_message& boot, const std::string& misc_blk_device,

  std::string* err) {

  return write_misc_partition(&boot, sizeof(boot), misc_blk_device,

  BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err);

  }

  // 写BCB到Misc分区

  bool write_bootloader_message(const bootloader_message& boot, std::string* err) {

  std::string misc_blk_device = get_misc_blk_device(err);

  if (misc_blk_device.empty()) {

  return false;

  }

  return write_bootloader_message_to(boot, misc_blk_device, err);

  }

  // 清空BSC

  bool clear_bootloader_message(std::string* err) {

  bootloader_message boot = {};

  return write_bootloader_message(boot, err);

  }

  // 写recovery commands到BCB

  bool write_bootloader_message(const std::vector& options, std::string* err) {

  bootloader_message boot = {};

  update_bootloader_message_in_struct(&boot, options);

  return write_bootloader_message(boot, err);

  }

  bool write_bootloader_message_to(const std::vector& options,

  const std::string& misc_blk_device, std::string* err) {

  bootloader_message boot = {};

  update_bootloader_message_in_struct(&boot, options);

  return write_bootloader_message_to(boot, misc_blk_device, err);

  }

  // 更新recovery commands

  bool update_bootloader_message(const std::vector& options, std::string* err) {

  bootloader_message boot;

  if (!read_bootloader_message(&boot, err)) {

  return false;

  }

  update_bootloader_message_in_struct(&boot, options);

  return write_bootloader_message(boot, err);

  }

  bool update_bootloader_message_in_struct(bootloader_message* boot,

  const std::vector& options) {

  if (!boot) return false;

  // Replace the command & recovery fields.

  memset(boot->command, 0, sizeof(boot->command));

  memset(boot->recovery, 0, sizeof(boot->recovery));

  strlcpy(boot->command, "boot-recovery", sizeof(boot->command));

  std::string recovery = "recovery

  ";

  for (const auto& s : options) {

  recovery += s;

  if (s.back() != '

  ') {

  recovery += '

  ';

  }

  }

  strlcpy(boot->recovery, recovery.c_str(), sizeof(boot->recovery));

  return true;

  }

  // 将重启到bootloader的命令写入到BCB,这里是bootonce-bootloader

  bool write_reboot_bootloader(std::string* err) {

  bootloader_message boot;

  if (!read_bootloader_message(&boot, err)) {

  return false;

  }

  if (boot.command[0] != '0') {

  *err = "Bootloader command pending.";

  return false;

  }

  strlcpy(boot.command, "bootonce-bootloader", sizeof(boot.command));

  return write_bootloader_message(boot, err);

  }

  以上就是Android系统中底层Reboot流程的详细内容,更多关于Android系统中底层Reboot流程的资料请关注脚本之家其它相关文章!

  您可能感兴趣的文章: