標準啟動原因

Android 9 對啟動載入程式啟動原因規格進行了下列變更。

啟動原因

開機載入器會使用獨有的硬體和記憶體資源,判斷裝置重新啟動的原因,然後在啟動時將 androidboot.bootreason=<reason> 加入 Android 核心指令列,傳達判斷結果。init 接著會轉譯這個指令列,以傳播至 Android 屬性 bootloader_boot_reason_prop (ro.boot.bootreason)。 對於搭載 Android 12 以上版本,且使用核心版本 5.10 以上的裝置,androidboot.bootreason=<reason> 會新增至 bootconfig,而不是核心指令列。

啟動原因規格

舊版 Android 指定的開機原因格式不含空格、一律為小寫,且僅包含少數需求 (例如回報 kernel_panicwatchdogcold/warm/hard),並允許其他特殊原因。這項寬鬆的規格導致數百個自訂 (有時毫無意義) 的開機原因字串大量增加,進而造成難以管理的情況。在目前的 Android 版本中,系統啟動載入程式提交的內容幾乎無法剖析或毫無意義,因此造成 bootloader_boot_reason_prop 的法規遵循問題。

Android 9 發布後,Android 團隊發現舊版 bootloader_boot_reason_prop 具有相當大的動能,無法在執行階段重新編寫。因此,如要改善啟動原因規格,必須與啟動載入程式開發人員互動,並調整現有系統。為此,Android 團隊:

  • 與啟動載入程式開發人員互動,鼓勵他們:
    • 提供可剖析且可辨識的標準原因,以供 bootloader_boot_reason_prop 使用。
    • 參與 system/core/bootstat/bootstat.cpp kBootReasonMap 清單。
  • 新增受控且可在執行階段重新寫入的 system_boot_reason_prop 來源 (sys.boot.reason)。只有一小部分系統應用程式 (例如 bootstatinit) 可以重新寫入這項屬性,但所有應用程式都可以獲得 sepolicy 權限來讀取這項屬性。
  • 告知使用者啟動原因,以便等到使用者資料掛接後,再信任系統啟動原因屬性 system_boot_reason_prop 中的內容。

為什麼這麼晚才收到?雖然 bootloader_boot_reason_prop 可在啟動初期使用,但 Android 安全性政策會視需要封鎖這項資訊,因為這類資訊不準確、無法剖析且不符合標準。在多數情況下,只有對啟動系統有深入瞭解的開發人員才需要存取這項資訊。只有在使用者資料掛接,才能可靠且準確地擷取開機原因的精簡、可剖析且標準的 API system_boot_reason_prop。具體違規事項如下:

  • userdata 掛接之前, system_boot_reason_prop 會包含來自 bootloader_boot_reason_prop 的值。
  • 使用者資料掛接後system_boot_reason_prop 可能會更新為符合規定,或回報更準確的資訊。

因此,Android 9 延長了可正式取得啟動原因的時間,從啟動時立即準確 (使用 bootloader_boot_reason_prop),改為只有在掛接使用者資料後才能取得 (使用 system_boot_reason_prop)。

Bootstat 邏輯取決於更具參考價值且符合規範的 bootloader_boot_reason_prop。如果該屬性使用可預測的格式,就能提高所有受控重新啟動和關機情境的準確度,進而提升 system_boot_reason_prop 的準確度和意義。

標準開機原因格式

Android 9 的 bootloader_boot_reason_prop 採用下列標準開機原因格式:

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

格式設定規則:

  • 小寫
  • 不可留白 (請使用底線)
  • 所有可列印字元
  • 以半形逗號分隔的 reasonsubreason,以及一或多個 detail 執行個體。
    • 必要 reason,代表裝置必須重新啟動或關機的最高優先順序原因。
    • 選用的 subreason,代表裝置必須重新啟動或關機的簡短摘要 (或重新啟動或關機裝置的人員)。
    • 一或多個選用 detail 值。detail 可能會指向子系統,協助判斷導致 subreason 的特定系統。您可以指定多個 detail 值,這些值通常應遵循重要性階層。不過,回報多個重要性相同的值也是可以接受的做法。detail

bootloader_boot_reason_prop 的空白值視為無效 (因為這會允許其他代理程式事後插入啟動原因)。

原因規定

reason (第一個跨度,終止或逗號前) 的值必須屬於下列集合,並分為核心、強烈和直接原因:

  • 核心集:
    • watchdog"
    • "kernel_panic"
  • 強烈設定:
    • "recovery"
    • "bootloader"
  • 鈍角集合:
    • "cold"。通常表示所有裝置 (包括記憶體) 都已完全重設。
    • "hard"。通常表示硬體已重設狀態,ramoops 應保留永久內容。
    • "warm"。一般來說,這表示記憶體和裝置會保留某些狀態,而 ramoops (請參閱核心中的 pstore 驅動程式) 備份儲存空間包含持續性內容。
    • "shutdown"
    • "reboot"。通常表示 ramoops 狀態不明,硬體狀態不明。這個值是萬用值,因為 coldhardwarm 值會提供裝置重設深度的線索。

開機載入程式必須提供核心集或鈍集 reason,並強烈建議提供 subreason (如可判斷)。舉例來說,長按電源鍵 (可能或可能沒有 ramoops 備份) 的啟動原因為 "reboot,longkey"

任何 subreasondetail 都不得包含第一個跨度 reason。不過,由於核心設定原因無法由使用者空間產生,因此在設定原因不明確後,"watchdog" 可能會連同來源詳細資料 (例如 "reboot,watchdog,service_manager_unresponsive""reboot,software,watchdog") 重複使用。

開機原因不應需要專家內部知識才能解讀,且/或應以直覺式報表呈現,方便使用者閱讀。例如: "shutdown,vbxd" (不佳)、"shutdown,uv" (較佳)、 "shutdown,undervoltage" (最佳)。

原因和子原因組合

Android 會保留一組 reason-subreason 組合,這些組合不應在正常使用情況下過載,但如果組合能準確反映相關條件,則可視情況使用。保留組合的例子包括:

  • "reboot,userrequested"
  • "shutdown,userrequested"
  • "shutdown,thermal" (來源:thermald)
  • "shutdown,battery"
  • "shutdown,battery,thermal" (來自 BatteryStatsService)
  • "reboot,adb"
  • "reboot,shell"
  • "reboot,bootloader"
  • "reboot,recovery"

詳情請參閱 kBootReasonMap 中的 system/core/bootstat/bootstat.cpp,以及 Android 來源存放區中的相關 Git 變更記錄。

回報啟動原因

所有啟動原因 (無論是來自系統啟動載入程式,還是記錄在標準啟動原因中) 都必須記錄在 system/core/bootstat/bootstat.cppkBootReasonMap 區段中。kBootReasonMap 清單混合了符合規定和不符合規定的舊版原因。開機載入程式開發人員應只在此註冊新的相容原因 (除非產品已出貨且無法變更,否則不應註冊不相容原因)。

強烈建議您使用 system/core/bootstat/bootstat.cpp 中現有的相容項目,並謹慎使用不相容的字串。做為參考,建議您:

  • 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.
  • 不建議kBootReasonMap 中回報不符規定的字串 (例如 "panic"),因為這最終會導致無法調整 reason)。

舉例來說,如果 kBootReasonMap 包含 "wdog_bark",開機載入程式開發人員應:

  • 變更為 "watchdog,bark",並新增至 kBootReasonMap 中的清單。
  • 請考慮對不熟悉這項技術的人來說,"bark" 代表什麼意義,並判斷是否有更具意義的 subreason

確認啟動原因是否符合規定

目前 Android 並未提供主動式 CTS 測試,可準確觸發或檢查開機載入程式可能提供的所有開機原因;合作夥伴仍可嘗試執行被動式測試,判斷相容性。

因此,為確保開機載入程式符合規定,開發人員必須自願遵守上述規則和規範的精神。 我們強烈建議這類開發人員為 AOSP (特別是 system/core/bootstat/bootstat.cpp) 做出貢獻,並利用這個機會,在論壇上討論啟動原因問題。