Motivo del inicio canónico

Android 9 incluye los siguientes cambios en la especificación del motivo de inicio del bootloader.

Motivos de inicio

Un bootloader usa hardware y recursos de memoria disponibles de manera única para determinar por qué se reinició un dispositivo y, luego, comunica esa determinación agregando androidboot.bootreason=<reason> a la línea de comandos del kernel de Android para su lanzamiento. Luego, init traduce esta línea de comandos para propagarla a la propiedad bootloader_boot_reason_prop (ro.boot.bootreason) de Android. Para los dispositivos que se inician con Android 12 o versiones posteriores, que usan la versión 5.10 del kernel o una posterior, androidboot.bootreason=<reason> se agrega a bootconfig en lugar de la línea de comandos del kernel.

Especificaciones del motivo de inicio

Las versiones anteriores de Android especificaban un formato de motivo de inicio que no usaba espacios, estaba en minúsculas, incluía pocos requisitos (como para informar kernel_panic, watchdog, cold/warm/hard) y admitía otros motivos únicos. Esta especificación laxa provocó la proliferación de cientos de cadenas de motivos de inicio personalizadas (y, a veces, sin sentido), lo que, a su vez, generó una situación inmanejable. A partir de la versión actual de Android, el gran impulso del contenido casi sin analizar o sin sentido que presentó el bootloader creó problemas de cumplimiento para bootloader_boot_reason_prop.

Con el lanzamiento de Android 9, el equipo de Android reconoce que el bootloader_boot_reason_prop heredado tiene un impulso sustancial y no se puede volver a escribir durante el tiempo de ejecución. Por lo tanto, cualquier mejora en la especificación del motivo de inicio debe provenir de interacciones con los desarrolladores del bootloader y ajustes en el sistema existente. Para ello, el equipo de Android hace lo siguiente:

  • Interacción con los desarrolladores de bootloader para alentarlos a hacer lo siguiente:
    • Proporciona motivos canónicos, analizables y reconocibles a bootloader_boot_reason_prop.
    • Participar en la lista system/core/bootstat/bootstat.cpp kBootReasonMap
  • Agregar una fuente controlada y reescribible en el tiempo de ejecución de system_boot_reason_prop (sys.boot.reason). Un conjunto limitado de apps del sistema (como bootstat y init) puede reescribir esta propiedad, pero se pueden otorgar derechos de sepolicy a todas las apps para que la lean.
  • Informar a los usuarios del motivo del inicio para que esperen hasta que se monte el userdata antes de confiar en el contenido de la propiedad system_boot_reason_prop del motivo del inicio del sistema

¿Por qué tan tarde? Si bien bootloader_boot_reason_prop está disponible al principio del inicio, la política de seguridad de Android lo bloquea según sea necesario, ya que representa información imprecisa, no analizable y no canónica. En la mayoría de los casos, solo los desarrolladores con un conocimiento profundo del sistema de inicio deberían necesitar acceder a esta información. Una API refinada, analizable y canónica para el motivo de inicio con system_boot_reason_prop se puede detectar de forma confiable y precisa solo después de que se haya activado el archivo userdata. Más precisamente:

  • Antes de que se monte userdata, system_boot_reason_prop contendrá el valor de bootloader_boot_reason_prop.
  • Después de que se activen los datos del usuario, es posible que se actualice system_boot_reason_prop para que cumpla con los requisitos o informe con información más precisa.

Por este motivo, Android 9 extiende el período antes de que se pueda adquirir oficialmente el motivo del inicio, de modo que pase de ser preciso de inmediato durante el inicio (con bootloader_boot_reason_prop) a estar disponible solo después de que se haya activado el usuario de datos (con system_boot_reason_prop).

La lógica de Bootstat depende de un bootloader_boot_reason_prop más informativo y conforme. Cuando esa propiedad usa un formato predecible, mejora la precisión de todas las situaciones de reinicio y apagado controladas, lo que, a su vez, define mejor y expande la precisión y el significado de system_boot_reason_prop.

Formato del motivo de inicio canónico

El formato de motivo de inicio canónico para bootloader_boot_reason_prop en Android 9 usa la siguiente sintaxis:

<reason>,<subreason>,<detail>…

Reglas de formato:

  • Minúscula
  • Sin espacios en blanco (usa subrayado)
  • Todos los caracteres imprimibles
  • Instancias de reason, subreason y una o más detail separadas por comas.
    • Un reason obligatorio que representa el motivo de prioridad más alta por el que el dispositivo tuvo que reiniciarse o apagarse.
    • Un objeto subreason opcional que representa un breve resumen de por qué se tuvo que reiniciar o apagar el dispositivo (o quién reinició o apagó el dispositivo).
    • Uno o más valores detail opcionales. Un detail puede apuntar a un subsistema para ayudar a determinar qué sistema específico generó el subreason. Puedes especificar varios valores de detail, que, por lo general, deberían seguir una jerarquía de importancia. Sin embargo, también se acepta informar varios valores de detail de igual importancia.

Un valor vacío para bootloader_boot_reason_prop se considera ilegal (ya que permite que otros agentes inserten un motivo de inicio después de que se produce).

Requisitos de los motivos

El valor proporcionado para reason (primer intervalo, antes de la terminación o la coma) debe ser del siguiente conjunto dividido en motivos de kernel, fuertes y contundentes:

  • conjunto de kernels:
    • "watchdog"
    • "kernel_panic"
  • conjunto sólido:
    • "recovery"
    • "bootloader"
  • conjunto contundente:
    • "cold". Por lo general, indica un restablecimiento completo de todos los dispositivos, incluida la memoria.
    • "hard": Por lo general, indica que se restableció el estado del hardware y que ramoops debe retener el contenido persistente.
    • "warm". Por lo general, indica que la memoria y los dispositivos retienen algún estado, y el almacenamiento en caché de ramoops (consulta el controlador pstore en el kernel) contiene contenido persistente.
    • "shutdown"
    • "reboot". Por lo general, significa que se desconoce el estado de ramoops y el estado del hardware. Este valor es un comodín, ya que los valores cold, hard y warm proporcionan pistas sobre la profundidad del restablecimiento del dispositivo.

Los bootloaders deben proporcionar un conjunto de kernel o un conjunto reason contundente, y se recomienda que proporcionen un subreason si se puede determinar. Por ejemplo, si mantienes presionada la tecla de encendido que puede tener una copia de seguridad de ramoops o no, el motivo de inicio es "reboot,longkey".

Ningún reason de primer intervalo puede ser parte de ningún subreason ni detail. Sin embargo, como el espacio de usuario no puede producir los motivos de configuración del kernel, "watchdog" se puede volver a usar después de un motivo de configuración contundente, junto con un detalle de la fuente (por ejemplo, "reboot,watchdog,service_manager_unresponsive" o "reboot,software,watchdog").

Los motivos de inicio no deben requerir conocimientos internos de expertos para descifrarlos o deben ser legibles por humanos con un informe intuitivo. Ejemplos: "shutdown,vbxd" (malo), "shutdown,uv" (mejor), "shutdown,undervoltage" (preferido).

Combinaciones de motivos y submotivos

Android reserva un conjunto de combinaciones reason-subreason que no deben sobrecargarse durante el uso normal, pero que se pueden usar caso por caso si la combinación refleja con exactitud la condición asociada. Estos son algunos ejemplos de combinaciones reservadas:

  • "reboot,userrequested"
  • "shutdown,userrequested"
  • "shutdown,thermal" (de thermald)
  • "shutdown,battery"
  • "shutdown,battery,thermal" (desde BatteryStatsService)
  • "reboot,adb"
  • "reboot,shell"
  • "reboot,bootloader"
  • "reboot,recovery"

Para obtener más detalles, consulta kBootReasonMap en system/core/bootstat/bootstat.cpp y el historial de cambios de git asociado en el repositorio de código fuente de Android.

Cómo informar los motivos de inicio

Todos los motivos de inicio, ya sea del bootloader o registrados en el motivo de inicio canónico, deben registrarse en la sección kBootReasonMap de system/core/bootstat/bootstat.cpp. La lista kBootReasonMap es una combinación de motivos de cumplimiento y no cumplimiento heredados. Los desarrolladores del bootloader solo deben registrar aquí nuevos motivos de cumplimiento (y no deben registrar los de incumplimiento, a menos que el producto ya se haya enviado y no se pueda cambiar).

Te recomendamos que uses entradas existentes que cumplan con los requisitos en system/core/bootstat/bootstat.cpp y que te muestres prudente antes de usar una cadena que no cumpla con los requisitos. A modo de lineamiento, debes cumplir con los siguientes requisitos:

  • OK para informar "kernel_panic" desde el bootloader, ya que bootstat puede inspeccionar ramoops para que kernel_panic signatures defina mejor los submotivos en el system_boot_reason_prop canónico.
  • No es aceptable informar una cadena que no cumpla con los requisitos en kBootReasonMap (como "panic") del bootloader, ya que, en última instancia, se perderá la capacidad de definir mejor reason.

Por ejemplo, si kBootReasonMap contiene "wdog_bark", un desarrollador del bootloader debe hacer lo siguiente:

  • Cambia a "watchdog,bark" y agrégalo a la lista en kBootReasonMap.
  • Considera lo que significa "bark" para quienes no están familiarizados con la tecnología y determina si hay un subreason más significativo disponible.

Verifica el cumplimiento del motivo de inicio

En este momento, Android no proporciona una prueba de CTS activa que pueda activar o inspeccionar con precisión todos los motivos de inicio posibles que podría proporcionar un bootloader. Los socios aún pueden intentar ejecutar una prueba pasiva para determinar la compatibilidad.

Como resultado, el cumplimiento del bootloader requiere que los desarrolladores de bootloaders se adhieran de forma voluntaria al espíritu de las reglas y los lineamientos descritos anteriormente. Instamos a esos desarrolladores a que contribuyan al AOSP (específicamente a system/core/bootstat/bootstat.cpp) y a que usen esta oportunidad como foro para debatir sobre problemas con el motivo de inicio.