Каноническая причина загрузки

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 зарезервирован набор комбинаций reasonsubreason , которые не следует перегружать при обычном использовании, но можно использовать в каждом конкретном случае, если комбинация точно отражает соответствующее состояние. Примеры зарезервированных комбинаций:

  • "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 ) и использовать эту возможность в качестве форума для обсуждения проблем, связанных с причинами загрузки.