Canonical Boot Reason

Android 9 includes the following changes to the bootloader boot reason specification.

About boot reasons

A bootloader uses uniquely-available hardware and memory resources to determine why a device rebooted, then communicates that determination by adding androidboot.bootreason=<reason> to the Android kernel command line for its launch. init then translates this command line to propagate to the Android property bootloader_boot_reason_prop (ro.boot.bootreason).

About boot reason specifications

Previous releases of Android specified a boot reason format that used no spaces, was all lowercase, included few requirements (such as for reporting kernel_panic, watchdog, cold/warm/hard), and which made allowances for other unique reasons. This loose specification resulted in the proliferation of hundreds of custom (and sometimes meaningless) boot reason strings, which in turn led to an unmanageable situation. As of the current Android release, the sheer momentum of near unparseable or meaningless content filed by the bootloader has created compliance issues for bootloader_boot_reason_prop.

With the Android 9 release, the Android team recognizes that the legacy bootloader_boot_reason_prop has substantial momentum and cannot be re-written at runtime. Any improvements to the boot reason specification must therefore come from interactions with bootloader developers and tweaks to the existing system. To that end the Android team is:

  • Engaging with bootloader developers to encourage them to:
    • Provide canonical, parseable, and recognizable reasons to bootloader_boot_reason_prop.
    • Participate in the system/core/bootstat/bootstat.cpp kBootReasonMap list.
  • Adding a controlled and runtime-rewritable source of the system_boot_reason_prop (sys.boot.reason). A limited set of system applications (such as bootstat and init) can rewrite this property, but all applications can be granted sepolicy rights to read it.
  • Informing users of the boot reason to wait until after userdata is mounted before trusting the content in the system boot reason property system_boot_reason_prop.

Why so late? While bootloader_boot_reason_prop is available early on in boot, it is blocked by the Android security policy on an as-need basis because it represents inaccurate, unparseable, and noncanonical information. In most situations, only developers with deep knowledge of the boot system should need to access this information. A refined, parseable, and canonical API for boot reason via system_boot_reason_prop can be reliably and accurately picked up only after userdata has mounted. Specifically:

  • Before userdata has mounted, system_boot_reason_prop will contain the value from bootloader_boot_reasoon_prop.
  • After userdata has mounted, system_boot_reason_prop may be updated to be compliant or to report more accurate information.

For this reason, Android 9 extends the period of time before the boot reason can be officially acquired, changing it from being immediately accurate in boot (with bootloader_boot_reason_prop) to being available only after userdata has mounted (with system_boot_reason_prop).

Bootstat logic depends on a more informative and compliant bootloader_boot_reason_prop. When that property uses a predictable format, it improves the accuracy of all controlled reboot and shutdown scenarios, which in turn refines and expands the accuracy and meaning of system_boot_reason_prop.

Canonical boot reason format

The canonical boot reason format for bootloader_boot_reason_prop in Android 9 uses the following syntax:

<reason>,<subreason>,<detail>…

Formatting rules:

  • Lower case
  • No blanks (use underline)
  • All printable characters
  • Comma-separated reason, subreason, and one or more detail(s).
    • A required reason that represents the highest priority reason why the device had to reboot or shutdown.
    • An optional subreason that represents a short summary of why the device had to reboot or shutdown (or who rebooted or shutdown the device).
    • One or more optional detail values. A detail may point to a subsystem to aid in determining which specific system resulted in the subreason. You can specify multiple detail values, which should generally follow a hierarchy of importance. However, it is also acceptable to report multiple detail values of equal importance.

An empty value for bootloader_boot_reason_prop is considered illegal (as this allows other agents to inject a boot reason after the fact).

Reason requirements

The value given for reason (first span, prior to termination or comma) must be of the following set divided into kernel, strong, and blunt reasons:

  • kernel set:
    • "watchdog"
    • "kernel_panic"
  • strong set:
    • "recovery"
    • "bootloader"
  • blunt set:
    • "cold". Generally indicates a full reset of all devices, including memory.
    • "hard". Generally indicates the hardware has its state reset and ramoops should retain persistent content.
    • "warm". Generally indicates the memory and the devices retain some state, and the ramoops (see pstore driver in kernel) backing store contains persistent content.
    • "shutdown"
    • "reboot". Generally means the ramoops state is unknown and the hardware state is unknown. This value is a catchall as the cold, hard, and warm values provide clues as to the depth of the reset for the device.

Bootloaders must provide a kernel set or a blunt set reason, and are strongly encouraged to provide a subreason if it can be determined. For example, a power key long press that may or may not have ramoops backup would have the boot reason "reboot,longkey".

No first-span reason can be part of any subreason or detail. However, because kernel set reasons cannot be produced by user space, "watchdog" may be reused after a blunt set reason, along with a detail of the source (e.g. "reboot,watchdog,service_manager_unresponsive", or "reboot,software,watchdog").

Boot reasons should not require expert internal knowledge to decipher and/or should be human readable with an intuitive report. Examples: "shutdown,vbxd" (bad), "shutdown,uv" (better), "shutdown,undervoltage" (preferred).

Reason-Subreason combinations

Android reserves a set of reason-subreason combinations that should not be overloaded in normal usage but can be used on a case-by-case basis if the combination accurately reflects the associated condition. Examples of reserved combinations include:

  • "reboot,userrequested"
  • "shutdown,userrequested"
  • "Shutdown,thermal" (from thermald)
  • "shutdown,battery"
  • "Shutdown,battery,thermal" (from BatteryStatsService)
  • "reboot,adb"
  • "reboot,shell"
  • "reboot,bootloader"
  • "reboot,recovery"

For more details, refer to kBootReasonMap in system/core/bootstat/bootstat.cpp and the associated git changelog history in the Android source repository.

Reporting boot reasons

All boot reasons, either from the bootloader or recorded in the canonical boot reason, must be recorded in the kBootReasonMap section of system/core/bootstat/bootstat.cpp. The kBootReasonMap list is a mix of compliant and legacy non-compliant reasons. Bootloader developers should register only new compliant reasons here (and should not register non-compliant reasons unless the product has already shipped and cannot be changed).

We strongly recommend using existing, compliant entries in system/core/bootstat/bootstat.cpp and exercising restraint before using a non-compliant string. As a guideline, it is:

  • OK to report "kernel_panic" from the bootloader, as bootstat may be able to inspect ramoops for kernel_panic signatures to refine the subreasons into the canonical system_boot_reason_prop.
  • Not OK to report a non-compliant string in kBootReasonMap (such as "panic") from the bootloader, as this will ultimately break the ability to refine the reason.

For example, if kBootReasonMap contains "wdog_bark", a bootloader developer should:

  • Change to "watchdog,bark" and add to the list in kBootReasonMap.
  • Consider what "bark" means for those unfamiliar with the technology and determine if a more meaningful subreason is available.

Verifying boot reason compliance

At this time, Android does not provide an active CTS test that can accurately trigger or inspect all possible boot reasons a bootloader could provide; partners can still attempt to run a passive test to determine compatibility.

As a result, bootloader compliance requires bootloader developers to voluntarily adhere to the spirit of the rules and guidelines described above. We urge such developers to contribute to AOSP (specifically to system/core/bootstat/bootstat.cpp) and use this opportunity as a forum for discussions about boot reason issues.