Implementar atualizações OTA

Para implementar as atualizações over the air (OTA), o carregador de inicialização 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 na 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 no flash usado para comunicações pela 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 A/B atualizações, 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 do HAL. O carregador de inicialização nunca deve marcar uma partição como inicializada.

Suporte ao HAL de controle de inicialização

O carregador de inicialização precisa oferecer suporte ao 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 usado, muda o slot ativo usando o HAL e reinicializa no sistema operacional atualizado. Para mais detalhes, consulte Implementar o controle de inicialização HAL.

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 a qual slot elas pertencem 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 lançados com o Android 12 ou mais recente.

  • O valor slot-retry-count é redefinido para um valor positivo (geralmente 3) pelo 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 repetições 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 slotting do carregador de inicialização
Figura 1. Fluxo de slots 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 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 ao usuário.

  3. Selecione o boot.img apropriado 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. Inicialize. Se não estiver marcado como slot-successful, diminua slot-retry-count.

O utilitário fastboot determina qual partição atualizar ao executar comandos 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 precisa ser atualizada (system_a, system_b etc.).

Ao definir o slot atual usando o comando set_active do fastboot ou o comando setActiveBootSlot do 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 repetições. 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 gravá-la 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 precisará atualizar o rádio. Isso pode ser feito de duas maneiras:

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

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