Implementar atualizações OTA

Para implementar as atualizações OTA (over-the-air), o bootloader precisa acessar um disco RAM de recuperação durante a inicialização. Se o dispositivo usar uma imagem de recuperação do AOSP não modificada, o carregador de inicialização vai ler os primeiros 32 bytes na partição misc. Se os dados corresponderem a boot-recovery, o carregador de inicialização vai inicializar a imagem recovery. Esse método permite que qualquer trabalho de recuperação pendente (por exemplo, aplicar uma OTA ou remover dados) continue até a conclusão.

Para detalhes sobre o conteúdo de um bloco na memória flash usado para comunicações por recuperação e o carregador de inicialização, consulte bootable/recovery/bootloader_message/bootloader_message.h.

Dispositivos com atualizações A/B

Para oferecer suporte a atualizações OTA em dispositivos que usam atualizações A/B, verifique se o carregador de inicialização do dispositivo atende aos seguintes critérios.

Critérios gerais

  • Todas as partições atualizadas por uma OTA precisam ser atualizáveis enquanto o sistema principal está inicializado (e não atualizado na recuperação).

  • Para inicializar a partição system, o carregador de inicialização transmite o seguinte valor na linha de comando do kernel: ro root=/dev/[node] rootwait init=/init.

  • É responsabilidade do framework do Android chamar markBootSuccessful da HAL. O carregador de inicialização nunca deve marcar uma partição como inicializada com sucesso.

Suporte para HAL de controle de inicialização

O carregador de inicialização precisa ser compatível com a HAL boot_control, conforme definido em hardware/libhardware/include/hardware/boot_control.h. O atualizador consulta o HAL de controle de inicialização, atualiza o slot de inicialização não utilizado, muda o slot ativo usando o HAL e reinicializa o sistema operacional atualizado. Para mais detalhes, consulte Implementar o HAL de controle de inicialização.

Suporte para slots

O carregador de inicialização precisa oferecer suporte a funcionalidades relacionadas a partições e slots, incluindo:

  • Os nomes das partições precisam incluir um sufixo que identifique a qual slot do carregador de inicialização elas pertencem. Para cada partição, há uma variável correspondente has-slot:partition base name com um valor de yes. Os slots são nomeados em ordem alfabética como a, b, c etc., correspondendo a partições com o sufixo _a, _b, _c etc. O carregador de inicialização precisa informar ao sistema operacional qual slot foi inicializado usando a propriedade da linha de comando androidboot.slot_suffix. Essa propriedade é definida pelo bootconfig para dispositivos lançados com o Android 12 ou mais recente.

  • O valor slot-retry-count é redefinido para um valor positivo (geralmente 3), pela HAL de controle de inicialização usando o callback setActiveBootSlot ou pelo comando fastboot set_active. Ao modificar uma partição que faz parte de um slot, o carregador de inicialização limpa "inicializado com sucesso" e redefine a contagem de novas tentativas do slot.

O carregador de inicialização também precisa determinar qual slot carregar. A figura mostra um exemplo de processo de decisão.

Fluxo de slot do carregador de inicialização
Figura 1. Fluxo de slot do carregador de inicialização
  1. Determine qual slot tentar. Não tente carregar um slot marcado como slot-unbootable. Esse slot precisa ser consistente com os valores retornados pelo fastboot e é chamado de slot atual.

  2. Se o slot atual não estiver marcado como slot-successful e tiver um slot-retry-count = 0, marque o slot atual como slot-unbootable. Em seguida, selecione um slot diferente que não esteja marcado como unbootable e esteja marcado como slot-successful. Esse slot agora é o selecionado. Se nenhum slot atual estiver disponível, inicialize a recuperação ou mostre uma mensagem de erro significativa para o usuário.

  3. Selecione o boot.img adequado e inclua o caminho para a partição do sistema correta na linha de comando do kernel.

  4. Preencha o parâmetro slot_suffix da linha de comando do kernel.

  5. Inicializar. Se não estiver marcado como slot-successful, diminua slot-retry-count.

O utilitário fastboot determina qual partição será atualizada ao executar qualquer comando de atualização. Por exemplo, executar o comando fastboot flash system system.img primeiro consulta a variável current-slot e depois concatena o resultado ao sistema para gerar o nome da partição que deve ser atualizada (system_a, system_b etc.).

Ao definir o slot atual usando o comando fastboot set_active ou o comando HAL de controle de inicialização setActiveBootSlot, o carregador de inicialização precisa atualizar o slot atual, limpar slot-unbootable e slot-successful e redefinir a contagem de novas tentativas. Essa é a única maneira de limpar slot-unbootable.

Dispositivos sem atualizações A/B

Para oferecer suporte a atualizações OTA em dispositivos que não usam atualizações A/B (consulte Dispositivos atualizáveis não A/B), verifique se o carregador de inicialização do dispositivo atende aos seguintes critérios.

  • A partição recovery precisa conter uma imagem capaz de ler uma imagem do sistema de alguma partição compatível (cache, userdata) e gravar na partição system.

  • O carregador de inicialização precisa oferecer suporte à inicialização direta no modo de recuperação.

  • Se as atualizações de imagem de rádio forem compatíveis, a partição recovery também poderá atualizar o rádio. Isso pode ser feito de duas maneiras:

    • O carregador de inicialização pisca o rádio. Nesse caso, é possível reiniciar da partição de recuperação de volta ao carregador de inicialização para concluir a atualização.

    • A imagem de recuperação pisca o rádio. Essa funcionalidade pode ser fornecida como uma biblioteca ou utilitário binário.