Razão de inicialização canônica

O Android 9 inclui as seguintes alterações 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 exclusivamente disponíveis 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 sua inicialização. init então traduz esta linha de comando para propagar para a propriedade do Android bootloader_boot_reason_prop ( ro.boot.bootreason ). Para dispositivos iniciados com Android 12 ou posterior, usando kernel versão 5.10 ou superior, androidboot.bootreason=<reason> é adicionado ao bootconfig em vez da linha de comando do kernel.

Especificações do motivo da inicialização

As 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 relatar kernel_panic , watchdog , cold / warm / hard ) e que permitia outros motivos exclusivos. Essa especificação solta resultou na proliferação de centenas de strings de motivo de inicialização personalizadas (e às vezes sem sentido), o que, por sua vez, levou a uma situação incontrolável. A partir da versão atual do Android, o grande impulso de conteúdo quase não analisável ou sem sentido arquivado pelo bootloader 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 impulso substancial e não pode ser reescrito em tempo de execução. Quaisquer melhorias na especificação do motivo da inicialização devem, portanto, vir de interações com os desenvolvedores do carregador de inicialização e ajustes no sistema existente. Para isso, a equipe do Android é:

  • Envolver-se com desenvolvedores de bootloader para incentivá-los 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 .
  • Adicionando uma fonte controlada e regravável em tempo de execução do system_boot_reason_prop ( sys.boot.reason ). Um conjunto limitado de aplicativos do sistema (como bootstat e init ) pode reescrever essa propriedade, mas todos os aplicativos podem receber direitos de sepolicy para lê-la.
  • Informando os usuários sobre o motivo da inicialização para esperar até que userdata seja montado antes de confiar no conteúdo na propriedade de 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 a necessidade porque representa informações imprecisas, não analisáveis ​​e não canônicas. Na maioria das situações, apenas desenvolvedores com profundo conhecimento do sistema de inicialização devem precisar acessar essas informações. Uma API refinada, analisável e canônica para motivo de inicialização via system_boot_reason_prop pode ser selecionada de maneira confiável e precisa somente após a montagem de userdata. Especificamente:

  • Antes que userdata seja montado, system_boot_reason_prop conterá o valor de bootloader_boot_reason_prop .
  • Após a montagem de userdata, system_boot_reason_prop pode ser atualizado para ser compatível ou para relatar informações mais precisas.

Por esse motivo, o Android 9 estende o período de tempo antes que o motivo da inicialização possa ser adquirido oficialmente, alterando-o de ser imediatamente preciso na inicialização (com bootloader_boot_reason_prop ) para estar disponível somente após a montagem de userdata (com system_boot_reason_prop ).

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

Formato do motivo da inicialização canônica

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:

  • Minúsculas
  • Sem espaços em branco (use sublinhado)
  • Todos os caracteres imprimíveis
  • reason separada por vírgula , subreason e um ou mais detail .
    • Um reason obrigatório que representa o motivo de maior prioridade pelo qual o dispositivo teve que ser reinicializado ou desligado.
    • Um subreason opcional que representa um breve resumo do motivo pelo qual o dispositivo teve que reinicializar ou desligar (ou quem reinicializou ou desligou o dispositivo).
    • Um ou mais valores de detail opcionais. Um detail pode apontar para um subsistema para ajudar a determinar qual sistema específico resultou na subreason . Você pode especificar vários valores de detail , que geralmente devem seguir uma hierarquia de importância. No entanto, também é aceitável relatar vários valores de detail de igual importância.

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

Requisitos de motivo

O valor dado para reason (primeiro intervalo, antes da terminação ou vírgula) deve ser do seguinte conjunto dividido em motivos kernel, fortes e contundentes:

  • conjunto de núcleos:
    • " watchdog"
    • "kernel_panic"
  • conjunto forte:
    • "recovery"
    • "bootloader"
  • conjunto sem corte:
    • "cold" . Geralmente indica uma reinicialização completa de todos os dispositivos, incluindo a memória.
    • "hard" . Geralmente indica que o hardware tem seu estado redefinido e ramoops deve reter conteúdo persistente.
    • "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 ramoops é desconhecido e o estado do hardware é desconhecido. Esse valor é abrangente, pois os valores cold , hard e warm fornecem pistas sobre a profundidade da redefinição do dispositivo.

Os carregadores de inicialização devem fornecer um conjunto de kernel ou um reason de conjunto sem corte e são fortemente encorajados a fornecer um subreason se puder ser determinado. Por exemplo, um pressionamento longo da tecla liga / desliga que pode ou não ter o backup do ramoops teria o motivo da inicialização "reboot,longkey" .

Nenhum reason do primeiro período pode fazer parte de qualquer subreason ou detail . No entanto, como os motivos do conjunto do kernel não podem ser produzidos pelo espaço do usuário, "watchdog" pode ser reutilizado após um motivo definido, juntamente 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 especializado para decifrar e/ou devem ser legíveis por humanos com um relatório intuitivo. Exemplos: "shutdown,vbxd" (ruim), "shutdown,uv" (melhor), "shutdown,undervoltage" (preferencial).

Combinações Razão-Sub-razão

O Android reserva um conjunto de combinações de reason e subreason que não devem ser sobrecarregados em uso normal, mas podem ser usados ​​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 obter mais detalhes, consulte kBootReasonMap em system/core/bootstat/bootstat.cpp e o histórico associado do git changelog no repositório de origem do Android.

Relatando motivos de inicialização

Todos os motivos de inicialização, sejam do carregador de inicialização ou registrados no motivo de inicialização canônico, devem ser registrados na seção kBootReasonMap de system/core/bootstat/bootstat.cpp . A lista kBootReasonMap é uma mistura de motivos de conformidade e não conformidade herdados. Os desenvolvedores de bootloader devem registrar apenas novos motivos de conformidade aqui (e não devem registrar motivos de não conformidade, a menos que o produto já tenha sido enviado e não possa ser alterado).

É altamente recomendável usar entradas existentes e compatíveis em system/core/bootstat/bootstat.cpp e exercer restrição antes de usar uma string não compatível. Como orientação, é:

  • OK para relatar "kernel_panic" do bootloader, pois o bootstat pode inspecionar ramoops para kernel_panic signatures para refinar as sub-razões no sistema canônico system_boot_reason_prop .
  • Não há problema em relatar uma string não compatível no kBootReasonMap (como "panic") do carregador de inicialização, pois isso acabará interrompendo a capacidade de refinar o reason .

Por exemplo, se kBootReasonMap contém "wdog_bark" , um desenvolvedor de bootloader deve:

  • Mude para "watchdog,bark" e adicione à lista em kBootReasonMap .
  • Considere o que "bark" significa para aqueles que não estão familiarizados com a tecnologia e determine se uma subreason mais significativa está disponível.

Verificando a conformidade do motivo da inicialização

No momento, o Android não fornece 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 pode fornecer; os parceiros ainda podem tentar executar um teste passivo para determinar a compatibilidade.

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