В 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 на его чтение. - Информирование пользователей о причине загрузки, чтобы они дождались монтирования пользовательских данных, прежде чем доверять контенту в свойстве причины загрузки системы
system_boot_reason_prop.
Почему так поздно? bootloader_boot_reason_prop доступен на ранних этапах загрузки, но блокируется правилами безопасности Android по мере необходимости, поскольку представляет собой неточную, нераспознаваемую и неканоническую информацию.
В большинстве случаев эта информация нужна только разработчикам, которые хорошо разбираются в системе загрузки. Уточненный, анализируемый и канонический API для причины загрузки с system_boot_reason_prop можно надежно и точно получить только после монтирования userdata.
А именно:
- До монтирования userdata переменная
system_boot_reason_propбудет содержать значение изbootloader_boot_reason_prop. - После монтирования раздела userdata значение
system_boot_reason_propможет быть изменено, чтобы соответствовать требованиям или предоставлять более точную информацию.
По этой причине в Android 9 период времени, в течение которого можно официально получить причину загрузки, был увеличен. Теперь она становится доступна не сразу после загрузки (с помощью bootloader_boot_reason_prop), а только после монтирования раздела userdata (с помощью 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 (первый диапазон, до точки или запятой), должно быть одним из следующих вариантов, разделенных на основные, сильные и слабые причины:
- kernel set:
- "
watchdog" "kernel_panic"
- "
- strong set:
"recovery""bootloader"
- blunt set:
"cold". Обычно указывает на полный сброс всех устройств, включая память."hard". Обычно указывает на то, что состояние оборудования было сброшено иramoopsдолжен сохранить постоянный контент."warm". Обычно указывает на то, что память и устройства сохраняют некоторое состояние, а резервное хранилищеramoops(см. драйверpstoreв ядре) содержит постоянный контент."shutdown""reboot". Обычно означает, что статусramoopsнеизвестен, а также неизвестен статус оборудования. Это значение является универсальным, поскольку значенияcold,hardиwarmпозволяют определить, насколько глубоким был сброс устройства.
Загрузчики операционной системы должны предоставлять набор kernel или 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"
Дополнительные сведения можно найти в 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) и использовать эту возможность в качестве форума для обсуждения проблем, связанных с причинами загрузки.