O Android 10 apresenta o Checkpoint de dados do usuário (UDC), que
permite que o Android seja revertido ao estado anterior quando uma atualização over-the-air
(OTA) falha. Com o UDC, se uma atualização OTA do Android falhar, o dispositivo poderá
ser revertido com segurança ao estado anterior. Embora as atualizações A/B resolvam esse problema para a inicialização antecipada, o rollback não é compatível quando a partição de dados do usuário (montada em /data
) é modificada.
O UDC permite que o dispositivo reverta a partição de dados do usuário mesmo depois de ser modificada. O recurso UDC faz isso com recursos de checkpoint para o sistema de arquivos, uma implementação alternativa quando o sistema de arquivos não é compatível com checkpoints, integração com o mecanismo A/B do carregador de inicialização e suporte a atualizações não A/B, além de suporte para vinculação de versão de chave e prevenção de reversão de chave.
Impacto no usuário
O recurso UDC melhora a experiência de atualização OTA para os usuários, já que menos pessoas perdem os dados quando uma atualização OTA falha. Isso pode reduzir o número de ligações para o suporte de usuários que encontram problemas durante o processo de atualização. No entanto, quando uma atualização OTA falha, os usuários podem notar que o dispositivo é reiniciado várias vezes.
Como funciona
Funcionalidade de checkpoint em diferentes sistemas de arquivos
Para o sistema de arquivos F2FS, o UDC adiciona a funcionalidade de ponto de verificação ao kernel Linux 4.20 upstream e faz o backport para todos os kernels comuns compatíveis com dispositivos que executam o Android 10.
Para outros sistemas de arquivos, a UDC usa um dispositivo virtual de mapeamento de dispositivo chamado dm_bow
para a funcionalidade de ponto de verificação. O dm_bow
fica entre o dispositivo e o sistema de arquivos. Quando uma partição é montada, um corte é emitido, fazendo com que o sistema de arquivos
emita comandos de corte em todos os blocos livres. O dm_bow
intercepta esses cortes e os usa para configurar uma lista de bloqueio sem custo financeiro. As leituras e gravações são enviadas ao dispositivo
sem modificações, mas antes de uma gravação ser permitida, os dados necessários para uma restauração são armazenados
em um bloco livre.
Processo de checkpoint
Quando uma partição com a flag checkpoint=fs/block
é montada, o Android chama
restoreCheckpoint
na unidade para permitir que o dispositivo restaure qualquer
checkpoint atual. Em seguida, init
chama a função needsCheckpoint
para determinar se
o dispositivo está em um estado A/B do carregador de inicialização ou se definiu a contagem
de novas tentativas de atualização. Se uma delas for verdadeira, o Android vai chamar createCheckpoint
para adicionar flags de montagem ou criar um dispositivo dm_bow
.
Depois que a partição é montada, o código de checkpoint é chamado para emitir remoções.
O processo de inicialização continua normalmente. Em LOCKED_BOOT_COMPLETE
, o Android
chama commitCheckpoint
para confirmar o checkpoint atual e a atualização
continua normalmente.
Gerenciar chaves do KeyMint (antigo Keymaster)
As chaves do KeyMint são usadas para criptografia de dispositivos ou outras finalidades. Para gerenciar essas chaves, o Android atrasa as chamadas de exclusão até que o ponto de verificação seja confirmado.
Monitorar a integridade
Um daemon de integridade verifica se há espaço em disco suficiente para criar um
ponto de verificação. O daemon de integridade está localizado em
cp_healthDaemon
em Checkpoint.cpp
.
O daemon de integridade tem os seguintes comportamentos que podem ser configurados:
ro.sys.cp_msleeptime
: controla a frequência com que o dispositivo verifica o uso do disco.ro.sys.cp_min_free_bytes
: controla o valor mínimo que o daemon de integridade procura.ro.sys.cp_commit_on_full
: controla se o daemon de integridade reinicializa o dispositivo ou confirma o ponto de verificação e continua quando o disco está cheio.
APIs de ponto de verificação
As APIs de ponto de verificação são usadas pelo recurso UDC. Para outras APIs usadas pela UDC, consulte
IVold.aidl
.
void startCheckpoint(int retry)
Cria um checkpoint.
O framework chama esse método quando está pronto para iniciar uma atualização. O
checkpoint é criado antes que os sistemas de arquivos com checkpoint, como userdata, sejam
montados R/W após a reinicialização. Se a contagem de novas tentativas for positiva, a API vai processar
novas tentativas de rastreamento, e o atualizador vai chamar needsRollback
para verificar se um rollback
da atualização é necessário. Se a contagem de novas tentativas for -1
, a API vai adiar a decisão para o carregador de inicialização
A/B.
Esse método não é chamado ao fazer uma atualização normal de A/B.
void commitChanges()
Faz commit das mudanças.
O framework chama esse método após a reinicialização quando as mudanças estão prontas para serem
confirmadas. Isso é chamado antes que os dados (como fotos, vídeos, SMS, recebimento
pelo servidor) sejam gravados em userdata e antes de BootComplete
.
Se não houver uma atualização com checkpoint ativa, esse método não terá efeito.
abortChanges()
Força a reinicialização e reverte para o checkpoint. Abandona todas as modificações de dados do usuário desde a primeira reinicialização.
O framework chama esse método após a reinicialização, mas antes de commitChanges
.
retry_counter
é reduzido quando esse método é chamado. As entradas de registro são geradas.
bool needsRollback()
Determina se uma reversão é necessária.
Em dispositivos que não são de checkpoint, retorna false
. Em dispositivos de checkpoint, retorna true
durante uma inicialização sem checkpoint.
Implementar a UDC
Implementação de referência
Para um exemplo de como a UDC pode ser implementada, consulte dm-bow.c. Para mais documentação sobre o recurso, consulte dm-bow.txt.
Configurar
Em on fs
no arquivo init.hardware.rc
, verifique se você tem:
mount_all /vendor/etc/fstab.${ro.boot.hardware.platform} --early
Em on late-fs
no arquivo init.hardware.rc
, verifique se você tem:
mount_all /vendor/etc/fstab.${ro.boot.hardware.platform} --late
No arquivo fstab.hardware
, verifique se /data
está marcado como latemount
.
/dev/block/bootdevice/by-name/userdata /data f2fs noatime,nosuid,nodev,discard,reserve_root=32768,resgid=1065,fsync_mode=nobarrier latemount,wait,check,fileencryption=ice,keydirectory=/metadata/vold/metadata_encryption,quota,formattable,sysfs_path=/sys/devices/platform/soc/1d84000.ufshc,reservedsize=128M,checkpoint=fs
Adicionar partição de metadados
A UDC exige uma partição de metadados para armazenar a contagem de novas tentativas sem carregador de inicialização e
chaves. Configure uma partição de metadados e faça a montagem antecipada em /metadata
.
No arquivo fstab.hardware
, verifique se /metadata
está marcado como earlymount
ou first_stage_mount
.
/dev/block/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard,sync wait,formattable,first_stage_mount
Inicialize a partição com todos os zeros.
Adicione as linhas abaixo a BoardConfig.mk
:
BOARD_USES_METADATA_PARTITION := true BOARD_ROOT_EXTRA_FOLDERS := existing_folders metadata
Atualizar sistemas
Sistemas F2FS
Para sistemas que usam o F2FS para formatar dados, verifique se a versão do F2FS é compatível com pontos de verificação. Para mais informações, consulte Funcionalidade de ponto de verificação em diferentes sistemas de arquivos.
Adicione a flag checkpoint=fs
à seção <fs_mgr_flags>
do fstab para o
dispositivo montado em /data
.
Sistemas não F2FS
Para sistemas que não são F2FS, dm-bow
precisa estar ativado na configuração do kernel.
Adicione a flag checkpoint=block
à seção <fs_mgr_flags>
do fstab para o
dispositivo montado em /data
.
Verificar registros
As entradas de registro são geradas quando as APIs Checkpoint são chamadas.
Validação
Para testar a implementação da UDC, execute o conjunto VtsKernelCheckpointTest
de testes do VTS.