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 權限來讀取這項屬性。 - 告知使用者啟動原因,以便等到使用者資料掛接後,再信任系統啟動原因屬性
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>…
格式設定規則:
- 小寫
- 不可留白 (請使用底線)
- 所有可列印字元
- 以半形逗號分隔的
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
、hard
和warm
值會提供裝置重設深度的線索。
開機載入程式必須提供核心集或鈍集 reason
,並強烈建議提供 subreason
(如可判斷)。舉例來說,長按電源鍵 (可能或可能沒有 ramoops
備份) 的啟動原因為 "reboot,longkey"
。
任何 subreason
或 detail
都不得包含第一個跨度 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.cpp
的 kBootReasonMap
區段中。kBootReasonMap
清單混合了符合規定和不符合規定的舊版原因。開機載入程式開發人員應只在此註冊新的相容原因 (除非產品已出貨且無法變更,否則不應註冊不相容原因)。
強烈建議您使用 system/core/bootstat/bootstat.cpp
中現有的相容項目,並謹慎使用不相容的字串。做為參考,建議您:
- OK to report
"kernel_panic"
from the bootloader, asbootstat
may be able to inspectramoops
forkernel_panic signatures
to refine the subreasons into the canonicalsystem_boot_reason_prop
. - 不建議在
kBootReasonMap
中回報不符規定的字串 (例如"panic")
,因為這最終會導致無法調整reason
)。
舉例來說,如果 kBootReasonMap
包含 "wdog_bark"
,開機載入程式開發人員應:
- 變更為
"watchdog,bark"
,並新增至kBootReasonMap
中的清單。 - 請考慮對不熟悉這項技術的人來說,
"bark"
代表什麼意義,並判斷是否有更具意義的subreason
。
確認啟動原因是否符合規定
目前 Android 並未提供主動式 CTS 測試,可準確觸發或檢查開機載入程式可能提供的所有開機原因;合作夥伴仍可嘗試執行被動式測試,判斷相容性。
因此,為確保開機載入程式符合規定,開發人員必須自願遵守上述規則和規範的精神。
我們強烈建議這類開發人員為 AOSP (特別是 system/core/bootstat/bootstat.cpp
) 做出貢獻,並利用這個機會,在論壇上討論啟動原因問題。