標準啟動原因

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 權限。
  • 通知使用者啟動原因,請等到 userdata 掛載後再信任系統啟動原因屬性 system_boot_reason_prop 中的內容。

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

  • userdata 掛載之前,system_boot_reason_prop 會包含 bootloader_boot_reason_prop 的值。
  • 安裝 userdata 後,system_boot_reason_prop 可能會更新以符合規定,或回報更準確的資訊。

因此,Android 9 會延長正式取得啟動原因所需的時間,從啟動時立即取得 (使用 bootloader_boot_reason_prop) 改為在 userdata 掛載後才取得 (使用 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 的值 (第一個區間,在結束或半形逗號之前) 必須是下列集合中的值,並分為核心、強大和鈍鈍的理由:

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

引導程式必須提供核心組合或鈍性組合 reason,並且強烈建議在可判斷的情況下提供 subreason。舉例來說,長按電源鍵 (可能有或沒有 ramoops 備份) 會顯示啟動原因 "reboot,longkey"

任何第一個區段 reason 都不能是任何 subreasondetail 的一部分。不過,由於核心設定原因無法由使用者空間產生,因此 "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"

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

回報啟動原因

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

我們強烈建議您在 system/core/bootstat/bootstat.cpp 中使用現有的相容項目,並在使用不相容字串前謹慎評估。以下為相關指南:

  • OK:從啟動載入程式回報 "kernel_panic",因為 bootstat 可能會檢查 ramoops 以便 kernel_panic signatures 將子原因精簡為標準 system_boot_reason_prop
  • 不正確:在 kBootReasonMap 中回報不符合規定的字串 (例如來自引導程式的 "panic")),因為這會最終導致無法精進 reason

舉例來說,如果 kBootReasonMap 包含 "wdog_bark",則引導程式開發人員應:

  • 變更為 "watchdog,bark",並新增至 kBootReasonMap 中的清單。
  • 請考量 "bark" 對不熟悉該技術的使用者而言代表什麼意思,並判斷是否有更有意義的 subreason 可用。

驗證啟動原因是否符合規定

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

因此,啟動載入程式相容性要求啟動載入程式開發人員自願遵守上述規則和指南的精神。我們強烈建議這類開發人員為 AOSP (特別是 system/core/bootstat/bootstat.cpp) 做出貢獻,並利用這個機會討論有關啟動原因的問題。