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.cppkBootReasonMap列表。
- 為
- 添加
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的值。 - 掛載 userdata後,
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>…
格式化規則:
- 小寫
- 沒有空格(使用下劃線)
- 所有可打印字符
- 逗號分隔的
reason、subreason原因和一個或多個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狀態未知,硬件狀態未知。這個值是一個包羅萬象的值,因為cold、hardwarm值提供了有關設備重置深度的線索。
-
引導加載程序必須提供內核集或subreason集reason ,如果可以確定,強烈建議提供子原因。例如,可能有也可能沒有ramoops備份的電源鍵長按將具有啟動原因"reboot,longkey" 。
任何第一跨度reason都不能成為subreason或detail的一部分。但是,由於內核設置原因不能由用戶空間產生, "watchdog"可能會在鈍設置原因之後被重用,以及源的詳細信息(例如"reboot,watchdog,service_manager_unresponsive" ,或"reboot,software,watchdog" )。
啟動原因不應該需要專業的內部知識來破譯和/或應該是人類可讀的直觀報告。示例: "shutdown,vbxd" (壞)、 "shutdown,uv" (更好)、 "shutdown,undervoltage" ,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的 kBootReasonMap 以及 Android 源存儲庫中相關的 git changelog 歷史記錄。
報告啟動原因
所有引導原因,無論是來自引導加載程序還是記錄在規範引導原因中,都必須記錄在system/core/bootstat/bootstat.cpp的kBootReasonMap部分中。 kBootReasonMap列表是合規和舊版不合規原因的混合。引導加載程序開發人員應僅在此處註冊新的合規原因(並且不應註冊不合規原因,除非產品已發貨且無法更改)。
我們強烈建議在system/core/bootstat/bootstat.cpp中使用現有的、合規的條目,並在使用不合規的字符串之前進行克制。作為指導方針,它是:
- 可以從引導加載程序報告
"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 )做出貢獻,並利用這個機會作為討論啟動原因問題的論壇。