標準啟動原因

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) 可以重新寫入這個屬性,但所有應用程式皆可授予讀取此屬性的權限。
  • 通知使用者啟動原因,等到使用者資料安裝完畢之後,再信任系統啟動原因屬性 system_boot_reason_prop 中的內容。

為何遲到?雖然 bootloader_boot_reason_prop 可在啟動時及早取得,但 Android 安全性政策會視需要封鎖這項資訊,因為其中提供的資訊不正確、無法剖析且非標準。在大多數情況下,只有對啟動系統有深厚知識的開發人員才能存取這項資訊。以 system_boot_reason_prop 做為啟動原因的精緻、可剖析的標準 API 只有在使用者資料安裝「之後」才能夠正確可靠地選取。具體違規事項如下:

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

因此,Android 9 會延長系統正式取得啟動原因前的時間長度,因此在啟動期間,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"
  • Burunt:
    • "cold":通常表示所有裝置 (包括記憶體) 已完全重設。
    • "hard":一般表示硬體已重設狀態,ramoops 應保留永久內容。
    • "warm"。一般表示記憶體和裝置會保留部分狀態,而 ramoops (請參閱核心中的 pstore 驅動程式) 備份儲存庫則包含永久內容。
    • "shutdown"
    • "reboot":通常表示 ramoops 狀態不明且硬體狀態不明。這個值是通用值,因為 coldhardwarm 值提供了關於裝置重設深度的線索。

系統啟動載入程式必須提供核心集或 Blunt 組合 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 中使用符合規定的現有項目,並先練習休息,再使用不符規定的字串。原則上:

  • 可以從系統啟動載入程式回報 "kernel_panic",因為 bootstat 能夠檢查 kernel_panic signaturesramoops,以將子原因修正為標準 system_boot_reason_prop
  • 不允許kBootReasonMap 中回報不符規定的字串 (例如:系統啟動載入程式中的 "panic"),因為這最終會破壞修正 reason 的功能)。

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

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

確認啟動原因符合規範

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

因此,系統啟動載入程式開發人員必須自行遵循上述規則和規範的精神,才能符合系統啟動載入程式的相關規定。我們強烈建議這類開發人員向 Android 開放原始碼計畫 (特別是 system/core/bootstat/bootstat.cpp) 做出貢獻,並將這個機會做為討論啟動原因問題的論壇。