Formato de archivo APEX

El formato de contenedor Android Pony EXpress (APEX) se introdujo en Android 10 y se utiliza en el flujo de instalación de módulos del sistema de nivel inferior. Este formato facilita las actualizaciones de componentes del sistema que no encajan en el modelo de aplicación estándar de Android. Algunos componentes de ejemplo son bibliotecas y servicios nativos, capas de abstracción de hardware ( HAL ), tiempo de ejecución ( ART ) y bibliotecas de clases.

El término "APEX" también puede referirse a un archivo APEX.

Fondo

Aunque Android admite actualizaciones de módulos que se ajustan al modelo de aplicación estándar (por ejemplo, servicios, actividades) a través de aplicaciones de instalación de paquetes (como la aplicación Google Play Store), el uso de un modelo similar para componentes del sistema operativo de nivel inferior tiene los siguientes inconvenientes:

  • Los módulos basados ​​en APK no se pueden utilizar al principio de la secuencia de inicio. El administrador de paquetes es el depósito central de información sobre aplicaciones y solo se puede iniciar desde el administrador de actividades, que estará listo en una etapa posterior del procedimiento de inicio.
  • El formato APK (particularmente el manifiesto) está diseñado para aplicaciones de Android y los módulos del sistema no siempre son adecuados.

Diseño

Esta sección describe el diseño de alto nivel del formato de archivo APEX y el administrador APEX, que es un servicio que administra archivos APEX.

Para obtener más información sobre por qué se seleccionó este diseño para APEX, consulte Alternativas consideradas al desarrollar APEX .

formato ápice

Este es el formato de un archivo APEX.

Formato de archivo APEX

Figura 1. Formato de archivo APEX

En el nivel superior, un archivo APEX es un archivo zip en el que los archivos se almacenan sin comprimir y se ubican en límites de 4 KB.

Los cuatro archivos en un archivo APEX son:

  • apex_manifest.json
  • AndroidManifest.xml
  • apex_payload.img
  • apex_pubkey

El archivo apex_manifest.json contiene el nombre y la versión del paquete, que identifican un archivo APEX. Este es un búfer de protocolo ApexManifest en formato JSON.

El archivo AndroidManifest.xml permite que el archivo APEX utilice herramientas e infraestructura relacionadas con APK, como ADB, PackageManager y aplicaciones de instalación de paquetes (como Play Store). Por ejemplo, el archivo APEX puede utilizar una herramienta existente como aapt para inspeccionar metadatos básicos del archivo. El archivo contiene el nombre del paquete y la información de la versión. Esta información generalmente también está disponible en apex_manifest.json .

Se recomienda apex_manifest.json sobre AndroidManifest.xml para códigos y sistemas nuevos que tratan con APEX. AndroidManifest.xml puede contener información de orientación adicional que pueden utilizar las herramientas de publicación de aplicaciones existentes.

apex_payload.img es una imagen del sistema de archivos ext4 respaldada por dm-verity. La imagen se monta en tiempo de ejecución mediante un dispositivo loopback. Específicamente, el árbol hash y el bloque de metadatos se crean utilizando la biblioteca libavb . La carga útil del sistema de archivos no se analiza (porque la imagen debería poder montarse en su lugar). Los archivos normales se incluyen dentro del archivo apex_payload.img .

apex_pubkey es la clave pública utilizada para firmar la imagen del sistema de archivos. En tiempo de ejecución, esta clave garantiza que el APEX descargado esté firmado con la misma entidad que firma el mismo APEX en las particiones integradas.

Pautas de nomenclatura de APEX

Para ayudar a evitar conflictos de nombres entre nuevos APEX a medida que avanza la plataforma, utilice las siguientes pautas de nombres:

  • com.android.*
    • Reservado para AOSP APEX. No es exclusivo de ninguna empresa o dispositivo.
  • com.<companyname>.*
    • Reservado para una empresa. Potencialmente utilizado por múltiples dispositivos de esa empresa.
  • com.<companyname>.<devicename>.*
    • Reservado para APEX exclusivos de un dispositivo específico (o subconjunto de dispositivos).

gerente de APEX

El administrador APEX (o apexd ) es un proceso nativo independiente responsable de verificar, instalar y desinstalar archivos APEX. Este proceso se inicia y está listo al principio de la secuencia de inicio. Los archivos APEX normalmente están preinstalados en el dispositivo en /system/apex . El administrador de APEX utiliza de forma predeterminada estos paquetes si no hay actualizaciones disponibles.

La secuencia de actualización de un APEX utiliza la clase PackageManager y es la siguiente.

  1. Un archivo APEX se descarga a través de una aplicación de instalación de paquetes, ADB u otra fuente.
  2. El administrador de paquetes inicia el procedimiento de instalación. Al reconocer que el archivo es APEX, el administrador de paquetes transfiere el control al administrador de APEX.
  3. El administrador APEX verifica el archivo APEX.
  4. Si se verifica el archivo APEX, la base de datos interna del administrador APEX se actualiza para reflejar que el archivo APEX se activa en el próximo inicio.
  5. El solicitante de instalación recibe una transmisión tras la verificación exitosa del paquete.
  6. Para continuar con la instalación, se debe reiniciar el sistema.
  7. En el siguiente inicio, se inicia el administrador APEX, lee la base de datos interna y hace lo siguiente para cada archivo APEX enumerado:

    1. Verifica el archivo APEX.
    2. Crea un dispositivo de loopback a partir del archivo APEX.
    3. Crea un dispositivo de bloque asignador de dispositivos encima del dispositivo de bucle invertido.
    4. Monta el dispositivo de bloque del asignador de dispositivos en una ruta única (por ejemplo, /apex/ name @ ver ).

Cuando se montan todos los archivos APEX enumerados en la base de datos interna, el administrador APEX proporciona un servicio de carpeta para que otros componentes del sistema consulten información sobre los archivos APEX instalados. Por ejemplo, los otros componentes del sistema pueden consultar la lista de archivos APEX instalados en el dispositivo o consultar la ruta exacta donde está montado un APEX específico, para poder acceder a los archivos.

Los archivos APEX son archivos APK

Los archivos APEX son archivos APK válidos porque son archivos zip firmados (utilizando el esquema de firma APK) que contienen un archivo AndroidManifest.xml . Esto permite que los archivos APEX utilicen la infraestructura para archivos APK, como una aplicación de instalación de paquetes, la utilidad de firma y el administrador de paquetes.

El archivo AndroidManifest.xml dentro de un archivo APEX es mínimo y consta del name del paquete, versionCode y targetSdkVersion , minSdkVersion y maxSdkVersion opcionales para una orientación detallada. Esta información permite que los archivos APEX se entreguen a través de canales existentes, como aplicaciones de instalación de paquetes y ADB.

Tipos de archivos admitidos

El formato APEX admite estos tipos de archivos:

  • Bibliotecas compartidas nativas
  • Ejecutables nativos
  • archivos JAR
  • Archivos de información
  • Archivos de configuración

Esto no significa que APEX pueda actualizar todos estos tipos de archivos. La posibilidad de actualizar un tipo de archivo depende de la plataforma y de cuán estables sean las definiciones de las interfaces para los tipos de archivos.

Opciones de firma

Los archivos APEX se firman de dos formas. Primero, el archivo apex_payload.img (específicamente, el descriptor vbmeta adjunto a apex_payload.img ) está firmado con una clave. Luego, todo el APEX se firma utilizando el esquema de firma APK v3 . En este proceso se utilizan dos claves diferentes.

En el lado del dispositivo, se instala una clave pública correspondiente a la clave privada utilizada para firmar el descriptor vbmeta. El administrador de APEX utiliza la clave pública para verificar los APEX cuya instalación se solicita. Cada APEX debe firmarse con claves diferentes y se aplica tanto en el momento de la compilación como en el de la ejecución.

APEX en mamparas empotradas

Los archivos APEX se pueden ubicar en particiones integradas como /system . La partición ya está sobre dm-verity, por lo que los archivos APEX se montan directamente sobre el dispositivo loopback.

Si un APEX está presente en una partición incorporada, el APEX se puede actualizar proporcionando un paquete APEX con el mismo nombre de paquete y un código de versión mayor o igual. El nuevo APEX se almacena en /data y, de manera similar a los APK, la versión recién instalada oculta la versión que ya está presente en la partición integrada. Pero a diferencia de los APK, la versión recién instalada de APEX solo se activa después del reinicio.

Requisitos del núcleo

Para admitir los módulos principales de APEX en un dispositivo Android, se requieren las siguientes funciones del kernel de Linux: el controlador de bucle invertido y dm-verity. El controlador de loopback monta la imagen del sistema de archivos en un módulo APEX y dm-verity verifica el módulo APEX.

El rendimiento del controlador loopback y dm-verity es importante para lograr un buen rendimiento del sistema cuando se utilizan módulos APEX.

Versiones de kernel soportadas

Los módulos principales de APEX son compatibles con dispositivos que utilizan la versión del kernel 4.4 o superior. Los dispositivos nuevos que se inicien con Android 10 o superior deben usar la versión del kernel 4.9 o superior para admitir los módulos APEX.

Parches de kernel necesarios

Los parches del kernel necesarios para admitir módulos APEX se incluyen en el árbol común de Android. Para que los parches sean compatibles con APEX, utilice la última versión del árbol común de Android.

Versión del núcleo 4.4

Esta versión solo es compatible con dispositivos actualizados de Android 9 a Android 10 y desean admitir módulos APEX. Para obtener los parches necesarios, se recomienda encarecidamente una fusión desde la rama android-4.4 . La siguiente es una lista de los parches individuales necesarios para la versión 4.4 del kernel.

  • UPSTREAM: bucle: agregue ioctl para cambiar el tamaño del bloque lógico ( 4.4 )
  • BACKPORT: bloque/bucle: establecer hw_sectors ( 4.4 )
  • UPSTREAM: bucle: agregue LOOP_SET_BLOCK_SIZE en compat ioctl ( 4.4 )
  • ANDROID: mnt: Reparar next_descendent ( 4.4 )
  • ANDROID: mnt: el montaje debe propagarse a los esclavos de los esclavos ( 4.4 )
  • ANDROID: mnt: Propagar el remontaje correctamente ( 4.4 )
  • Revertir "ANDROID: dm verity: agregar tamaño mínimo de captación previa" ( 4.4 )
  • UPSTREAM: bucle: eliminar cachés si se cambia el desplazamiento o el tamaño del bloque ( 4.4 )

Versiones del núcleo 4.9/4.14/4.19

Para obtener los parches necesarios para las versiones del kernel 4.9/4.14/4.19, realice una fusión desde la rama android-common .

Opciones de configuración del kernel requeridas

La siguiente lista muestra los requisitos de configuración básicos para admitir módulos APEX que se introdujeron en Android 10. Los elementos con un asterisco (*) son requisitos existentes de Android 9 y versiones anteriores.

(*) CONFIG_AIO=Y # AIO support (for direct I/O on loop devices)
CONFIG_BLK_DEV_LOOP=Y # for loop device support
CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 # pre-create 16 loop devices
(*) CONFIG_CRYPTO_SHA1=Y # SHA1 hash for DM-verity
(*) CONFIG_CRYPTO_SHA256=Y # SHA256 hash for DM-verity
CONFIG_DM_VERITY=Y # DM-verity support

Requisitos de los parámetros de la línea de comandos del kernel

Para admitir APEX, asegúrese de que los parámetros de la línea de comandos del kernel cumplan con los siguientes requisitos:

  • loop.max_loop NO debe configurarse
  • loop.max_part debe ser <= 8

Construir un APEX

Esta sección describe cómo construir un APEX utilizando el sistema de compilación de Android. El siguiente es un ejemplo de Android.bp para un APEX llamado apex.test .

apex {
    name: "apex.test",
    manifest: "apex_manifest.json",
    file_contexts: "file_contexts",
    // libc.so and libcutils.so are included in the apex
    native_shared_libs: ["libc", "libcutils"],
    binaries: ["vold"],
    java_libs: ["core-all"],
    prebuilts: ["my_prebuilt"],
    compile_multilib: "both",
    key: "apex.test.key",
    certificate: "platform",
}

Ejemplo apex_manifest.json :

{
  "name": "com.android.example.apex",
  "version": 1
}

ejemplo de file_contexts :

(/.*)?           u:object_r:system_file:s0
/sub(/.*)?       u:object_r:sub_file:s0
/sub/file3       u:object_r:file3_file:s0

Tipos de archivos y ubicaciones en APEX

Tipo de archivo Ubicación en APEX
Bibliotecas compartidas /lib y /lib64 ( /lib/arm para brazo traducido en x86)
Ejecutables /bin
bibliotecas java /javalib
Preconstruidos /etc

Dependencias transitivas

Los archivos APEX incluyen automáticamente dependencias transitivas de bibliotecas o ejecutables compartidos nativos. Por ejemplo, si libFoo depende de libBar , las dos bibliotecas se incluyen cuando solo libFoo aparece en la propiedad native_shared_libs .

Manejar múltiples ABI

Instale la propiedad native_shared_libs para las interfaces binarias de aplicaciones (ABI) primarias y secundarias del dispositivo. Si un APEX apunta a dispositivos con una única ABI (es decir, solo 32 bits o solo 64 bits), solo se instalan bibliotecas con la ABI correspondiente.

Instale la propiedad binaries solo para la ABI principal del dispositivo como se describe a continuación:

  • Si el dispositivo es solo de 32 bits, solo se instala la variante de 32 bits del binario.
  • Si el dispositivo es solo de 64 bits, entonces solo se instala la variante de 64 bits del binario.

Para agregar un control detallado sobre las ABI de las bibliotecas nativas y los binarios, use las propiedades multilib.[first|lib32|lib64|prefer32|both].[native_shared_libs|binaries] .

  • first : coincide con el ABI principal del dispositivo. Este es el valor predeterminado para los binarios.
  • lib32 : coincide con la ABI de 32 bits del dispositivo, si es compatible.
  • lib64 : Coincide con la ABI de 64 bits del dispositivo, es compatible.
  • prefer32 : coincide con la ABI de 32 bits del dispositivo, si es compatible. Si no se admite la ABI de 32 bits, coincide con la ABI de 64 bits.
  • both : coincide con ambos ABI. Este es el valor predeterminado para native_shared_libraries .

Las propiedades java , libraries y prebuilts son independientes de ABI.

Este ejemplo es para un dispositivo que admite 32/64 y no prefiere 32:

apex {
    // other properties are omitted
    native_shared_libs: ["libFoo"], // installed for 32 and 64
    binaries: ["exec1"], // installed for 64, but not for 32
    multilib: {
        first: {
            native_shared_libs: ["libBar"], // installed for 64, but not for 32
            binaries: ["exec2"], // same as binaries without multilib.first
        },
        both: {
            native_shared_libs: ["libBaz"], // same as native_shared_libs without multilib
            binaries: ["exec3"], // installed for 32 and 64
        },
        prefer32: {
            native_shared_libs: ["libX"], // installed for 32, but not for 64
        },
        lib64: {
            native_shared_libs: ["libY"], // installed for 64, but not for 32
        },
    },
}

firma vbmeta

Firme cada APEX con claves diferentes. Cuando se requiera una nueva clave, cree un par de claves pública-privada y cree un módulo apex_key . Utilice la propiedad key para firmar el APEX utilizando la clave. La clave pública se incluye automáticamente en APEX con el nombre avb_pubkey .

# create an rsa key pair
openssl genrsa -out foo.pem 4096

# extract the public key from the key pair
avbtool extract_public_key --key foo.pem --output foo.avbpubkey

# in Android.bp
apex_key {
    name: "apex.test.key",
    public_key: "foo.avbpubkey",
    private_key: "foo.pem",
}

En el ejemplo anterior, el nombre de la clave pública ( foo ) se convierte en el ID de la clave. El ID de la clave utilizada para firmar un APEX está escrito en el APEX. En tiempo de ejecución, apexd verifica APEX utilizando una clave pública con la misma ID en el dispositivo.

firma APEX

Firme APEX de la misma manera que firma APK. Firme APEX dos veces; una vez para el mini sistema de archivos (archivo apex_payload.img ) y una vez para el archivo completo.

Para firmar un APEX a nivel de archivo, establezca la propiedad certificate de una de estas tres maneras:

  • No establecido: si no se establece ningún valor, el APEX se firma con el certificado ubicado en PRODUCT_DEFAULT_DEV_CERTIFICATE . Si no se establece ningún indicador, la ruta predeterminada es build/target/product/security/testkey .
  • <name> : APEX está firmado con el certificado <name> en el mismo directorio que PRODUCT_DEFAULT_DEV_CERTIFICATE .
  • :<name> : El APEX está firmado con el certificado definido por el módulo Soong llamado <name> . El módulo de certificado se puede definir de la siguiente manera.
android_app_certificate {
    name: "my_key_name",
    certificate: "dir/cert",
    // this will use dir/cert.x509.pem (the cert) and dir/cert.pk8 (the private key)
}

Instalar un APEX

Para instalar un APEX, utilice ADB.

adb install apex_file_name
adb reboot

Si supportsRebootlessUpdate se establece en true en apex_manifest.json y el APEX actualmente instalado no se utiliza (por ejemplo, todos los servicios que contiene se han detenido), entonces se puede instalar un nuevo APEX sin reiniciar con el indicador --force-non-staged .

adb install --force-non-staged apex_file_name

Utilice un APEX

Después de reiniciar, APEX se monta en el directorio /apex/<apex_name>@<version> . Se pueden montar varias versiones del mismo APEX al mismo tiempo. Entre las rutas de montaje, la que corresponde a la última versión está montada en enlace en /apex/<apex_name> .

Los clientes pueden utilizar la ruta montada en enlace para leer o ejecutar archivos desde APEX.

Los APEX se utilizan normalmente de la siguiente manera:

  1. Un OEM u ODM precarga un APEX en /system/apex cuando se envía el dispositivo.
  2. Se accede a los archivos en APEX a través de la ruta /apex/<apex_name>/ .
  3. Cuando se instala una versión actualizada de APEX en /data/apex , la ruta apunta al nuevo APEX después del reinicio.

Actualizar un servicio con un APEX

Para actualizar un servicio usando un APEX:

  1. Marque el servicio en la partición del sistema como actualizable. Agregue la opción updatable a la definición del servicio.

    /system/etc/init/myservice.rc:
    
    service myservice /system/bin/myservice
        class core
        user system
        ...
        updatable
    
  2. Cree un nuevo archivo .rc para el servicio actualizado. Utilice la opción override para redefinir el servicio existente.

    /apex/my.apex/etc/init.rc:
    
    service myservice /apex/my.apex/bin/myservice
        class core
        user system
        ...
        override
    

Las definiciones de servicios solo se pueden definir en el archivo .rc de un APEX. Los desencadenadores de acciones no son compatibles con APEX.

Si un servicio marcado como actualizable se inicia antes de que se activen los APEX, el inicio se retrasa hasta que se complete la activación de los APEX.

Configurar el sistema para admitir actualizaciones de APEX

Establezca la siguiente propiedad del sistema en true para admitir actualizaciones de archivos APEX.

<device.mk>:

PRODUCT_PROPERTY_OVERRIDES += ro.apex.updatable=true

BoardConfig.mk:
TARGET_FLATTEN_APEX := false

o solo

<device.mk>:

$(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)

ÁPICE aplanado

Para dispositivos heredados, a veces es imposible o inviable actualizar el kernel antiguo para que sea totalmente compatible con APEX. Por ejemplo, es posible que el kernel se haya creado sin CONFIG_BLK_DEV_LOOP=Y , lo cual es crucial para montar la imagen del sistema de archivos dentro de un APEX.

Flattened APEX es un APEX especialmente diseñado que se puede activar en dispositivos con un kernel heredado. Los archivos en un APEX aplanado se instalan directamente en un directorio debajo de la partición incorporada. Por ejemplo, lib/libFoo.so en un APEX aplanado my.apex se instala en /system/apex/my.apex/lib/libFoo.so .

La activación de un APEX aplanado no implica el dispositivo de bucle. Todo el directorio /system/apex/my.apex está directamente montado en /apex/name@ver .

Los APEX aplanados no se pueden actualizar descargando versiones actualizadas de los APEX de la red porque los APEX descargados no se pueden aplanar. Los APEX aplanados solo se pueden actualizar a través de una OTA normal.

APEX aplanado es la configuración predeterminada. Esto significa que todos los APEX están aplanados de forma predeterminada, a menos que configure explícitamente su dispositivo para crear APEX no aplanados para admitir actualizaciones de APEX (como se explicó anteriormente).

NO se admite la mezcla de APEX aplanados y no aplanados en un dispositivo. Los APEX de un dispositivo deben estar todos aplanados o no aplanados. Esto es especialmente importante cuando se envían elementos prediseñados de APEX firmados para proyectos como Mainline. Los APEX que no están prefirmados (es decir, creados a partir de la fuente) tampoco deben estar aplanados y firmados con las claves adecuadas. El dispositivo debe heredar de updatable_apex.mk como se explica en Actualización de un servicio con APEX .

APEX comprimidos

Android 12 y versiones posteriores cuentan con compresión APEX para reducir el impacto del almacenamiento de los paquetes APEX actualizables. Después de instalar una actualización de un APEX, aunque su versión preinstalada ya no se usa, sigue ocupando la misma cantidad de espacio. Ese espacio ocupado sigue sin estar disponible.

La compresión APEX minimiza este impacto en el almacenamiento mediante el uso de un conjunto altamente comprimido de archivos APEX en particiones de solo lectura (como la partición /system ). Android 12 y versiones posteriores utilizan un algoritmo de compresión zip DEFLATE.

La compresión no proporciona optimización para lo siguiente:

  • Bootstrap APEX que deben montarse muy temprano en la secuencia de inicio.

  • APEX no actualizables. La compresión solo es beneficiosa si se instala una versión actualizada de APEX en la partición /data . Una lista completa de APEX actualizables está disponible en la página Componentes del sistema modular .

  • APEX de bibliotecas compartidas dinámicas. Dado que apexd siempre activa ambas versiones de dichos APEX (preinstalados y actualizados), comprimirlos no agrega valor.

Formato de archivo APEX comprimido

Este es el formato de un archivo APEX comprimido.

Diagram shows the format of a compressed APEX file

Figura 2. Formato de archivo APEX comprimido

En el nivel superior, un archivo APEX comprimido es un archivo zip que contiene el archivo apex original en forma desinflada con un nivel de compresión de 9 y con otros archivos almacenados sin comprimir.

Cuatro archivos componen un archivo APEX:

  • original_apex : desinflado con nivel de compresión de 9. Este es el archivo APEX original sin comprimir.
  • apex_manifest.pb : solo almacenado
  • AndroidManifest.xml : solo almacenado
  • apex_pubkey : solo almacenado

Los archivos apex_manifest.pb , AndroidManifest.xml y apex_pubkey son copias de sus archivos correspondientes en original_apex .

Construir APEX comprimido

APEX comprimido se puede construir usando la herramienta apex_compression_tool.py ubicada en system/apex/tools .

Varios parámetros relacionados con la compresión APEX están disponibles en el sistema de compilación.

En Android.bp , la propiedad compressible controla si un archivo APEX es comprimible:

apex {
    name: "apex.test",
    manifest: "apex_manifest.json",
    file_contexts: "file_contexts",
    compressible: true,
}

Un indicador de producto PRODUCT_COMPRESSED_APEX controla si una imagen del sistema creada a partir del código fuente debe contener archivos APEX comprimidos.

Para la experimentación local, puede forzar una compilación para comprimir APEX configurando OVERRIDE_PRODUCT_COMPRESSED_APEX= en true .

Los archivos APEX comprimidos generados por el sistema de compilación tienen la extensión .capex . La extensión facilita la distinción entre versiones comprimidas y sin comprimir de un archivo APEX.

Algoritmos de compresión soportados

Android 12 solo admite la compresión deflate-zip.

Activar un archivo APEX comprimido durante el arranque

Antes de que se pueda activar un APEX comprimido, el archivo original_apex que contiene se descomprime en el directorio /data/apex/decompressed . El archivo APEX descomprimido resultante está vinculado al directorio /data/apex/active .

Considere el siguiente ejemplo como una ilustración del proceso descrito anteriormente.

Considere /system/apex/com.android.foo.capex como un APEX comprimido que se activa, con el código de versión 37.

  1. El archivo original_apex dentro de /system/apex/com.android.foo.capex se descomprime en /data/apex/decompressed/com.android.foo@37.apex .
  2. Se realiza restorecon /data/apex/decompressed/com.android.foo@37.apex para verificar que tiene una etiqueta SELinux correcta.
  3. Las comprobaciones de verificación se realizan en /data/apex/decompressed/com.android.foo@37.apex para garantizar su validez: apexd verifica la clave pública incluida en /data/apex/decompressed/com.android.foo@37.apex para verifique que sea igual al incluido en /system/apex/com.android.foo.capex .
  4. El archivo /data/apex/decompressed/com.android.foo@37.apex está vinculado al directorio /data/apex/active/com.android.foo@37.apex .
  5. La lógica de activación normal para archivos APEX sin comprimir se realiza en /data/apex/active/com.android.foo@37.apex .

Interacción con la OTA

Los archivos APEX comprimidos tienen implicaciones en la entrega y aplicación OTA. Dado que una actualización OTA puede contener un archivo APEX comprimido con un nivel de versión superior al que está activo en un dispositivo, se debe reservar una cierta cantidad de espacio libre antes de reiniciar un dispositivo para aplicar una actualización OTA.

Para admitir el sistema OTA, apexd expone estas dos API de carpeta:

  • calculateSizeForCompressedApex : calcula el tamaño necesario para descomprimir archivos APEX en un paquete OTA. Esto se puede utilizar para verificar que un dispositivo tenga suficiente espacio antes de descargar una OTA.
  • reserveSpaceForCompressedApex : reserva espacio en el disco para uso futuro de apexd para descomprimir archivos APEX comprimidos dentro del paquete OTA.

En el caso de una actualización A/B OTA, apexd intenta la descompresión en segundo plano como parte de la rutina OTA posterior a la instalación. Si la descompresión falla, apexd realiza la descompresión durante el inicio que aplica la actualización OTA.

Alternativas consideradas al desarrollar APEX

A continuación se muestran algunas opciones que AOSP consideró al diseñar el formato de archivo APEX y por qué se incluyeron o excluyeron.

Sistemas habituales de gestión de paquetes.

Las distribuciones de Linux tienen sistemas de administración de paquetes como dpkg y rpm , que son potentes, maduros y robustos. Sin embargo, no fueron adoptados para APEX porque no pueden proteger los paquetes después de la instalación. La verificación se realiza sólo cuando se están instalando paquetes. Los atacantes pueden romper la integridad de los paquetes instalados, sin ser detectados. Esta es una regresión para Android donde todos los componentes del sistema se almacenaron en sistemas de archivos de solo lectura cuya integridad está protegida por dm-verity para cada E/S. Cualquier manipulación de los componentes del sistema debe estar prohibida o ser detectable para que el dispositivo pueda negarse a arrancar si se ve comprometido.

dm-crypt para la integridad

Los archivos en un contenedor APEX provienen de particiones integradas (por ejemplo, la partición /system ) que están protegidas por dm-verity, donde cualquier modificación de los archivos está prohibida incluso después de montar las particiones. Para proporcionar el mismo nivel de seguridad a los archivos, todos los archivos en un APEX se almacenan en una imagen del sistema de archivos que está emparejada con un árbol hash y un descriptor vbmeta. Sin dm-verity, un APEX en la partición /data es vulnerable a modificaciones no deseadas que se realizan después de haber sido verificado e instalado.

De hecho, la partición /data también está protegida por capas de cifrado como dm-crypt. Aunque esto proporciona cierto nivel de protección contra la manipulación, su objetivo principal es la privacidad, no la integridad. Cuando un atacante obtiene acceso a la partición /data , no puede haber más protección, y esto nuevamente es una regresión en comparación con todos los componentes del sistema que están en la partición /system . El árbol hash dentro de un archivo APEX junto con dm-verity proporciona el mismo nivel de protección de contenido.

Redirigir rutas de /system a /apex

Se puede acceder a los archivos de componentes del sistema empaquetados en un APEX a través de nuevas rutas como /apex/<name>/lib/libfoo.so . Cuando los archivos formaban parte de la partición /system , se podía acceder a ellos a través de rutas como /system/lib/libfoo.so . Un cliente de un archivo APEX (otros archivos APEX o la plataforma) debe utilizar las nuevas rutas. Es posible que deba actualizar el código existente como resultado del cambio de ruta.

Aunque una forma de evitar el cambio de ruta es superponer el contenido del archivo en un archivo APEX en la partición /system , el equipo de Android decidió no superponer archivos en la partición /system porque esto podría afectar el rendimiento debido a la cantidad de archivos que se superponen ( posiblemente incluso apilados uno tras otro) aumentaron.

Otra opción era secuestrar funciones de acceso a archivos como open , stat y readlink , de modo que las rutas que comenzaran con /system fueran redirigidas a sus rutas correspondientes en /apex . El equipo de Android descartó esta opción porque es inviable cambiar todas las funciones que aceptan rutas. Por ejemplo, algunas aplicaciones vinculan estáticamente Bionic, que implementa las funciones. En tales casos, esas aplicaciones no son redirigidas.