O Microdroid é um SO mini-Android executado em uma pVM. Não é necessário usar o Microdroid. Você pode iniciar uma VM com qualquer SO. No entanto, os principais casos de uso para pVMs não são a execução de um SO independente, mas sim oferecer um ambiente de execução isolado para executar uma parte de um app com garantias de confidencialidade e integridade mais fortes do que o Android pode oferecer.
Com sistemas operacionais tradicionais, fornecer confidencialidade e integridade fortes exige muito trabalho (geralmente duplicado), porque os sistemas operacionais tradicionais não se encaixam na arquitetura geral do Android. Por exemplo, com a arquitetura padrão do Android, os desenvolvedores precisam implementar um meio de carregar e executar com segurança parte do app na pVM, e o payload é criado no glibc. O app Android usa o Bionic, a comunicação exige um protocolo personalizado sobre vsock, e a depuração usando o adb é desafiadora.
O Microdroid preenche essas lacunas fornecendo uma imagem de SO pronta para uso, projetada para exigir o mínimo de esforço dos desenvolvedores para descarregar uma parte do app em uma pVM. O código nativo é criado no Bionic, a comunicação acontece pelo Binder, e ele permite importar APEXes do Android host e expõe um subconjunto da API Android, como o keystore para operações criptográficas com chaves com suporte de hardware. No geral, os desenvolvedores vão achar o Microdroid um ambiente familiar com as ferramentas a que se acostumaram no SO Android completo.
Recursos
O Microdroid é uma versão simplificada do Android com alguns componentes adicionais específicos para pVMs. O Microdroid oferece suporte a:
- Um subconjunto de APIs do NDK (todas as APIs para a implementação do libc e do Bionic do Android são fornecidas)
- Recursos de depuração, como adb, logcat, tombstone e gdb
- Inicialização verificada e SELinux
- Carregamento e execução de um binário, junto com bibliotecas compartilhadas, incorporadas em um APK
- RPC do Binder sobre vsock e troca de arquivos com verificações de integridade implícitas
- Carregamento de APEXes
O Microdroid não oferece suporte a:
APIs Java do Android nos pacotes
android.\*SystemServer e Zygote
Gráficos/interface
HALs
Arquitetura do Microdroid
O Microdroid é semelhante ao Cuttlefish, porque ambos têm uma arquitetura semelhante ao Android padrão. O Microdroid consiste nas seguintes imagens de partição agrupadas em uma imagem de disco composta:
bootloader: verifica e inicia o kernel.boot.img: contém o kernel e o ramdisk init.vendor_boot.img: contém módulos de kernel específicos da VM, como o virtio.super.img: consiste em partições lógicas do sistema e do fornecedor.vbmeta.img: contém metadados de inicialização verificados.
As imagens de partição são enviadas no APEX de virtualização e são empacotadas em uma imagem de disco composta por VirtualizationService. Além da imagem de disco composta do SO principal, VirtualizationService é responsável por criar estas outras partições:
payload: um conjunto de partições com suporte dos APEXes e APKs do Androidinstance: uma partição criptografada para persistir dados de inicialização verificados por instância , como sal por instância, chaves públicas APEX confiáveis e contadores de reversão
Sequência de inicialização
A sequência de inicialização do Microdroid ocorre após a inicialização do dispositivo. A inicialização do dispositivo é discutida na seção Firmware da pVM do documento de arquitetura. A figura 1 mostra as etapas que ocorrem durante a sequência de inicialização do Microdroid:
Confira uma explicação das etapas:
O bootloader é carregado na memória pelo crosvm e o pvmfw começa a ser executado. Antes de pular para o bootloader, o pvmfw executa duas tarefas:
- Verifica o bootloader para conferir se ele é de uma fonte confiável (Google ou OEM).
- Garante que o mesmo bootloader seja usado de forma consistente em várias inicializações da mesma pVM usando a imagem da instância. Especificamente, a pVM é inicializada com uma imagem de instância vazia. O pvmfw armazena a identidade do bootloader na imagem da instância e a criptografa. Assim, na próxima vez que a pVM for inicializada com a mesma imagem de instância, o pvmfw vai descriptografar a identidade salva da imagem de instância e verificar se ela é a mesma que foi salva anteriormente. Se as identidades forem diferentes, o pvmfw se recusará a inicializar.
O bootloader inicializa o Microdroid.
O bootloader acessa o disco da instância. Semelhante ao pvmfw, o bootloader tem uma unidade de disco de instância com informações sobre imagens de partição usadas nessa instância durante inicializações anteriores, incluindo a chave pública.
O bootloader verifica o vbmeta e as partições encadeadas, como
bootesuper, e, se for bem-sucedido, deriva os segredos da pVM da próxima fase. Em seguida, o Microdroid entrega o controle ao kernel.Como a superpartição já foi verificada pelo bootloader (etapa 3), o kernel monta incondicionalmente a superpartição. Assim como no Android completo, a superpartição consiste em várias partições lógicas montadas no dm-verity. O controle é transmitido ao processo
init, que inicia vários serviços nativos. O scriptinit.rcé semelhante ao do Android completo, mas adaptado às necessidades do Microdroid.O processo
initinicia o gerenciador do Microdroid, que acessa a imagem da instância. O serviço do gerenciador do Microdroid descriptografa a imagem usando a chave transmitida da fase anterior e lê as chaves públicas e os contadores de reversão do APK e dos APEXes do cliente em que essa pVM confia. Essas informações são usadas mais tarde porzipfuseeapexdquando eles montam o APK do cliente e os APEXes solicitados, respectivamente.O serviço do gerenciador do Microdroid inicia o
apexd.apexdmonta os APEXes nos diretórios/apex/<name>. A única diferença entre como o Android e o Microdroid montam APEXes é que, no Microdroid, os arquivos APEX vêm de dispositivos de bloco virtual (/dev/vdc1, …), não de arquivos normais (/system/apex/*.apex).zipfuseé o sistema de arquivos FUSE do Microdroid.zipfusemonta o APK do cliente, que é essencialmente um arquivo ZIP como um sistema de arquivos. Por baixo, o arquivo APK é transmitido como um dispositivo de bloco virtual pela pVM com dm-verity, assim como o APEX. O APK contém um arquivo de configuração com uma lista de APEXes que o desenvolvedor de apps solicitou para essa instância de pVM. A lista é usada peloapexdao ativar APEXes.O fluxo de inicialização retorna ao serviço do gerenciador do Microdroid. O serviço do gerenciador se comunica com o
VirtualizationServicedo Android usando o RPC do Binder para que ele possa informar eventos importantes, como falha ou desligamento, e aceitar solicitações, como encerrar a pVM. O serviço do gerenciador lê o local do binário principal no arquivo de configuração do APK e o executa.
Troca de arquivos (AuthFS)
É comum que os componentes do Android usem arquivos para entrada, saída e estado e os transmitam como descritores de arquivo (tipo ParcelFileDescriptor no AIDL) com acesso controlado pelo kernel do Android. O AuthFS facilita funcionalidades semelhantes para trocar arquivos entre endpoints mutuamente desconfiados em limites de pVM.
Fundamentalmente, o AuthFS é um sistema de arquivos remoto com verificações de integridade transparentes em operações de acesso individuais, semelhante ao fs-verity. As verificações permitem que o front-end, como um programa de leitura de arquivos executado em uma pVM, detecte se o back-end não confiável, normalmente o Android, adulterou o conteúdo do arquivo.
Para trocar arquivos, o back-end (fd\_server) é iniciado com a configuração por arquivo, especificando se ele é destinado à entrada (somente leitura) ou saída (leitura e gravação). Para entrada, o front-end exige que o conteúdo corresponda a um hash conhecido, além de uma árvore de Merkle para verificação no acesso. Para saída, o AuthFS mantém internamente uma árvore de hash do conteúdo observado nas operações de gravação e pode impor a integridade quando os dados são lidos novamente.
O transporte subjacente é baseado no RPC do Binder, mas isso pode mudar no futuro para otimizar a performance.
Gerenciamento de chaves
As pVMs recebem uma chave de vedação estável adequada para proteger dados persistentes e uma chave de atestado adequada para produzir assinaturas que são verificavelmente produzidas pela pVM.
RPC do Binder
A maioria das interfaces do Android é expressa em AIDL, que é criada com base no driver do kernel do Binder Linux. Para oferecer suporte a interfaces entre pVMs, o protocolo do Binder foi reescrito para funcionar em soquetes, vsock no caso de pVMs. A operação em soquetes permite que as interfaces AIDL atuais do Android sejam usadas nesse novo ambiente.
Para configurar a conexão, um endpoint, como o payload da pVM, cria um objeto RpcServer, registra um objeto raiz e começa a ouvir novas conexões. Os clientes podem se conectar a esse servidor usando um objeto RpcSession, receber o objeto Binder e usá-lo exatamente como um objeto Binder é usado com o driver do Binder do kernel.