Motivo de inicialização canônica

O Android 9 inclui as seguintes alterações na especificação do motivo de inicialização do bootloader.

Razões de inicialização

Um bootloader 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 sua inicialização. init então traduz esta linha de comando para propagar para a propriedade bootloader_boot_reason_prop do Android ( ro.boot.bootreason ). Para dispositivos iniciados com Android 12 ou posterior, usando o 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 fazia concessões para outros motivos exclusivos. Essa especificação frouxa resultou na proliferação de centenas de cadeias de caracteres 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 impossível de analisar 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 legado bootloader_boot_reason_prop 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 desenvolvedores do bootloader e ajustes no sistema existente. Para esse fim, a equipe do Android é:

  • Envolver-se com desenvolvedores de bootloader para incentivá-los a:
    • Forneça razões canônicas, 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.
  • Informar aos usuários o motivo da inicialização para aguardar até que o userdata seja montado antes de confiar no conteúdo da 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 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 precisarão acessar essas informações. Uma API refinada, analisável e canônica para motivo de inicialização via system_boot_reason_prop pode ser obtida de maneira confiável e precisa somente após a montagem dos dados do usuário. Especificamente:

  • Antes da montagem do userdata, system_boot_reason_prop conterá o valor de bootloader_boot_reason_prop .
  • Após a montagem do 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 do 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 controlados de reinicialização e desligamento, o que, por sua vez, refina e expande a precisão e o significado de system_boot_reason_prop .

Formato de 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:

  • Minúsculas
  • Sem espaços em branco (use sublinhado)
  • Todos os caracteres imprimíveis
  • reason separado por vírgula, subreason e um ou mais detail (s).
    • 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 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 . Você pode especificar vários valores detail , que geralmente devem seguir uma hierarquia de importância. No entanto, também é aceitável reportar vários valores detail de igual importância.

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

Requisitos de motivo

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

  • conjunto de kernel:
    • " watchdog"
    • "kernel_panic"
  • conjunto forte:
    • "recovery"
    • "bootloader"
  • conjunto contundente:
    • "cold" . Geralmente indica uma reinicialização completa de todos os dispositivos, incluindo a memória.
    • "hard" . Geralmente indica que o hardware teve 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. Este valor é genérico, 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 conjunto contundente de reason e são fortemente encorajados a fornecer um subreason , se puder ser determinado. Por exemplo, pressionar longamente a tecla liga / desliga que pode ou não ter backup ramoops teria o motivo de inicialização "reboot,longkey" .

Nenhuma reason de primeiro período pode fazer parte de qualquer subreason ou detail . No entanto, como os motivos definidos pelo kernel não podem ser produzidos pelo espaço do usuário, "watchdog" pode ser reutilizado após um motivo definido contundente, junto com um detalhe da fonte (por exemplo "reboot,watchdog,service_manager_unresponsive" ou "reboot,software,watchdog" ).

Os motivos da inicialização não devem exigir conhecimento interno especializado para serem decifrados 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-Subrazão

O Android reserva um conjunto de combinações reason e subreason que não devem ser sobrecarregados no 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 de changelog do git associado no repositório de origem do Android.

Relatando motivos de inicialização

Todos os motivos de inicialização, seja 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 de não conformidade legados. Os desenvolvedores do bootloader devem registrar aqui apenas novos motivos de conformidade (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).

Recomendamos fortemente o uso de entradas compatíveis existentes em system/core/bootstat/bootstat.cpp e o exercício de moderação antes de usar uma string não compatível. Como orientação, é:

  • OK para relatar "kernel_panic" do bootloader, pois bootstat pode inspecionar ramoops em busca de kernel_panic signatures para refinar os submotivos no canônico system_boot_reason_prop .
  • Não é correto relatar uma string não compatível em kBootReasonMap (como "panic") do carregador de inicialização, pois isso acabará prejudicando 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 quem não está familiarizado com a tecnologia e determine se um subreason mais significativo está disponível.

Verificando a conformidade do motivo de 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 bootloader pode fornecer; os parceiros ainda podem tentar executar um teste passivo para determinar a compatibilidade.

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