Você pode usar o formato de arquivo APEX para empacotar e instalar módulos do sistema operacional Android de nível inferior. Ele permite a construção e instalação independente de componentes como serviços e bibliotecas nativos, implementações HAL, firmware, arquivos de configuração, etc.
Os APEXes do fornecedor são instalados automaticamente pelo sistema de compilação na partição /vendor
e ativados em tempo de execução pelo apexd
, assim como os APEXes em outras partições.
Casos de uso
Modularização de imagens de fornecedores
Os APEXes facilitam o agrupamento e a modularização naturais de implementações de recursos em imagens de fornecedores.
Quando as imagens do fornecedor são criadas como uma combinação de APEXes de fornecedores independentes, os fabricantes de dispositivos podem escolher facilmente as implementações específicas do fornecedor desejadas em seus dispositivos. Os fabricantes podem até criar um novo APEX de fornecedor se nenhum dos APEX fornecidos atender às suas necessidades ou se eles tiverem um novo hardware personalizado.
Por exemplo, um OEM pode optar por compor seu dispositivo com a implementação de wifi AOSP APEX, a implementação de Bluetooth SoC APEX e uma implementação de telefonia OEM personalizada APEX.
Sem APEXes de fornecedores, uma implementação com tantas dependências entre componentes de fornecedores requer coordenação e rastreamento cuidadosos. Ao agrupar todos os componentes (incluindo arquivos de configuração e bibliotecas extras) em APEXes com interfaces claramente definidas em qualquer ponto de comunicação entre recursos, os diferentes componentes tornam-se intercambiáveis.
Iteração do desenvolvedor
Os APEXes do fornecedor ajudam os desenvolvedores a iterar mais rapidamente durante o desenvolvimento de módulos do fornecedor, agrupando uma implementação completa de recursos, como o HAL wifi, dentro de um APEX do fornecedor. Os desenvolvedores podem então criar e enviar individualmente o APEX do fornecedor para testar as alterações, em vez de reconstruir toda a imagem do fornecedor.
Isso simplifica e acelera o ciclo de iteração do desenvolvedor para desenvolvedores que trabalham principalmente em uma área de recurso e desejam iterar apenas nessa área de recurso.
O agrupamento natural de uma área de recurso em um APEX também simplifica o processo de construção, envio e teste de alterações para essa área de recurso. Por exemplo, reinstalar um APEX atualiza automaticamente qualquer biblioteca incluída ou arquivos de configuração que o APEX inclui.
Agrupar uma área de recurso em um APEX também simplifica a depuração ou a reversão quando um mau comportamento do dispositivo é observado. Por exemplo, se a telefonia estiver funcionando mal em uma nova compilação, os desenvolvedores poderão tentar instalar uma implementação de telefonia APEX mais antiga em um dispositivo (sem a necessidade de atualizar uma compilação completa) e verificar se o bom comportamento é restaurado.
Fluxo de trabalho de exemplo:
# Build the entire device and flash. OR, obtain an already-flashed device.
source build/envsetup.sh && lunch oem_device-userdebug
m
fastboot flashall -w
# Test the device.
... testing ...
# Check previous behavior using a vendor APEX from one week ago, downloaded from
# your continuous integration build.
... download command ...
adb install <path to downloaded APEX>
adb reboot
... testing ...
# Edit and rebuild just the APEX to change and test behavior.
... edit APEX source contents ...
m <apex module name>
adb install out/<path to built APEX>
adb reboot
... testing ...
Exemplos
Fundamentos
Consulte a página principal do formato de arquivo APEX para obter informações genéricas do APEX, incluindo requisitos do dispositivo, detalhes do formato do arquivo e etapas de instalação.
Em Android.bp
, definir a vendor: true
torna um módulo APEX um APEX de fornecedor.
apex {
..
vendor: true,
..
}
Binários e bibliotecas compartilhadas
Um APEX inclui dependências transitivas dentro da carga útil do APEX, a menos que tenham interfaces estáveis.
Interfaces nativas estáveis para dependências APEX de fornecedores incluem cc_library
com stubs
, ndk_library
ou llndk_library
. Essas dependências são excluídas do pacote e são registradas no manifesto APEX. O manifesto é processado pelo linkerconfig
para que as dependências nativas externas estejam disponíveis em tempo de execução.
Ao contrário dos APEXes na partição /system
, os APEXes do fornecedor normalmente estão vinculados a uma versão específica do VNDK. As bibliotecas VNDK garantem a estabilidade da ABI dentro do lançamento, para que possamos tratar as bibliotecas VNDK como estáveis e reduzir o tamanho dos APEXes do fornecedor, excluindo-os dos APEXes usando a propriedade use_vndk_as_stable
.
No trecho abaixo, o APEX conterá o binário ( my_service
) e suas dependências não estáveis ( arquivos *.so
). Ele não conterá bibliotecas VNDK, mesmo quando my_service
for criado com bibliotecas VNDK como libbase
. Em vez disso, em tempo de execução my_service
usará libbase
das bibliotecas VNDK fornecidas pelo sistema.
apex {
..
vendor: true,
use_vndk_as_stable: true,
binaries: ["my_service"],
..
}
No trecho abaixo, o APEX conterá a biblioteca compartilhada my_standalone_lib
e qualquer uma de suas dependências não estáveis (conforme descrito acima).
apex {
..
vendor: true,
use_vndk_as_stable: true,
native_shared_libs: ["my_standalone_lib"],
..
}
Implementações HAL
Para definir uma implementação HAL, forneça os binários e bibliotecas correspondentes dentro de um APEX de fornecedor semelhante aos exemplos a seguir:
Para encapsular totalmente a implementação HAL, o APEX também deve especificar quaisquer fragmentos VINTF e scripts de inicialização relevantes.
Fragmentos VINTF
Os fragmentos VINTF podem ser servidos a partir de um APEX de fornecedor quando os fragmentos estão localizados em etc/vintf
do APEX.
Use a propriedade prebuilts
para incorporar os fragmentos VINTF no APEX.
apex {
..
vendor: true,
prebuilts: ["fragment.xml"],
..
}
prebuilt_etc {
name: "fragment.xml",
src: "fragment.xml",
sub_dir: "vintf",
}
Scripts de inicialização
APEXes podem incluir scripts de inicialização de duas maneiras: (A) um arquivo de texto pré-construído dentro da carga útil do APEX ou (B) um script de inicialização regular em /vendor/etc
. Você pode definir ambos para o mesmo APEX.
Script de inicialização no APEX:
prebuilt_etc {
name: "myinit.rc",
src: "myinit.rc"
}
apex {
..
vendor: true,
prebuilts: ["myinit.rc"],
..
}
Os scripts de inicialização nos APEXes podem ter apenas definições service
. Os scripts de inicialização nos APEXes do fornecedor também podem ter diretivas on <property>
.
Tenha cuidado ao usar diretivas on
. Como os scripts de inicialização em APEXes são analisados e executados após a ativação dos APEXes, alguns eventos ou propriedades não podem ser usados. Use apex.all.ready=true
para disparar ações o mais cedo possível.
Firmware
Exemplo:
Incorpore o firmware em um fornecedor APEX com o tipo de módulo prebuilt_firmware
, conforme a seguir.
prebuilt_firmware {
name: "my.bin",
src: "path_to_prebuilt_firmware",
vendor: true,
}
apex {
..
vendor: true,
prebuilts: ["my.bin"], // installed inside APEX as /etc/firmware/my.bin
..
}
Os módulos prebuilt_firmware
são instalados no diretório <apex name>/etc/firmware
do APEX. ueventd
verifica os diretórios /apex/*/etc/firmware
para encontrar módulos de firmware.
Os file_contexts
do APEX devem rotular adequadamente quaisquer entradas de carga útil do firmware para garantir que esses arquivos sejam acessíveis pelo ueventd
em tempo de execução; normalmente, o rótulo vendor_file
é suficiente. Por exemplo:
(/.*)? u:object_r:vendor_file:s0
Módulos do kernel
Incorpore módulos de kernel em um APEX de fornecedor como módulos pré-construídos, conforme a seguir.
prebuilt_etc {
name: "my.ko",
src: "my.ko",
vendor: true,
sub_dir: "modules"
}
apex {
..
vendor: true,
prebuilts: ["my.ko"], // installed inside APEX as /etc/modules/my.ko
..
}
Os file_contexts
do APEX devem rotular corretamente qualquer entrada de carga útil do módulo do kernel. Por exemplo:
/etc/modules(/.*)? u:object_r:vendor_kernel_modules:s0
Os módulos do kernel devem ser instalados explicitamente. O exemplo de script de inicialização a seguir na partição do fornecedor mostra a instalação via insmod
:
my_init.rc
:
on early-boot
insmod /apex/myapex/etc/modules/my.ko
..
Sobreposições de recursos de tempo de execução
Exemplo:
Incorpore sobreposições de recursos de tempo de execução em um APEX de fornecedor usando a propriedade rros
.
runtime_resource_overlay {
name: "my_rro",
soc_specific: true,
}
apex {
..
vendor: true,
rros: ["my_rro"], // installed inside APEX as /overlay/my_rro.apk
..
}
Outros arquivos de configuração
Os APEXes do fornecedor suportam vários outros arquivos de configuração normalmente encontrados na partição do fornecedor como pré-construídos dentro dos APEXes do fornecedor, e mais estão sendo adicionados.
Exemplos:
- XMLs de declaração de recursos
- Os sensores apresentam XMLs como pré-construídos em um fornecedor de sensor HAL APEX
- Arquivos de configuração de entrada
- Configurações de tela sensível ao toque como pré-construídas em um APEX de fornecedor somente de configuração
Recursos extras de desenvolvimento
Seleção APEX na inicialização
Exemplo:
Os desenvolvedores também podem instalar várias versões de APEXes de fornecedores que compartilham o mesmo nome e chave APEX e, em seguida, escolher qual versão será ativada durante cada inicialização usando sysprops persistentes. Para determinados casos de uso de desenvolvedor, isso pode ser mais simples do que instalar uma nova cópia do APEX usando adb install
.
Exemplos de casos de uso:
- Instale 3 versões do fornecedor WiFi HAL APEX: As equipes de controle de qualidade podem executar testes manuais ou automatizados usando uma versão, reinicializar em outra versão e executar novamente os testes e, em seguida, comparar os resultados finais.
- Instale 2 versões da câmera HAL do fornecedor APEX, atual e experimental : Dogfooders podem usar a versão experimental sem baixar e instalar um arquivo adicional, para que possam facilmente trocar de volta.
Durante a inicialização, apexd
procura sysprops seguindo um formato específico para ativar a versão correta do APEX.
Os formatos esperados para a chave da propriedade são:
- Configuração de inicialização
- Usado para definir o valor padrão, em
BoardConfig.mk
. -
androidboot.vendor.apex.<apex name>
- Usado para definir o valor padrão, em
- Sysprop persistente
- Usado para alterar o valor padrão, definido em um dispositivo já inicializado.
- Substitui o valor bootconfig, se presente.
-
persist.vendor.apex.<apex name>
O valor da propriedade deverá ser o nome do arquivo do APEX que deverá ser ativado.
// Default version.
apex {
name: "com.oem.camera.hal.my_apex_default",
vendor: true,
..
}
// Non-default version.
apex {
name: "com.oem.camera.hal.my_apex_experimental",
vendor: true,
..
}
A versão padrão também deve ser configurada usando bootconfig em BoardConfig.mk
:
# Example for APEX "com.oem.camera.hal" with the default above:
BOARD_BOOTCONFIG += \
androidboot.vendor.apex.com.oem.camera.hal=com.oem.camera.hal.my_apex_default
Depois que o dispositivo for inicializado, altere a versão ativada configurando o sysprop persistente:
$ adb root;
$ adb shell setprop \
persist.vendor.apex.com.oem.camera.hal \
com.oem.camera.hal.my_apex_experimental;
$ adb reboot;
Se o dispositivo suportar a atualização do bootconfig após a atualização (como por meio de comandos fastboot oem
), a alteração da propriedade bootconfig do APEX multiinstalado também alterará a versão ativada na inicialização.
Para dispositivos de referência virtual baseados em Cuttlefish , você pode usar o comando --extra_bootconfig_args
para definir a propriedade bootconfig diretamente durante a inicialização. Por exemplo:
launch_cvd --noresume \
--extra_bootconfig_args "androidboot.vendor.apex.com.oem.camera.hal:=com.oem.camera.hal.my_apex_experimental";
, Você pode usar o formato de arquivo APEX para empacotar e instalar módulos do sistema operacional Android de nível inferior. Ele permite a construção e instalação independente de componentes como serviços e bibliotecas nativos, implementações HAL, firmware, arquivos de configuração, etc.
Os APEXes do fornecedor são instalados automaticamente pelo sistema de compilação na partição /vendor
e ativados em tempo de execução pelo apexd
, assim como os APEXes em outras partições.
Casos de uso
Modularização de imagens de fornecedores
Os APEXes facilitam o agrupamento e a modularização naturais de implementações de recursos em imagens de fornecedores.
Quando as imagens do fornecedor são criadas como uma combinação de APEXes de fornecedores independentes, os fabricantes de dispositivos podem escolher facilmente as implementações específicas do fornecedor desejadas em seus dispositivos. Os fabricantes podem até criar um novo APEX de fornecedor se nenhum dos APEX fornecidos atender às suas necessidades ou se eles tiverem um novo hardware personalizado.
Por exemplo, um OEM pode optar por compor seu dispositivo com a implementação de wifi AOSP APEX, a implementação de Bluetooth SoC APEX e uma implementação de telefonia OEM personalizada APEX.
Sem APEXes de fornecedores, uma implementação com tantas dependências entre componentes de fornecedores requer coordenação e rastreamento cuidadosos. Ao agrupar todos os componentes (incluindo arquivos de configuração e bibliotecas extras) em APEXes com interfaces claramente definidas em qualquer ponto de comunicação entre recursos, os diferentes componentes tornam-se intercambiáveis.
Iteração do desenvolvedor
Os APEXes do fornecedor ajudam os desenvolvedores a iterar mais rapidamente durante o desenvolvimento de módulos do fornecedor, agrupando uma implementação completa de recursos, como o HAL wifi, dentro de um APEX do fornecedor. Os desenvolvedores podem então criar e enviar individualmente o APEX do fornecedor para testar as alterações, em vez de reconstruir toda a imagem do fornecedor.
Isso simplifica e acelera o ciclo de iteração do desenvolvedor para desenvolvedores que trabalham principalmente em uma área de recurso e desejam iterar apenas nessa área de recurso.
O agrupamento natural de uma área de recurso em um APEX também simplifica o processo de construção, envio e teste de alterações para essa área de recurso. Por exemplo, reinstalar um APEX atualiza automaticamente qualquer biblioteca incluída ou arquivos de configuração que o APEX inclui.
Agrupar uma área de recurso em um APEX também simplifica a depuração ou a reversão quando um mau comportamento do dispositivo é observado. Por exemplo, se a telefonia estiver funcionando mal em uma nova compilação, os desenvolvedores poderão tentar instalar uma implementação de telefonia APEX mais antiga em um dispositivo (sem a necessidade de atualizar uma compilação completa) e verificar se o bom comportamento é restaurado.
Fluxo de trabalho de exemplo:
# Build the entire device and flash. OR, obtain an already-flashed device.
source build/envsetup.sh && lunch oem_device-userdebug
m
fastboot flashall -w
# Test the device.
... testing ...
# Check previous behavior using a vendor APEX from one week ago, downloaded from
# your continuous integration build.
... download command ...
adb install <path to downloaded APEX>
adb reboot
... testing ...
# Edit and rebuild just the APEX to change and test behavior.
... edit APEX source contents ...
m <apex module name>
adb install out/<path to built APEX>
adb reboot
... testing ...
Exemplos
Fundamentos
Consulte a página principal do formato de arquivo APEX para obter informações genéricas do APEX, incluindo requisitos do dispositivo, detalhes do formato do arquivo e etapas de instalação.
Em Android.bp
, definir a vendor: true
torna um módulo APEX um APEX de fornecedor.
apex {
..
vendor: true,
..
}
Binários e bibliotecas compartilhadas
Um APEX inclui dependências transitivas dentro da carga útil do APEX, a menos que tenham interfaces estáveis.
Interfaces nativas estáveis para dependências APEX de fornecedores incluem cc_library
com stubs
, ndk_library
ou llndk_library
. Essas dependências são excluídas do pacote e são registradas no manifesto APEX. O manifesto é processado pelo linkerconfig
para que as dependências nativas externas estejam disponíveis em tempo de execução.
Ao contrário dos APEXes na partição /system
, os APEXes do fornecedor normalmente estão vinculados a uma versão específica do VNDK. As bibliotecas VNDK garantem a estabilidade da ABI dentro do lançamento, para que possamos tratar as bibliotecas VNDK como estáveis e reduzir o tamanho dos APEXes do fornecedor, excluindo-os dos APEXes usando a propriedade use_vndk_as_stable
.
No trecho abaixo, o APEX conterá o binário ( my_service
) e suas dependências não estáveis ( arquivos *.so
). Ele não conterá bibliotecas VNDK, mesmo quando my_service
for criado com bibliotecas VNDK como libbase
. Em vez disso, em tempo de execução my_service
usará libbase
das bibliotecas VNDK fornecidas pelo sistema.
apex {
..
vendor: true,
use_vndk_as_stable: true,
binaries: ["my_service"],
..
}
No trecho abaixo, o APEX conterá a biblioteca compartilhada my_standalone_lib
e qualquer uma de suas dependências não estáveis (conforme descrito acima).
apex {
..
vendor: true,
use_vndk_as_stable: true,
native_shared_libs: ["my_standalone_lib"],
..
}
Implementações HAL
Para definir uma implementação HAL, forneça os binários e bibliotecas correspondentes dentro de um APEX de fornecedor semelhante aos exemplos a seguir:
Para encapsular totalmente a implementação HAL, o APEX também deve especificar quaisquer fragmentos VINTF e scripts de inicialização relevantes.
Fragmentos VINTF
Os fragmentos VINTF podem ser servidos a partir de um APEX de fornecedor quando os fragmentos estão localizados em etc/vintf
do APEX.
Use a propriedade prebuilts
para incorporar os fragmentos VINTF no APEX.
apex {
..
vendor: true,
prebuilts: ["fragment.xml"],
..
}
prebuilt_etc {
name: "fragment.xml",
src: "fragment.xml",
sub_dir: "vintf",
}
Scripts de inicialização
APEXes podem incluir scripts de inicialização de duas maneiras: (A) um arquivo de texto pré-construído dentro da carga útil do APEX ou (B) um script de inicialização regular em /vendor/etc
. Você pode definir ambos para o mesmo APEX.
Script de inicialização no APEX:
prebuilt_etc {
name: "myinit.rc",
src: "myinit.rc"
}
apex {
..
vendor: true,
prebuilts: ["myinit.rc"],
..
}
Os scripts de inicialização nos APEXes podem ter apenas definições service
. Os scripts de inicialização nos APEXes do fornecedor também podem ter diretivas on <property>
.
Tenha cuidado ao usar diretivas on
. Como os scripts de inicialização em APEXes são analisados e executados após a ativação dos APEXes, alguns eventos ou propriedades não podem ser usados. Use apex.all.ready=true
para disparar ações o mais cedo possível.
Firmware
Exemplo:
Incorpore o firmware em um fornecedor APEX com o tipo de módulo prebuilt_firmware
, conforme a seguir.
prebuilt_firmware {
name: "my.bin",
src: "path_to_prebuilt_firmware",
vendor: true,
}
apex {
..
vendor: true,
prebuilts: ["my.bin"], // installed inside APEX as /etc/firmware/my.bin
..
}
Os módulos prebuilt_firmware
são instalados no diretório <apex name>/etc/firmware
do APEX. ueventd
verifica os diretórios /apex/*/etc/firmware
para encontrar módulos de firmware.
Os file_contexts
do APEX devem rotular adequadamente quaisquer entradas de carga útil do firmware para garantir que esses arquivos sejam acessíveis pelo ueventd
em tempo de execução; normalmente, o rótulo vendor_file
é suficiente. Por exemplo:
(/.*)? u:object_r:vendor_file:s0
Módulos do kernel
Incorpore módulos de kernel em um APEX de fornecedor como módulos pré-construídos, conforme a seguir.
prebuilt_etc {
name: "my.ko",
src: "my.ko",
vendor: true,
sub_dir: "modules"
}
apex {
..
vendor: true,
prebuilts: ["my.ko"], // installed inside APEX as /etc/modules/my.ko
..
}
Os file_contexts
do APEX devem rotular corretamente qualquer entrada de carga útil do módulo do kernel. Por exemplo:
/etc/modules(/.*)? u:object_r:vendor_kernel_modules:s0
Os módulos do kernel devem ser instalados explicitamente. O exemplo de script de inicialização a seguir na partição do fornecedor mostra a instalação via insmod
:
my_init.rc
:
on early-boot
insmod /apex/myapex/etc/modules/my.ko
..
Sobreposições de recursos de tempo de execução
Exemplo:
Incorpore sobreposições de recursos de tempo de execução em um APEX de fornecedor usando a propriedade rros
.
runtime_resource_overlay {
name: "my_rro",
soc_specific: true,
}
apex {
..
vendor: true,
rros: ["my_rro"], // installed inside APEX as /overlay/my_rro.apk
..
}
Outros arquivos de configuração
Os APEXes do fornecedor suportam vários outros arquivos de configuração normalmente encontrados na partição do fornecedor como pré-construídos dentro dos APEXes do fornecedor, e mais estão sendo adicionados.
Exemplos:
- XMLs de declaração de recursos
- Os sensores apresentam XMLs como pré-construídos em um fornecedor de sensor HAL APEX
- Arquivos de configuração de entrada
- Configurações de tela sensível ao toque como pré-construídas em um APEX de fornecedor somente de configuração
Recursos extras de desenvolvimento
Seleção APEX na inicialização
Exemplo:
Os desenvolvedores também podem instalar várias versões de APEXes de fornecedores que compartilham o mesmo nome e chave APEX e, em seguida, escolher qual versão será ativada durante cada inicialização usando sysprops persistentes. Para determinados casos de uso de desenvolvedor, isso pode ser mais simples do que instalar uma nova cópia do APEX usando adb install
.
Exemplos de casos de uso:
- Instale 3 versões do fornecedor WiFi HAL APEX: As equipes de controle de qualidade podem executar testes manuais ou automatizados usando uma versão, reinicializar em outra versão e executar novamente os testes e, em seguida, comparar os resultados finais.
- Instale 2 versões da câmera HAL do fornecedor APEX, atual e experimental : Dogfooders podem usar a versão experimental sem baixar e instalar um arquivo adicional, para que possam facilmente trocar de volta.
Durante a inicialização, apexd
procura sysprops seguindo um formato específico para ativar a versão correta do APEX.
Os formatos esperados para a chave da propriedade são:
- Configuração de inicialização
- Usado para definir o valor padrão, em
BoardConfig.mk
. -
androidboot.vendor.apex.<apex name>
- Usado para definir o valor padrão, em
- Sysprop persistente
- Usado para alterar o valor padrão, definido em um dispositivo já inicializado.
- Substitui o valor bootconfig, se presente.
-
persist.vendor.apex.<apex name>
O valor da propriedade deverá ser o nome do arquivo do APEX que deverá ser ativado.
// Default version.
apex {
name: "com.oem.camera.hal.my_apex_default",
vendor: true,
..
}
// Non-default version.
apex {
name: "com.oem.camera.hal.my_apex_experimental",
vendor: true,
..
}
A versão padrão também deve ser configurada usando bootconfig em BoardConfig.mk
:
# Example for APEX "com.oem.camera.hal" with the default above:
BOARD_BOOTCONFIG += \
androidboot.vendor.apex.com.oem.camera.hal=com.oem.camera.hal.my_apex_default
Depois que o dispositivo for inicializado, altere a versão ativada configurando o sysprop persistente:
$ adb root;
$ adb shell setprop \
persist.vendor.apex.com.oem.camera.hal \
com.oem.camera.hal.my_apex_experimental;
$ adb reboot;
Se o dispositivo suportar a atualização do bootconfig após a atualização (como por meio de comandos fastboot oem
), a alteração da propriedade bootconfig do APEX multiinstalado também alterará a versão ativada na inicialização.
Para dispositivos de referência virtual baseados em Cuttlefish , você pode usar o comando --extra_bootconfig_args
para definir a propriedade bootconfig diretamente durante a inicialização. Por exemplo:
launch_cvd --noresume \
--extra_bootconfig_args "androidboot.vendor.apex.com.oem.camera.hal:=com.oem.camera.hal.my_apex_experimental";
, Você pode usar o formato de arquivo APEX para empacotar e instalar módulos do sistema operacional Android de nível inferior. Ele permite a construção e instalação independente de componentes como serviços e bibliotecas nativos, implementações HAL, firmware, arquivos de configuração, etc.
Os APEXes do fornecedor são instalados automaticamente pelo sistema de compilação na partição /vendor
e ativados em tempo de execução pelo apexd
, assim como os APEXes em outras partições.
Casos de uso
Modularização de imagens de fornecedores
Os APEXes facilitam o agrupamento e a modularização naturais de implementações de recursos em imagens de fornecedores.
Quando as imagens do fornecedor são criadas como uma combinação de APEXes de fornecedores independentes, os fabricantes de dispositivos podem escolher facilmente as implementações específicas do fornecedor desejadas em seus dispositivos. Os fabricantes podem até criar um novo APEX de fornecedor se nenhum dos APEX fornecidos atender às suas necessidades ou se eles tiverem um novo hardware personalizado.
Por exemplo, um OEM pode optar por compor seu dispositivo com a implementação de wifi AOSP APEX, a implementação de Bluetooth SoC APEX e uma implementação de telefonia OEM personalizada APEX.
Sem APEXes de fornecedores, uma implementação com tantas dependências entre componentes de fornecedores requer coordenação e rastreamento cuidadosos. Ao agrupar todos os componentes (incluindo arquivos de configuração e bibliotecas extras) em APEXes com interfaces claramente definidas em qualquer ponto de comunicação entre recursos, os diferentes componentes tornam-se intercambiáveis.
Iteração do desenvolvedor
Os APEXes do fornecedor ajudam os desenvolvedores a iterar mais rapidamente durante o desenvolvimento de módulos do fornecedor, agrupando uma implementação completa de recursos, como o HAL wifi, dentro de um APEX do fornecedor. Os desenvolvedores podem então criar e enviar individualmente o APEX do fornecedor para testar as alterações, em vez de reconstruir toda a imagem do fornecedor.
Isso simplifica e acelera o ciclo de iteração do desenvolvedor para desenvolvedores que trabalham principalmente em uma área de recurso e desejam iterar apenas nessa área de recurso.
O agrupamento natural de uma área de recurso em um APEX também simplifica o processo de construção, envio e teste de alterações para essa área de recurso. Por exemplo, reinstalar um APEX atualiza automaticamente qualquer biblioteca incluída ou arquivos de configuração que o APEX inclui.
Agrupar uma área de recurso em um APEX também simplifica a depuração ou a reversão quando um mau comportamento do dispositivo é observado. Por exemplo, se a telefonia estiver funcionando mal em uma nova compilação, os desenvolvedores poderão tentar instalar uma implementação de telefonia APEX mais antiga em um dispositivo (sem a necessidade de atualizar uma compilação completa) e verificar se o bom comportamento é restaurado.
Fluxo de trabalho de exemplo:
# Build the entire device and flash. OR, obtain an already-flashed device.
source build/envsetup.sh && lunch oem_device-userdebug
m
fastboot flashall -w
# Test the device.
... testing ...
# Check previous behavior using a vendor APEX from one week ago, downloaded from
# your continuous integration build.
... download command ...
adb install <path to downloaded APEX>
adb reboot
... testing ...
# Edit and rebuild just the APEX to change and test behavior.
... edit APEX source contents ...
m <apex module name>
adb install out/<path to built APEX>
adb reboot
... testing ...
Exemplos
Fundamentos
Consulte a página principal do formato de arquivo APEX para obter informações genéricas do APEX, incluindo requisitos do dispositivo, detalhes do formato do arquivo e etapas de instalação.
Em Android.bp
, definir a vendor: true
torna um módulo APEX um APEX de fornecedor.
apex {
..
vendor: true,
..
}
Binários e bibliotecas compartilhadas
Um APEX inclui dependências transitivas dentro da carga útil do APEX, a menos que tenham interfaces estáveis.
Interfaces nativas estáveis para dependências APEX de fornecedores incluem cc_library
com stubs
, ndk_library
ou llndk_library
. Essas dependências são excluídas do pacote e são registradas no manifesto APEX. O manifesto é processado pelo linkerconfig
para que as dependências nativas externas estejam disponíveis em tempo de execução.
Ao contrário dos APEXes na partição /system
, os APEXes do fornecedor normalmente estão vinculados a uma versão específica do VNDK. As bibliotecas VNDK garantem a estabilidade da ABI dentro do lançamento, para que possamos tratar as bibliotecas VNDK como estáveis e reduzir o tamanho dos APEXes do fornecedor, excluindo-os dos APEXes usando a propriedade use_vndk_as_stable
.
No trecho abaixo, o APEX conterá o binário ( my_service
) e suas dependências não estáveis ( arquivos *.so
). Ele não conterá bibliotecas VNDK, mesmo quando my_service
for criado com bibliotecas VNDK como libbase
. Em vez disso, em tempo de execução my_service
usará libbase
das bibliotecas VNDK fornecidas pelo sistema.
apex {
..
vendor: true,
use_vndk_as_stable: true,
binaries: ["my_service"],
..
}
No trecho abaixo, o APEX conterá a biblioteca compartilhada my_standalone_lib
e qualquer uma de suas dependências não estáveis (conforme descrito acima).
apex {
..
vendor: true,
use_vndk_as_stable: true,
native_shared_libs: ["my_standalone_lib"],
..
}
Implementações HAL
Para definir uma implementação HAL, forneça os binários e bibliotecas correspondentes dentro de um APEX de fornecedor semelhante aos exemplos a seguir:
Para encapsular totalmente a implementação HAL, o APEX também deve especificar quaisquer fragmentos VINTF e scripts de inicialização relevantes.
Fragmentos VINTF
Os fragmentos VINTF podem ser servidos a partir de um APEX de fornecedor quando os fragmentos estão localizados em etc/vintf
do APEX.
Use a propriedade prebuilts
para incorporar os fragmentos VINTF no APEX.
apex {
..
vendor: true,
prebuilts: ["fragment.xml"],
..
}
prebuilt_etc {
name: "fragment.xml",
src: "fragment.xml",
sub_dir: "vintf",
}
Scripts de inicialização
APEXes podem incluir scripts de inicialização de duas maneiras: (A) um arquivo de texto pré-construído dentro da carga útil do APEX ou (B) um script de inicialização regular em /vendor/etc
. Você pode definir ambos para o mesmo APEX.
Script de inicialização no APEX:
prebuilt_etc {
name: "myinit.rc",
src: "myinit.rc"
}
apex {
..
vendor: true,
prebuilts: ["myinit.rc"],
..
}
Os scripts de inicialização nos APEXes podem ter apenas definições service
. Os scripts de inicialização nos APEXes do fornecedor também podem ter diretivas on <property>
.
Tenha cuidado ao usar diretivas on
. Como os scripts de inicialização em APEXes são analisados e executados após a ativação dos APEXes, alguns eventos ou propriedades não podem ser usados. Use apex.all.ready=true
para disparar ações o mais cedo possível.
Firmware
Exemplo:
Incorpore o firmware em um fornecedor APEX com o tipo de módulo prebuilt_firmware
, conforme a seguir.
prebuilt_firmware {
name: "my.bin",
src: "path_to_prebuilt_firmware",
vendor: true,
}
apex {
..
vendor: true,
prebuilts: ["my.bin"], // installed inside APEX as /etc/firmware/my.bin
..
}
Os módulos prebuilt_firmware
são instalados no diretório <apex name>/etc/firmware
do APEX. ueventd
verifica os diretórios /apex/*/etc/firmware
para encontrar módulos de firmware.
Os file_contexts
do APEX devem rotular adequadamente quaisquer entradas de carga útil do firmware para garantir que esses arquivos sejam acessíveis pelo ueventd
em tempo de execução; normalmente, o rótulo vendor_file
é suficiente. Por exemplo:
(/.*)? u:object_r:vendor_file:s0
Módulos do kernel
Incorpore módulos de kernel em um APEX de fornecedor como módulos pré-construídos, conforme a seguir.
prebuilt_etc {
name: "my.ko",
src: "my.ko",
vendor: true,
sub_dir: "modules"
}
apex {
..
vendor: true,
prebuilts: ["my.ko"], // installed inside APEX as /etc/modules/my.ko
..
}
Os file_contexts
do APEX devem rotular corretamente qualquer entrada de carga útil do módulo do kernel. Por exemplo:
/etc/modules(/.*)? u:object_r:vendor_kernel_modules:s0
Os módulos do kernel devem ser instalados explicitamente. O exemplo de script de inicialização a seguir na partição do fornecedor mostra a instalação via insmod
:
my_init.rc
:
on early-boot
insmod /apex/myapex/etc/modules/my.ko
..
Sobreposições de recursos de tempo de execução
Exemplo:
Incorpore sobreposições de recursos de tempo de execução em um APEX de fornecedor usando a propriedade rros
.
runtime_resource_overlay {
name: "my_rro",
soc_specific: true,
}
apex {
..
vendor: true,
rros: ["my_rro"], // installed inside APEX as /overlay/my_rro.apk
..
}
Outros arquivos de configuração
Os APEXes do fornecedor suportam vários outros arquivos de configuração normalmente encontrados na partição do fornecedor como pré-construídos dentro dos APEXes do fornecedor, e mais estão sendo adicionados.
Exemplos:
- XMLs de declaração de recursos
- Os sensores apresentam XMLs como pré-construídos em um fornecedor de sensor HAL APEX
- Arquivos de configuração de entrada
- Configurações de tela sensível ao toque como pré-construídas em um APEX de fornecedor somente de configuração
Recursos extras de desenvolvimento
Seleção APEX na inicialização
Exemplo:
Os desenvolvedores também podem instalar várias versões de APEXes de fornecedores que compartilham o mesmo nome e chave APEX e, em seguida, escolher qual versão será ativada durante cada inicialização usando sysprops persistentes. Para determinados casos de uso de desenvolvedor, isso pode ser mais simples do que instalar uma nova cópia do APEX usando adb install
.
Exemplos de casos de uso:
- Instale 3 versões do fornecedor WiFi HAL APEX: As equipes de controle de qualidade podem executar testes manuais ou automatizados usando uma versão, reinicializar em outra versão e executar novamente os testes e, em seguida, comparar os resultados finais.
- Instale 2 versões da câmera HAL do fornecedor APEX, atual e experimental : Dogfooders podem usar a versão experimental sem baixar e instalar um arquivo adicional, para que possam facilmente trocar de volta.
Durante a inicialização, apexd
procura sysprops seguindo um formato específico para ativar a versão correta do APEX.
Os formatos esperados para a chave da propriedade são:
- Configuração de inicialização
- Usado para definir o valor padrão, em
BoardConfig.mk
. -
androidboot.vendor.apex.<apex name>
- Usado para definir o valor padrão, em
- Sysprop persistente
- Usado para alterar o valor padrão, definido em um dispositivo já inicializado.
- Substitui o valor bootconfig, se presente.
-
persist.vendor.apex.<apex name>
O valor da propriedade deverá ser o nome do arquivo do APEX que deverá ser ativado.
// Default version.
apex {
name: "com.oem.camera.hal.my_apex_default",
vendor: true,
..
}
// Non-default version.
apex {
name: "com.oem.camera.hal.my_apex_experimental",
vendor: true,
..
}
A versão padrão também deve ser configurada usando bootconfig em BoardConfig.mk
:
# Example for APEX "com.oem.camera.hal" with the default above:
BOARD_BOOTCONFIG += \
androidboot.vendor.apex.com.oem.camera.hal=com.oem.camera.hal.my_apex_default
Depois que o dispositivo for inicializado, altere a versão ativada configurando o sysprop persistente:
$ adb root;
$ adb shell setprop \
persist.vendor.apex.com.oem.camera.hal \
com.oem.camera.hal.my_apex_experimental;
$ adb reboot;
Se o dispositivo suportar a atualização do bootconfig após a atualização (como por meio de comandos fastboot oem
), a alteração da propriedade bootconfig do APEX multiinstalado também alterará a versão ativada na inicialização.
Para dispositivos de referência virtual baseados em Cuttlefish , você pode usar o comando --extra_bootconfig_args
para definir a propriedade bootconfig diretamente durante a inicialização. Por exemplo:
launch_cvd --noresume \
--extra_bootconfig_args "androidboot.vendor.apex.com.oem.camera.hal:=com.oem.camera.hal.my_apex_experimental";