Para implementar A/B virtual em um novo dispositivo ou para adaptar um dispositivo iniciado, você deve fazer alterações no código específico do dispositivo.
Construir sinalizadores
Os dispositivos que usam A/B virtual devem ser configurados como um dispositivo A/B e devem ser iniciados com partições dinâmicas .
Para dispositivos iniciados com A/B virtual, defina-os para herdar a configuração básica do dispositivo A/B virtual:
$(call inherit-product, \
$(SRC_TARGET_DIR)/product/virtual_ab_ota.mk)
Dispositivos lançados com A/B virtual precisam apenas da metade do tamanho da placa para BOARD_SUPER_PARTITION_SIZE
porque os slots B não estão mais em super. Ou seja, BOARD_SUPER_PARTITION_SIZE
deve ser maior ou igual a sum(size of update groups) + overhead , que, por sua vez, deve ser maior ou igual a sum(size of partitions) + overhead .
Para habilitar snapshots compactados com Virtual A/B, herde a seguinte configuração básica:
$(call inherit-product, \
$(SRC_TARGET_DIR)/product/virtual_ab_ota/compression.mk)
Controle de inicialização HAL
O controle de inicialização HAL fornece uma interface para clientes OTA controlarem os slots de inicialização. O A/B virtual requer uma atualização de versão secundária do HAL de controle de inicialização porque APIs adicionais são necessárias para garantir que o carregador de inicialização seja protegido durante o flashing/redefinição de fábrica. Consulte IBootControl.hal e types.hal para obter a versão mais recente da definição HAL.
// hardware/interfaces/boot/1.1/types.hal
enum MergeStatus : uint8_t {
NONE, UNKNOWN, SNAPSHOTTED, MERGING, CANCELLED };
// hardware/interfaces/boot/1.1/IBootControl.hal
package android.hardware.boot@1.1;
interface IBootControl extends @1.0::IBootControl {
setSnapshotMergeStatus(MergeStatus status)
generates (bool success);
getSnapshotMergeStatus()
generates (MergeStatus status);
}
// Recommended implementation
Return<bool> BootControl::setSnapshotMergeStatus(MergeStatus v) {
// Write value to persistent storage
// e.g. misc partition (using libbootloader_message)
// bootloader rejects wipe when status is SNAPSHOTTED
// or MERGING
}
Mudanças de Fstab
A integridade da partição de metadados é essencial para o processo de inicialização, especialmente logo após a aplicação de uma atualização OTA. Portanto, a partição de metadados deve ser verificada antes que first_stage_init
a monte. Para garantir que isso aconteça, adicione o sinalizador check
fs_mgr à entrada para /metadata
. O seguinte fornece um exemplo:
/dev/block/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard,sync wait,formattable,first_stage_mount,check
Requisitos do kernel
Para habilitar o snapshot, defina CONFIG_DM_SNAPSHOT
como true
.
Para dispositivos que usam F2FS, inclua o sinalizador f2fs: export FS_NOCOW_FL para o patch do kernel do usuário para corrigir a fixação do arquivo. Inclua o f2fs: suporte ao patch de kernel de arquivo fixado alinhado também.
O A/B virtual conta com recursos adicionados no kernel versão 4.3: o bit de status de estouro no snapshot
e destinos snapshot-merge
. Todos os dispositivos iniciados com Android 9 e posterior já devem ter a versão 4.4 ou posterior do kernel.
Para habilitar instantâneos compactados, a versão mínima do kernel com suporte é 4.19. Defina CONFIG_DM_USER=m
ou CONFIG_DM_USER=y
. Se estiver usando o primeiro (um módulo), o módulo deve ser carregado no ramdisk do primeiro estágio. Isso pode ser feito adicionando a seguinte linha ao Makefile do dispositivo:
BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko
Retrofit em dispositivos que atualizam para o Android 11
Ao atualizar para o Android 11, os dispositivos iniciados com partições dinâmicas podem adaptar opcionalmente o A/B virtual. O processo de atualização é basicamente o mesmo para dispositivos iniciados com A/B virtual, com algumas pequenas diferenças:
Localização dos arquivos COW — Para dispositivos de inicialização, o cliente OTA usa todo o espaço vazio disponível na superpartição antes de usar o espaço em
/data
. Para dispositivos de retrofit, sempre há espaço suficiente na superpartição para que o arquivo COW nunca seja criado em/data
.Sinalizadores de recursos em tempo de compilação — para dispositivos que adaptam A/B virtual, tanto
PRODUCT_VIRTUAL_AB_OTA
quantoPRODUCT_VIRTUAL_AB_OTA_RETROFIT
são definidos comotrue
, conforme mostrado abaixo:(call inherit-product, \
(SRC_TARGET_DIR)/product/virtual_ab_ota_retrofit.mk)
Tamanho da superpartição — Dispositivos iniciados com A/B virtual podem cortar
BOARD_SUPER_PARTITION_SIZE
pela metade porque os slots B não estão na superpartição. Os dispositivos que adaptam o A/B virtual mantêm o antigo tamanho da superpartição, entãoBOARD_SUPER_PARTITION_SIZE
é maior ou igual a 2 * sum(size of update groups) + overhead , que por sua vez é maior ou igual a 2 * sum(size of partitions) + sobrecarga .
Alterações do carregador de inicialização
Durante a etapa de mesclagem de uma atualização, /data
contém a única instância inteira do sistema operacional Android. Depois que a migração é iniciada, as partições nativas do system
, vendor
e product
ficam incompletas até que a cópia seja concluída. Se o dispositivo for redefinido de fábrica durante esse processo, seja por recuperação ou por meio da caixa de diálogo de configurações do sistema, o dispositivo não poderá ser inicializado.
Antes de apagar /data
, finalize a mesclagem em recuperação ou reversão dependendo do estado do dispositivo:
- Se a nova compilação inicializou com êxito antes, conclua a migração.
- Caso contrário, volte para o slot antigo:
- Para partições dinâmicas, retorne ao estado anterior.
- Para partições estáticas, defina o slot ativo para o slot antigo.
Tanto o bootloader quanto o fastbootd
podem apagar a partição /data
se o dispositivo estiver desbloqueado. Embora fastbootd
possa forçar a conclusão da migração, o bootloader não pode. O bootloader não sabe se uma mesclagem está em andamento ou quais blocos em /data
constituem as partições do SO. Os dispositivos devem impedir que o usuário inconscientemente torne o dispositivo inoperável (bricking) fazendo o seguinte:
- Implemente o HAL de controle de inicialização para que o carregador de inicialização possa ler o valor definido pelo método
setSnapshotMergeStatus()
. - Se o status de mesclagem for
MERGING
, ou se o status de mesclagem forSNAPSHOTTED
e o slot tiver mudado para o slot recém-atualizado, as solicitações para limparuserdata
,metadata
ou a partição que armazena o status de mesclagem devem ser rejeitadas no carregador de inicialização. - Implemente o comando
fastboot snapshot-update cancel
para que os usuários possam sinalizar ao bootloader que desejam ignorar esse mecanismo de proteção. - Modifique as ferramentas ou scripts de flash personalizados para emitir
fastboot snapshot-update cancel
ao fazer o flash de todo o dispositivo. Isso é seguro para emitir porque a atualização de todo o dispositivo remove o OTA. As ferramentas podem detectar esse comando em tempo de execução implementandofastboot getvar snapshot-update-status
. Este comando ajuda a diferenciar entre as condições de erro.
Exemplo
struct VirtualAbState {
uint8_t StructVersion;
uint8_t MergeStatus;
uint8_t SourceSlot;
};
bool ShouldPreventUserdataWipe() {
VirtualAbState state;
if (!ReadVirtualAbState(&state)) ...
return state.MergeStatus == MergeStatus::MERGING ||
(state.MergeStatus == MergeStatus::SNAPSHOTTED &&
state.SourceSlot != CurrentSlot()));
}
Mudanças nas ferramentas do Fastboot
O Android 11 faz as seguintes alterações no protocolo fastboot:
-
getvar snapshot-update-status
— Retorna o valor que o controle de inicialização HAL comunicou ao bootloader:- Se o estado for
MERGING
, o carregador de inicialização deve retornarmerging
. - Se o estado for
SNAPSHOTTED
, o carregador de inicialização deverá retornarsnapshotted
. - Caso contrário, o bootloader deve retornar
none
.
- Se o estado for
-
snapshot-update merge
— Conclui uma operação de merge, inicializando para recovery/fastbootd se necessário. Este comando é válido somente sesnapshot-update-status
formerging
e só tem suporte em fastbootd. -
snapshot-update cancel
— Configura o status de mesclagem do HAL do controle de inicialização paraCANCELLED
. Este comando é inválido quando o dispositivo está bloqueado. -
erase
orwipe
— Umerase
ouwipe
demetadata
,userdata
ou uma partição que mantém o status de mesclagem para o controle de inicialização HAL deve verificar o status de mesclagem do instantâneo. Se o status forMERGING
ouSNAPSHOTTED
, o dispositivo deverá abortar a operação. -
set_active
— Um comandoset_active
que altera o slot ativo deve verificar o status de mesclagem do instantâneo. Se o status forMERGING
, o dispositivo deve abortar a operação. O slot pode ser alterado com segurança no estadoSNAPSHOTTED
.
Essas alterações foram projetadas para evitar que um dispositivo não inicialize acidentalmente, mas podem prejudicar as ferramentas automatizadas. Quando os comandos são usados como um componente de flash de todas as partições, como executar fastboot flashall
, é recomendável usar o seguinte fluxo:
- Consulte
getvar snapshot-update-status
. - Se
merging
ou tirar umsnapshotted
, emitasnapshot-update cancel
. - Prossiga com as etapas piscando.
Reduzindo os requisitos de armazenamento
Dispositivos que não possuem armazenamento A/B completo alocado em super e esperam usar /data
conforme necessário, são altamente recomendados para usar a ferramenta de mapeamento de blocos. A ferramenta de mapeamento de bloco mantém a alocação de bloco consistente entre compilações, reduzindo gravações desnecessárias no instantâneo. Isso está documentado em Reduzir o tamanho de OTA .