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_panic
、watchdog
、cold
/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
)。只有少數系統應用程式 (例如bootstat
和init
) 可以覆寫此屬性,但所有應用程式都能獲得讀取的 sepolicy 權限。 - 通知使用者啟動原因,請等到 userdata 掛載後再信任系統啟動原因屬性
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 會延長正式取得啟動原因所需的時間,從啟動時立即取得 (使用 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>…
格式設定規則:
- 小寫
- 不留空白 (使用底線)
- 所有可列印半形字元
- 以半形逗號分隔的
reason
、subreason
和一或多個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
狀態不明,且硬體狀態不明。這個值是萬用值,因為cold
、hard
和warm
值會提供裝置重設深度的線索。
系統啟動載入程式必須提供核心集或 Blunt 組合 reason
。如果可以確定,強烈建議您提供 subreason
。舉例來說,如果電源鍵長按不一定會有 ramoops
備份,就會產生啟動原因 "reboot,longkey"
。
第一個區段 reason
不得是任何 subreason
或 detail
的一部分。不過,由於核心設定原因無法由使用者空間產生,因此 "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.cpp
的 kBootReasonMap
部分。kBootReasonMap
清單會混合符合規定和舊版不符合規定的原因。引導程式啟動程式開發人員應在此處僅註冊新的符合規定原因 (除非產品已出貨且無法變更,否則不應註冊不符合規定的原因)。
強烈建議您在 system/core/bootstat/bootstat.cpp
中使用符合規定的現有項目,並先練習休息,再使用不符規定的字串。原則上:
- 可以從系統啟動載入程式回報
"kernel_panic"
,因為bootstat
能夠檢查kernel_panic signatures
的ramoops
,以將子原因修正為標準system_boot_reason_prop
。 - 不正確:在
kBootReasonMap
中回報不符合規定的字串 (例如來自引導程式的"panic")
),因為這會最終導致無法精進reason
。
舉例來說,如果 kBootReasonMap
包含 "wdog_bark"
,則引導程式開發人員應:
- 變更為
"watchdog,bark"
,並新增至kBootReasonMap
中的清單。 - 請考量
"bark"
對不熟悉該技術的使用者而言代表什麼意思,並判斷是否有更有意義的subreason
可用。
確認啟動原因符合規範
目前 Android 並未提供主動 CTS 測試,無法準確觸發或檢查引導程式可能提供的所有可能啟動原因;合作夥伴仍可嘗試執行被動測試,以判斷相容性。
因此,啟動載入程式相容性要求啟動載入程式開發人員自願遵守上述規則和指南的精神。我們建議這類開發人員為 AOSP (特別是 system/core/bootstat/bootstat.cpp
) 做出貢獻,並利用這個機會討論有關啟動原因的問題。