O Google está trabalhando no APEX: atualizando as bibliotecas do sistema como uma distribuição Linux padrão. Esperado no Android Q, o APEX pode ser o maior sucesso desde o Projeto Treble.
A implementação do APEX é provavelmente a maior dor de cabeça que o Google enfrentou desde a introdução do Projeto Treble. O que é APEX e como sua introdução mudará o Android?
A ideia por trás do APEX por si só é bastante comum nas distribuições GNU/Linux cotidianas: atualizações de pacotes direcionadas a seções específicas do conjunto de bibliotecas Linux. Mas isso é algo que o Google nunca tentou fazer, já que o Android usou uma partição RO (somente leitura) onde todas as bibliotecas do sistema e frameworks são armazenados em comparação com as partições RW (leitura-gravação) usuais usadas na maioria das distribuições Linux, tornando o processo de atualização padrão inadequado.
Bibliotecas são códigos pré-compilados que podem ser usados em outros programas. Os métodos comumente usados podem ser transformados em bibliotecas para chamadas de aplicativos Android, reduzindo o tamanho dos APKs, pois o mesmo código não precisará ser reimplementado em vários aplicativos. Você pode encontrar muitas bibliotecas de sistema pré-instaladas nos diretórios /system/lib e /system/lib64. As bibliotecas do sistema Android geralmente não são atualizadas individualmente; em vez disso, elas são atualizadas como parte das atualizações das plataformas Android por meio de uma atualização OTA. Por outro lado, as bibliotecas nas distribuições Linux podem ser atualizadas individualmente. Com a introdução do APEX, as bibliotecas do sistema no Android podem ser atualizadas individualmente, como os aplicativos Android. O principal benefício disso é que os desenvolvedores de aplicativos poderão aproveitar as vantagens das bibliotecas atualizadas sem esperar que um OEM implemente uma atualização completa do sistema. Vamos mergulhar em mais detalhes técnicos sobre como funciona o APEX.
Como o APEX mudará a forma como as bibliotecas são atualizadas?
APEX é um ecossistema que forçou (ou melhor, está forçando) o Google a reconsiderar a forma como o Android carrega todas as bibliotecas e arquivos de uma partição não padrão diferente de /system.
Primeiro de tudo, temos que especificar a diferença entre uma biblioteca compartilhada e uma biblioteca estática. Uma biblioteca compartilhada é uma biblioteca (geralmente um arquivo chamado libkind.so) que não inclui todo o código necessário para ser executado, mas está “vinculado” a outras bibliotecas, na verdade. fornecendo o código, enquanto uma biblioteca estática é, como você pode imaginar, uma biblioteca que não depende de nenhuma outra biblioteca e tem tudo incluído estaticamente dentro do arquivo.
O Android configurou historicamente o caminho da biblioteca (conhecido como LD_LIBRARY_PATH no mundo Linux) com um único arquivo chamado ld.config.txt [0] para configurar os caminhos de pesquisa permitidos para as bibliotecas compartilhadas necessárias para o binário ou outro biblioteca. Esses caminhos são codificados na configuração e não são expansíveis. Esse layout, incluindo a partição do sistema somente leitura, leva a bibliotecas não atualizáveis, a menos que o usuário instale uma atualização OTA do Android. O Google corrigiu esse problema, permitindo estender o caminho de pesquisa, permitindo que os pacotes APEX únicos fornecessem seu próprio ld.config.txt que incluía os caminhos de bibliotecas extras (e atualizados) contidos neles.
Embora esta mudança tenha resolvido um dos principais problemas, ainda havia alguns problemas sérios a superar. Em primeiro lugar: estabilidade da ABI (interface binária do aplicativo). As bibliotecas devem sempre exportar um conjunto estável de interfaces para permitir que outros aplicativos e bibliotecas continuem a funcionar com o mesmo protocolo, mesmo com a biblioteca atualizada. O Google está trabalhando ativamente nisso, tentando criar uma interface C estável entre bibliotecas APEX.
Mas um APEX não se limita apenas a bibliotecas e binários. Na verdade, ele pode conter arquivos de configuração, atualizações de fuso horário e algumas estruturas Java (concriptadas no momento da escrita).
Aqui estão alguns exemplos dos pacotes APEX atuais fornecidos pelo AOSP:
- com.android.runtime: ART e tempo de execução biônico (binários e bibliotecas)
- com.android.tzdata: dados de fuso horário e ICU (bibliotecas e dados de configuração)
- com.android.resolv: Biblioteca usada pelo Android para resolver solicitações relacionadas à rede (bibliotecas)
- com.android.conscrypt: um provedor de segurança Java (estrutura Java)
Como um pacote APEX é instalado e estruturado?
Um pacote APEX é um arquivo zip simples (como um APK) que pode ser instalado pelo nosso prático ADB (neste ponto de desenvolvimento) e, posteriormente, pelo próprio usuário através de um gerenciador de pacotes (como o Google Play ou manualmente através do pacote Android instalador).
O layout do ZIP é o seguinte:
Vamos mergulhar nisso.
O apex_manifest.json especifica o nome e a versão do pacote.
O apex_payload.img é uma imagem de micro-sistema de arquivos (formatada como EXT4).
Os demais arquivos fazem parte do processo de verificação usado para instalar o pacote. Vamos dar uma olhada.
A presença de AndroidManifest.xml, mesmo que seja usado principalmente em aplicativos, nos ajuda a entender que grande parte da implementação usada para uma instalação padrão de APK é reutilizada até mesmo para esses pacotes. Na verdade, apenas a extensão está sendo verificada para diferenciá-los.
O META-INF/ diretório possui o certificado do pacote e usa o mesmo mecanismo dos APKs normais. Então esses pacotes são verificados por um par de chaves privada/pública em tempo de execução antes que o usuário tenha permissão para instalar uma atualização. Mas isso não foi suficiente para o Google, então eles adicionaram mais duas camadas de segurança. Eles estão usando dm-verity para verificar a integridade da imagem e verificações AVB (Android Verified Boot) para garantir que a imagem venha de uma fonte confiável. Na pior das hipóteses, o pacote APEX será rejeitado.
Se todas as etapas de verificação forem bem-sucedidas, a imagem será marcada como válida e substituirá a variante do sistema na próxima reinicialização.
Como uma imagem é instalada na inicialização?
Vamos começar dando uma olhada nos APEXes atualmente instalados no meu dispositivo (um emulador)
Como você pode ver, os pacotes pré-instalados estão armazenados em /system/apex/ e todos eles estão atualmente na versão número 1. Mas o que acontece quando um APEX é ativado? Usaremos novamente com.android.tzdata como exemplo.
Vamos reiniciar o dispositivo e analisar o logcat.
As primeiras 2 linhas fornecem informações suficientes para entender a origem do pacote e onde ele irá instalado: /apex/, um novo diretório introduzido no Android Q que será usado para armazenar o ativado pacotes.
Após o pacote ter sido verificado com sucesso com AVB e a chave pública corresponder, o APEX é montado usando um dispositivo de loop em /dev/block/loop0, tornando o sistema de arquivos EXT4 acessível ao sistema. Um dispositivo de loop é um pseudodispositivo que torna um arquivo acessível como um dispositivo de bloco, tornando o conteúdo desse arquivo acessível como um ponto de montagem.
Neste ponto, o APEX ainda não é utilizado por causa do sufixo @1 (que indica a versão do pacote). Para finalmente informar ao sistema que nosso pacote foi ativado com sucesso, ele será montado em /apex/com.android.tzdata, onde o Android espera ativamente que o tzdata esteja ativo. Uma montagem vinculada sobrepõe um diretório ou arquivo existente em um ponto diferente. [1]
A implementação do APEX está inteiramente contida em um único repositório no AOSP. [2] O diretório apexd (daemon APEX) possui o código em execução no Android. O diretório apexer contém o código usado pelo sistema de compilação para criar os pacotes APEX.
Qual é o propósito?
Neste ponto, tudo que posso fazer é especular. Meu melhor palpite é que o Google está tentando criar um conjunto básico de pacotes APEX que podem ser atualizados pelo Google para possivelmente criar um núcleo base unificado do Android compartilhado entre fornecedores, tornando possíveis apenas atualizações do “sistema”, mas usando um único pacote atualizações.
Todos os dispositivos serão compatíveis com APEX?
Não. Por exemplo, o apexd requer que /data/apex esteja disponível logo após a inicialização para atualizar todos os módulos do Android. Com FDE (Full-disk Encryption), /data/apex é criptografado até que o dispositivo seja desbloqueado pelo usuário, tornando o APEX basicamente inútil, pois apenas as variantes do sistema APEX serão carregadas na inicialização. Fora isso, todos os dispositivos deveriam suportar APEX, mas precisam de alguns patches de kernel (muitos dos quais são correções encontradas pelo Google ao brincar com dispositivos de loop). [3] [4]
Fontes [0], [1], [2], [3], [4]