O Google usou OTAs A/B em algum dispositivo?
Sim. O nome comercial das atualizações A/B é atualizações contínuas . Os telefones Pixel e Pixel XL de outubro de 2016 são fornecidos com A/B, e todos os Chromebooks usam a mesma implementação update_engine
de A/B. A implementação necessária do código da plataforma é pública no Android 7.1 e superior.
Por que as OTAs A/B são melhores?
As OTAs A/B proporcionam uma melhor experiência do usuário ao receber atualizações. As medições das atualizações mensais de segurança mostram que esse recurso já provou ser um sucesso: em maio de 2017, 95% dos proprietários de Pixel estavam executando a atualização de segurança mais recente após um mês, em comparação com 87% dos usuários do Nexus, e os usuários do Pixel atualizam mais cedo do que os usuários do Nexus. Falhas na atualização de blocos durante um OTA não resultam mais em um dispositivo que não inicializa; até que a nova imagem do sistema seja inicializada com êxito, o Android mantém a capacidade de retornar à imagem anterior do sistema em funcionamento.
Como o A/B afetou os tamanhos das partições do Pixel de 2016?
A tabela a seguir contém detalhes sobre a configuração A/B de envio versus a configuração não A/B testada internamente:
Tamanhos de partição de pixels | A/B | Não A/B |
---|---|---|
Carregador de inicialização | 50*2 | 50 |
Bota | 32*2 | 32 |
Recuperação | 0 | 32 |
Cache | 0 | 100 |
Rádio | 70*2 | 70 |
Fornecedor | 300*2 | 300 |
Sistema | 2048*2 | 4096 |
Total | 5.000 | 4680 |
As atualizações A/B exigem um aumento de apenas 320 MiB em flash, com uma economia de 32 MiB com a remoção da partição de recuperação e outros 100 MiB preservados com a remoção da partição de cache. Isso equilibra o custo das partições B para o bootloader, a partição de inicialização e a partição de rádio. A partição do fornecedor dobrou de tamanho (a grande maioria do aumento de tamanho). A imagem do sistema A/B do Pixel tem metade do tamanho da imagem original do sistema não A/B.
Para as variantes Pixel A/B e não A/B testadas internamente (somente A/B enviadas), o espaço usado diferiu em apenas 320 MiB. Em um dispositivo de 32GiB, isso é pouco menos de 1%. Para um dispositivo de 16GiB isso seria inferior a 2%, e para um dispositivo de 8GiB quase 4% (assumindo que todos os três dispositivos tivessem a mesma imagem de sistema).
Por que você não usou o SquashFS?
Experimentamos o SquashFS, mas não conseguimos atingir o desempenho desejado para um dispositivo de última geração. Não usamos nem recomendamos o SquashFS para dispositivos portáteis.
Mais especificamente, o SquashFS proporcionou uma economia de cerca de 50% no tamanho da partição do sistema, mas a esmagadora maioria dos arquivos bem compactados eram os arquivos .odex pré-compilados. Esses arquivos tinham taxas de compactação muito altas (aproximando-se de 80%), mas a taxa de compactação para o restante da partição do sistema era muito menor. Além disso, o SquashFS no Android 7.0 levantou as seguintes preocupações de desempenho:
- O Pixel tem flash muito rápido em comparação com dispositivos anteriores, mas não tem um grande número de ciclos de CPU extras, portanto, ler menos bytes do flash, mas precisar de mais CPU para E/S, era um gargalo potencial.
- As alterações de E/S que funcionam bem em um benchmark artificial executado em um sistema descarregado às vezes não funcionam bem em casos de uso do mundo real sob carga do mundo real (como criptografia no Nexus 6).
- O benchmarking mostrou regressões de 85% em alguns locais.
À medida que o SquashFS amadurece e adiciona recursos para reduzir o impacto da CPU (como uma lista de permissões de arquivos comumente acessados que não devem ser compactados), continuaremos a avaliá-lo e a oferecer recomendações aos fabricantes de dispositivos.
Como você reduziu pela metade o tamanho da partição do sistema sem o SquashFS?
Os aplicativos são armazenados em arquivos .apk, que na verdade são arquivos ZIP. Cada arquivo .apk contém um ou mais arquivos .dex contendo bytecode Dalvik portátil. Um arquivo .odex (.dex otimizado) reside separadamente do arquivo .apk e pode conter código de máquina específico para o dispositivo. Se um arquivo .odex estiver disponível, o Android poderá executar aplicativos em velocidades compiladas antecipadamente, sem ter que esperar que o código seja compilado sempre que o aplicativo for iniciado. Um arquivo .odex não é estritamente necessário: o Android pode executar o código .dex diretamente por meio de interpretação ou compilação Just-In-Time (JIT), mas um arquivo .odex fornece a melhor combinação de velocidade de inicialização e velocidade de tempo de execução se espaço está disponível.
Exemplo: para o arquivo install-files.txt de um Nexus 6P executando o Android 7.1 com um tamanho total de imagem do sistema de 2.628 MiB (2.755.792.836 bytes), o detalhamento dos maiores contribuidores para o tamanho geral da imagem do sistema por tipo de arquivo é o seguinte:
.odex | 1391770312 bytes | 50,5% |
.apk | 846878259 bytes | 30,7% |
.so (código C/C++ nativo) | 202162479 bytes | 7,3% |
Arquivos .oat/imagens .art | 163892188 bytes | 5,9% |
Fontes | 38952361 bytes | 1,4% |
dados de localidade da UTI | 27468687 bytes | 0,9% |
Esses números também são semelhantes para outros dispositivos, portanto, em dispositivos Nexus/Pixel, os arquivos .odex ocupam aproximadamente metade da partição do sistema. Isso significava que poderíamos continuar a usar o ext4, mas gravar os arquivos .odex na partição B na fábrica e depois copiá-los para /data
na primeira inicialização. O armazenamento real usado com ext4 A/B é idêntico ao SquashFS A/B, porque se tivéssemos usado o SquashFS, teríamos enviado os arquivos .odex pré-optados em system_a em vez de system_b.
Copiar arquivos .odex para/data não significa que o espaço economizado em/system será perdido em/data?
Não exatamente. No Pixel, a maior parte do espaço ocupado pelos arquivos .odex é para aplicativos, que normalmente existem em /data
. Esses aplicativos recebem atualizações do Google Play, portanto, os arquivos .apk e .odex na imagem do sistema não são usados durante a maior parte da vida útil do dispositivo. Esses arquivos podem ser totalmente excluídos e substituídos por pequenos arquivos .odex orientados por perfil quando o usuário realmente usa cada aplicativo (não exigindo, portanto, espaço para aplicativos que o usuário não usa). Para obter detalhes, consulte a palestra do Google I/O 2016, The Evolution of Art .
A comparação é difícil por alguns motivos principais:
- Os aplicativos atualizados pelo Google Play sempre tiveram seus arquivos .odex em
/data
assim que receberam a primeira atualização. - Os aplicativos que o usuário não executa não precisam de um arquivo .odex.
- A compilação orientada por perfil gera arquivos .odex menores do que a compilação antecipada (porque a primeira otimiza apenas código crítico para desempenho).
Para obter detalhes sobre as opções de ajuste disponíveis para OEMs, consulte Configurando o ART .
Não existem duas cópias dos arquivos .odex em/data?
É um pouco mais complicado... Após a gravação da nova imagem do sistema, a nova versão do dex2oat é executada nos novos arquivos .dex para gerar os novos arquivos .odex. Isso ocorre enquanto o sistema antigo ainda está em execução, portanto, os arquivos .odex antigos e novos estão em /data
ao mesmo tempo.
O código em OtaDexoptService ( frameworks/base/+/main/services/core/java/com/android/server/pm/OtaDexoptService.java
) chama getAvailableSpace
antes de otimizar cada pacote para evitar o preenchimento excessivo /data
. Observe que disponível aqui ainda é conservador: é a quantidade de espaço restante antes de atingir o limite normal de espaço baixo do sistema (medido como uma porcentagem e uma contagem de bytes). Portanto, se /data
estiver cheio, não haverá duas cópias de cada arquivo .odex. O mesmo código também possui um BULK_DELETE_THRESHOLD: Se o dispositivo chegar tão perto de preencher o espaço disponível (conforme descrito), os arquivos .odex pertencentes a aplicativos que não são usados serão removidos. Esse é outro caso sem duas cópias de cada arquivo .odex.
Na pior das hipóteses, onde /data
está completamente cheio, a atualização aguarda até que o dispositivo seja reinicializado no novo sistema e não precise mais dos arquivos .odex do sistema antigo. O PackageManager lida com isso: ( frameworks/base/+/main/services/core/java/com/android/server/pm/PackageManagerService.java#7215
). Após a inicialização bem-sucedida do novo sistema, installd
( frameworks/native/+/main/cmds/installd/dexopt.cpp#2422
) pode remover os arquivos .odex que foram usados pelo sistema antigo, retornando o dispositivo ao estado estacionário onde há apenas uma cópia.
Portanto, embora seja possível que /data
contenha duas cópias de todos os arquivos .odex, (a) isso é temporário e (b) só ocorre se você tiver bastante espaço livre em /data
de qualquer maneira. Exceto durante uma atualização, há apenas uma cópia. E como parte dos recursos gerais de robustez do ART, ele nunca preencherá /data
com arquivos .odex de qualquer maneira (porque isso também seria um problema em um sistema não A/B).
Toda essa escrita/cópia não aumenta o desgaste do flash?
Apenas uma pequena parte do flash é reescrita: uma atualização completa do sistema Pixel grava cerca de 2,3 GiB. (Os aplicativos também são recompilados, mas isso também vale para não-A/B.) Tradicionalmente, OTAs completos baseados em blocos gravam uma quantidade semelhante de dados, portanto, as taxas de desgaste do flash devem ser semelhantes.
A atualização de duas partições do sistema aumenta o tempo de atualização de fábrica?
Não. O Pixel não aumentou o tamanho da imagem do sistema (ele apenas dividiu o espaço em duas partições).
Manter os arquivos .odex em B não torna a reinicialização lenta após a redefinição dos dados de fábrica?
Sim. Se você realmente usou um dispositivo, pegou um OTA e executou uma redefinição de dados de fábrica, a primeira reinicialização será mais lenta do que seria (1m40s vs 40s em um Pixel XL) porque os arquivos .odex terão sido perdidos de B após o primeiro OTA e, portanto, não pode ser copiado para /data
. Essa é a compensação.
A redefinição dos dados de fábrica deve ser uma operação rara quando comparada à inicialização normal, portanto o tempo necessário é menos importante. (Isso não afeta usuários ou revisores que recebem seus dispositivos de fábrica, porque nesse caso a partição B está disponível.) O uso do compilador JIT significa que não precisamos recompilar tudo , então não é tão ruim quanto você pode pensar. Também é possível marcar aplicativos como exigindo compilação antecipada usando coreApp="true"
no manifesto: ( frameworks/base/+/main/packages/SystemUI/AndroidManifest.xml#23
). Atualmente é usado por system_server
porque não é permitido JIT por motivos de segurança.
Manter os arquivos .odex em /data em vez de /system torna a reinicialização após um OTA lenta?
Não. Conforme explicado acima, o novo dex2oat é executado enquanto a imagem antiga do sistema ainda está em execução para gerar os arquivos que serão necessários ao novo sistema. A atualização não é considerada disponível até que o trabalho seja concluído.
Podemos (devemos) enviar um dispositivo A/B de 32GiB? 16GiB? 8GiB?
32GiB funciona bem como foi comprovado no Pixel, e 320MiB de 16GiB significa uma redução de 2%. Da mesma forma, 320MiB de 8GiB representa uma redução de 4%. Obviamente A/B não seria a escolha recomendada em dispositivos com 4GiB, já que o overhead de 320MiB representa quase 10% do espaço total disponível.
O AVB2.0 requer OTAs A/B?
Não. O Android Verified Boot sempre exigiu atualizações baseadas em blocos, mas não necessariamente atualizações A/B.
Os OTAs A/B exigem AVB2.0?
Não.
Os OTAs A/B quebram a proteção contra reversão do AVB2.0?
Não. Há alguma confusão aqui porque se um sistema A/B falhar ao inicializar na nova imagem do sistema, ele irá (após algumas tentativas determinadas pelo seu gerenciador de inicialização) reverter automaticamente para a imagem do sistema "anterior". O ponto principal aqui é que "anterior" no sentido A/B ainda é, na verdade, a imagem "atual" do sistema. Assim que o dispositivo inicializar com êxito uma nova imagem, a proteção contra reversão entra em ação e garante que você não poderá voltar atrás. Mas até que você inicialize a nova imagem com êxito, a proteção contra reversão não a considera a imagem atual do sistema.
Se você estiver instalando uma atualização enquanto o sistema está em execução, isso não é lento?
Com atualizações não A/B, o objetivo é instalar a atualização o mais rápido possível porque o usuário está esperando e não pode usar o dispositivo enquanto a atualização é aplicada. Com atualizações A/B, o oposto é verdadeiro; como o usuário ainda está usando seu dispositivo, o objetivo é o menor impacto possível, então a atualização é deliberadamente lenta. Através da lógica do cliente de atualização do sistema Java (que para o Google é GmsCore, o pacote principal fornecido pelo GMS), o Android também tenta escolher um horário em que os usuários não estejam usando seus dispositivos. A plataforma suporta pausar/retomar a atualização, e o cliente pode usar isso para pausar a atualização se o usuário começar a usar o dispositivo e retomá-la quando o dispositivo estiver ocioso novamente.
Existem duas fases ao fazer um OTA, mostradas claramente na IU como Etapa 1 de 2 e Etapa 2 de 2 abaixo da barra de progresso. A etapa 1 corresponde à gravação dos blocos de dados, enquanto a etapa 2 é a pré-compilação dos arquivos .dex. Essas duas fases são bastante diferentes em termos de impacto no desempenho. A primeira fase é E/S simples. Isso requer poucos recursos (RAM, CPU, E/S) porque está apenas copiando blocos lentamente.
A segunda fase executa dex2oat para pré-compilar a nova imagem do sistema. Obviamente, isso tem limites menos claros em seus requisitos porque compila aplicativos reais. E obviamente há muito mais trabalho envolvido na compilação de um aplicativo grande e complexo do que em um aplicativo pequeno e simples; enquanto na fase 1 não há blocos de disco maiores ou mais complexos que outros.
O processo é semelhante a quando o Google Play instala uma atualização de aplicativo em segundo plano antes de mostrar a notificação de atualização de 5 aplicativos , como tem sido feito há anos.
E se um usuário estiver realmente aguardando a atualização?
A implementação atual no GmsCore não faz distinção entre atualizações em segundo plano e atualizações iniciadas pelo usuário, mas poderá fazê-lo no futuro. No caso em que o usuário solicitou explicitamente a instalação da atualização ou está observando a tela de progresso da atualização, priorizaremos o trabalho de atualização presumindo que ele esteja aguardando ativamente que ela termine.
O que acontece se não for possível aplicar uma atualização?
Com atualizações não A/B, se uma atualização não fosse aplicada, o usuário geralmente ficava com um dispositivo inutilizável. A única exceção era se a falha ocorresse antes mesmo de o aplicativo ter sido iniciado (porque o pacote não foi verificado, por exemplo). Com atualizações A/B, a falha na aplicação de uma atualização não afeta o sistema em execução no momento. A atualização pode simplesmente ser tentada novamente mais tarde.
Quais sistemas em um chip (SoCs) suportam A/B?
Em 15/03/2017, temos as seguintes informações:
Android 7.x e anteriores | Android 8.xe posterior | |
Qualcomm | Dependendo das solicitações do OEM | Todos os chipsets receberão suporte |
Mediatek | Dependendo das solicitações do OEM | Todos os chipsets receberão suporte |
Para obter detalhes sobre programações, consulte seus contatos do SoC. Para SoCs não listados acima, entre em contato diretamente com seu SoC.