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 セキュリティ ポリシーによりブロックされます。
多くの場合、この情報にアクセスする必要があるのは、ブートシステムを十分に理解しているデベロッパーのみです。system_boot_reason_prop
による、洗練され解析可能な正規のブート理由の API を、確実かつ正確に取得できるのは、ユーザーデータをマウントした後に限られます。
詳細は以下のとおりです。
- ユーザーデータがマウントされる前は、
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
、1 つ以上のdetail
のインスタンス。- 必須の
reason
。デバイスの再起動やシャットダウンが必要となった理由として最も優先度が高いものを表します。 - オプションの
subreason
。デバイスの再起動やシャットダウンが必要となった理由(または、デバイスの再起動やシャットダウンを実行したユーザー)の簡単な概要を表します。 - 1 つ以上のオプションの
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"
となります。
最初のスパンの reason
は subreason
や detail
の一部にはできません。ただし、カーネルセット理由はユーザー空間では生成できないため、"watchdog"
はブラントセットの理由の後に、発生元とあわせて再使用できます(たとえば "reboot,watchdog,service_manager_unresponsive"
や "reboot,software,watchdog"
など)。
ブート理由は、内部の専門知識がなくても解読でき、直観的なレポートで人間が読めるようにします(たとえば、"shutdown,vbxd"
(非推奨)、"shutdown,uv"
(許容可能)、"shutdown,undervoltage"
(推奨)など)。
reason と subreason の組み合わせ
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
が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
)に貢献し、この機会をブート理由の問題について話し合う場として活用することを強く期待します。