Implementar atualizações OTA

Para implementar as atualizações over-the-air (OTA), o bootloader precisa acessar um disco RAM de recuperação durante a inicialização. Se o dispositivo usar uma imagem de recuperação 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 será inicializado na imagem recovery. Esse método permite que qualquer trabalho de recuperação pendente (por exemplo, a aplicação de uma OTA ou a remoção de dados) continue até a conclusão.

Para detalhes sobre o conteúdo de um bloco em flash usado para comunicações por recuperação e pelo 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 OTA precisam ser atualizáveis enquanto o sistema principal é inicializado, e não atualizada 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 do HAL. O carregador de inicialização nunca deve marcar uma partição como inicializada com êxito.

Suporte para HAL de controle de inicialização

O carregador de inicialização precisa oferecer suporte à 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 que não está em uso, muda o slot ativo usando o HAL e reinicia no sistema operacional atualizado. Para saber mais, consulte Como implementar o HAL de controle de inicialização.

Suporte a 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 quais partições pertencem a um slot específico no carregador de inicialização. Para cada partição, há uma variável correspondente has-slot:partition base name com um valor de yes. Os slots são nomeados alfabeticamente 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 de linha de comando androidboot.slot_suffix. Essa propriedade é definida pelo bootconfig para dispositivos que são iniciados com o Android 12 ou mais recente.

  • O valor slot-retry-count é redefinido para um valor positivo (normalmente 3), pelo HAL de controle de inicialização pelo 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 a "inicialização com sucesso" e redefine a contagem de novas tentativas do slot.

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

Fluxo de alocação do carregador de inicialização
Figura 1. Fluxo de ranqueamento 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 como slot-unbootable. Em seguida, selecione outro slot que não esteja marcado como unbootable e que 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 apropriado e inclua o caminho para corrigir a partição do sistema na linha de comando do kernel.

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

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

O utilitário fastboot determina qual partição atualizar 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, em seguida, concatena o resultado ao sistema para gerar o nome da partição que será atualizada (system_a, system_b etc.).

Ao configurar o slot atual usando o comando set_active do fastboot ou o comando setActiveBootSlot da HAL de controle de inicialização, 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 não atualizáveis 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 com suporte (cache, userdata) e gravá-la na partição system.

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

  • Se as atualizações de imagem do 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 para o 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.