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
может быть надёжно и точно использован только после монтирования пользовательских данных. В частности:
- До монтирования пользовательских данных
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
.
Канонический формат причины загрузки
Канонический формат причины загрузки для bootloader_boot_reason_prop
в Android 9 использует следующий синтаксис:
<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"
.
Ни одна 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"
Более подробную информацию можно найти в kBootReasonMap
в system/core/bootstat/bootstat.cpp
и в соответствующей истории изменений git в исходном репозитории Android.
Сообщить о причинах загрузки
Все причины загрузки, как указанные в загрузчике, так и указанные в канонической причине загрузки, должны быть записаны в разделе kBootReasonMap
файла system/core/bootstat/bootstat.cpp
. Список 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
) и использовать эту возможность в качестве форума для обсуждения проблем, связанных с причинами загрузки.