Motivo de inicialização canônico

O Android 9 inclui as seguintes mudanças na especificação do motivo de inicialização do carregador de inicialização.

Motivos de inicialização

Um carregador de inicialização usa recursos de hardware e memória disponíveis exclusivamente para determinar por que um dispositivo foi reinicializado e, em seguida, comunica essa determinação adicionando androidboot.bootreason=<reason> à linha de comando do kernel do Android para o lançamento. O init traduz essa linha de comando para propagá-la à propriedade bootloader_boot_reason_prop (ro.boot.bootreason) do Android. Para dispositivos iniciados com o Android 12 ou versões mais recentes, usando a versão 5.10 ou mais recente do kernel, o androidboot.bootreason=<reason> é adicionado ao bootconfig em vez da linha de comando do kernel.

Especificações do motivo de inicialização

Versões anteriores do Android especificavam um formato de motivo de inicialização que não usava espaços, era todo em letras minúsculas, incluía poucos requisitos (como para informar kernel_panic, watchdog, cold/warm/hard) e permitia outros motivos exclusivos. Essa especificação solta resultou na proliferação de centenas de strings personalizadas (e às vezes sem sentido) de motivo de inicialização, o que, por sua vez, levou a uma situação incontrolável. A partir da versão atual do Android, o grande movimento de conteúdo quase não analisável ou sem sentido registrado pelo carregador de inicialização criou problemas de conformidade para bootloader_boot_reason_prop.

Com o lançamento do Android 9, a equipe do Android reconhece que o bootloader_boot_reason_prop legado tem um grande impulso e não pode ser reescrito no momento da execução. Portanto, qualquer melhoria na especificação do motivo de inicialização precisa vir de interações com desenvolvedores de carregador de inicialização e ajustes no sistema atual. Para isso, a equipe do Android está:

  • Envolver os desenvolvedores de carregador de inicialização para incentivar a:
    • Forneça motivos canônicos, analisáveis e reconhecíveis para bootloader_boot_reason_prop.
    • Participe da lista system/core/bootstat/bootstat.cpp kBootReasonMap.
  • Adicionar uma fonte do system_boot_reason_prop (sys.boot.reason) controlada e regravável durante a execução. Um conjunto limitado de apps do sistema (como bootstat e init) pode reescrever essa propriedade, mas todos os apps podem receber direitos de sepolicy para lê-la.
  • Informar aos usuários o motivo da inicialização para esperar até que o userdata seja montado antes de confiar no conteúdo na propriedade do motivo da inicialização do sistema system_boot_reason_prop.

Por que tão tarde? Embora bootloader_boot_reason_prop esteja disponível no início da inicialização, ele é bloqueado pela política de segurança do Android conforme necessário porque representa informações imprecisas, não paráveis e não canônicas. Na maioria das situações, apenas desenvolvedores com conhecimento profundo do sistema de inicialização precisam acessar essas informações. Uma API refinada, analisável e canônica por motivo de inicialização com system_boot_reason_prop pode ser selecionada de maneira confiável e precisa somente após a ativação dos dados do usuário. Especificamente:

  • Antes dos dados do usuário serem montados, system_boot_reason_prop conterá o valor de bootloader_boot_reason_prop.
  • Depois que o userdata for montado, system_boot_reason_prop poderá ser atualizado para estar em conformidade ou informar informações mais precisas.

Por esse motivo, o Android 9 estende o período de tempo antes que o motivo de inicialização possa ser oficialmente adquirido, mudando de preciso imediatamente na inicialização (com bootloader_boot_reason_prop) para estar disponível somente depois que o userdata for montado (com system_boot_reason_prop).

A lógica de inicialização depende de um bootloader_boot_reason_prop mais informativo e em conformidade. Quando essa propriedade usa um formato previsível, ela melhora a precisão de todos os cenários de reinicialização e encerramento controlados, o que, por sua vez, refina e expande a precisão e o significado de system_boot_reason_prop.

Formato do motivo de inicialização canônico

O formato de motivo de inicialização canônico para bootloader_boot_reason_prop no Android 9 usa a seguinte sintaxe:

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

Regras de formatação:

  • Letra minúscula
  • Sem espaços em branco (use sublinhado)
  • Todos os caracteres imprimíveis
  • reason, subreason e uma ou mais instâncias de detail separadas por vírgulas.
    • Um reason obrigatório que representa o motivo de maior prioridade para a reinicialização ou desligamento do dispositivo.
    • Um subreason opcional que representa um breve resumo do motivo pelo qual o dispositivo teve que ser reinicializado ou desligado (ou quem reinicializou ou desligou o dispositivo).
    • Um ou mais valores detail opcionais. Um detail pode apontar para um subsistema para ajudar a determinar qual sistema específico resultou na subreason. É possível especificar vários valores de detail, que geralmente seguem uma hierarquia de importância. No entanto, também é aceitável informar vários valores de detail de igual importância.

Um valor vazio para bootloader_boot_reason_prop é considerado ilegal, porque isso permite que outros agentes injetem um motivo de inicialização após o fato.

Requisitos do motivo

O valor fornecido para reason (primeiro período, antes do encerramento ou da vírgula) precisa ser do seguinte conjunto dividido por motivos de kernel, forte e contundente:

  • kernel set:
    • "watchdog"
    • "kernel_panic"
  • Conjunto forte:
    • "recovery"
    • "bootloader"
  • Conjunto de pontas embotadas:
    • "cold". Geralmente indica uma redefinição completa de todos os dispositivos, incluindo a memória.
    • "hard". Geralmente indica que o hardware teve o estado redefinido e ramoops precisa manter o conteúdo permanente.
    • "warm": geralmente indica que a memória e os dispositivos retêm algum estado, e o armazenamento de suporte ramoops (consulte o driver pstore no kernel) contém conteúdo persistente.
    • "shutdown"
    • "reboot". Geralmente significa que o estado de ramoops é desconhecido e o estado do hardware é desconhecido. Esse valor é um guarda-chuva, já que os valores cold, hard e warm fornecem dicas sobre a profundidade da redefinição do dispositivo.

Os boot loaders precisam fornecer um conjunto de kernel ou um conjunto reason, e é altamente recomendável fornecer um subreason, se possível. Por exemplo, um toque longo na tecla liga/desliga que pode ou não ter backup de ramoops teria o motivo de inicialização "reboot,longkey".

Nenhum reason de primeira extensão pode fazer parte de nenhum subreason ou detail. No entanto, como os motivos de conjunto do kernel não podem ser produzidos pelo espaço do usuário, o "watchdog" pode ser reutilizado após um motivo de conjunto brusco, junto com um detalhe da fonte (por exemplo, "reboot,watchdog,service_manager_unresponsive" ou "reboot,software,watchdog").

Os motivos de inicialização não devem exigir conhecimento interno de especialistas para decifrar e/ou devem ser legíveis por humanos com um relatório intuitivo. Exemplos: "shutdown,vbxd" (ruim), "shutdown,uv" (melhor), "shutdown,undervoltage" (preferido).

Combinações de motivo e submotivo

O Android reserva um conjunto de combinações reason-subreason que não devem ser sobrecarregadas no uso normal, mas podem ser usadas caso a caso, se a combinação refletir com precisão a condição associada. Exemplos de combinações reservadas incluem:

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

Para mais detalhes, consulte kBootReasonMap em system/core/bootstat/bootstat.cpp e o histórico de mudanças do git associado no repositório de origem do Android.

Relatar motivos de inicialização

Todos os motivos de inicialização, sejam do carregador de inicialização ou gravados no motivo canônico, precisam ser registrados na seção kBootReasonMap de system/core/bootstat/bootstat.cpp. A lista kBootReasonMap é uma combinação de motivos em conformidade e incompatíveis legados. Os desenvolvedores de gerenciadores de inicialização precisam registrar apenas novos motivos compatíveis aqui (e não podem registrar motivos incompatíveis, a menos que o produto já tenha sido enviado e não possa ser alterado).

Recomendamos o uso de entradas existentes e compatíveis em system/core/bootstat/bootstat.cpp e a restrição de uso de uma string que não esteja em conformidade. A diretriz é:

  • OK para informar "kernel_panic" do carregador de inicialização, já que bootstat pode inspecionar ramoops para kernel_panic signatures refinar as subrazões na system_boot_reason_prop canônica.
  • Não é aceitável informar uma string incompatível em kBootReasonMap (como "panic") do carregador de inicialização), porque isso acaba com a capacidade de refinar o reason.

Por exemplo, se kBootReasonMap contiver "wdog_bark", o desenvolvedor do carregador de inicialização precisará:

  • Mude para "watchdog,bark" e adicione à lista em kBootReasonMap.
  • Considere o que "bark" significa para quem não conhece a tecnologia e determine se um subreason mais significativo está disponível.

Verificar a conformidade do motivo de inicialização

No momento, o Android não oferece um teste CTS ativo que possa acionar ou inspecionar com precisão todos os possíveis motivos de inicialização que um carregador de inicialização possa fornecer. Os parceiros ainda podem tentar executar um teste passivo para determinar a compatibilidade.

Como resultado, a conformidade do carregador de inicialização exige que os desenvolvedores adiram voluntariamente ao espírito das regras e diretrizes descritas acima. Pedimos que esses desenvolvedores contribuam com o AOSP (especificamente com system/core/bootstat/bootstat.cpp) e usem essa oportunidade como um fórum para discussões sobre problemas de motivo de inicialização.