Artefactos auxiliares de un APK

referencia técnica · Revisado el 12 de agosto de 2026

1. Qué es y por qué existe

Un APK real tiene mucho más de lo que aparece en cualquier diagrama de anatomía. Junto al manifiesto, el DEX, resources.arsc, res/ y lib/ conviven decenas —a veces cientos— de entradas que no encajan en ninguna de esas categorías: metadatos de firma, perfiles de compilación, descriptores de servicio de Java, ficheros de versión de cada dependencia, recursos de bibliotecas que se colaron desde su .jar original. En eu.faircode.email_2318.apk del corpus hay 166 entradas en la raíz o sin categoría, 66 ficheros .version bajo META-INF/ y 8 .kotlin_builtins.

Nada de eso es basura, y casi nada es aleatorio. Cada grupo es la huella de una pieza concreta de la cadena de construcción: META-INF/*.version significa AndroidX, DebugProbesKt.bin significa kotlinx-coroutines, assets/dexopt/baseline.prof significa que alguien se preocupó del arranque. Leer ese inventario da, antes de decompilar nada, el stack sobre el que está construida la aplicación.

Este documento inventaria y describe esos artefactos, y aclara además una confusión frecuente: los ficheros que no están dentro del APK pero aparecen cuando se investiga en un dispositivo —.odex, .vdex, .oat, .art—, qué son y por qué el DEX del APK sigue siendo la fuente de verdad.

El detalle criptográfico de la firma v1 no está aquí, sino en Esquemas v1, v2 y v3. Aquí solo el inventario y el formato de texto.

2. META-INF/

Es un directorio con nombre reservado que Android hereda del formato JAR de Java. Su contenido se divide en cuatro grupos con orígenes distintos.

Grupo Entradas Lo pone
Firma v1 MANIFEST.MF, *.SF, *.RSA / *.DSA / *.EC apksigner o jarsigner
Metadatos de Java services/, versions/, *.kotlin_module Copiados de los .jar de las dependencias
Metadatos de build com/android/build/gradle/app-metadata.properties, version-control-info.textproto, *.version AGP
Resto native-image/, *.properties, licencias Las dependencias, sin filtrar

2.1 MANIFEST.MF

Fichero de texto con la gramática del JAR: una sección principal con atributos globales, una línea en blanco, y luego una sección por entrada con su digest.

manifest-file:      main-section newline *individual-section
main-section:       version-info newline *main-attribute
individual-section: Name : value newline *perentry-attribute

Dos reglas de formato que muerden a quien lo escriba:

  • «No line may be longer than 72 bytes (in UTF-8 encoded form)». Lo que sobra continúa en la línea siguiente empezando por un espacio. Un nombre de fichero largo se parte, y reconstruirlo mal produce un digest que no valida.
  • Los nombres de cabecera no se repiten dentro de una sección y su longitud máxima es de 70 bytes.

Contenido real de eu.faircode.email_2318.apk:

Manifest-Version: 1.0

Name: AndroidManifest.xml
SHA-256-Digest: 9EfxvZLEAOD2+jEmNu9nu2+x7C7jpwuyCUIqAfVwyaE=

Name: EmojiReference.txt
SHA-256-Digest: JHTJCDKXj8NxyqaKAY/OGmdtIBtWCKWE/6idHTCEJgU=

Hay una sección Name: por cada entrada del ZIP salvo las del propio META-INF/ que participan en la firma, con el digest en base64 de su contenido descomprimido.

2.2 *.SF

El fichero de firma. Misma gramática, pero los digests no son de los ficheros: son de las secciones de MANIFEST.MF. Ese doble nivel es lo que permite verificar la integridad del propio manifiesto sin recorrer todas las entradas.

Signature-Version: 1.0
Created-By: 1.0 (Android)
SHA-256-Digest-Manifest: m26RkTMb+iMPYOc3UvVskWmTPW4hHW2PVM8noQY+XO0=
X-Android-APK-Signed: 2, 3

Name: AndroidManifest.xml
SHA-256-Digest: Hz4mtPY9Y8CSLhP1DI4kwE7sOn0kD0guSy4cEMCVQC4=
  • SHA-256-Digest-Manifest cubre el MANIFEST.MF entero. Es la variante x-Digest-Manifest de la especificación JAR.
  • Cada Name: lleva el digest de su bloque de texto dentro de MANIFEST.MF, no del fichero. Por eso el valor de AndroidManifest.xml difiere entre los dos ficheros.
  • X-Android-APK-Signed es una extensión de Android, no del JAR. Declara qué esquemas modernos firman también este APK —aquí, v2 y v3— para que un verificador que los soporte no acepte una degradación a v1 a secas.

2.3 *.RSA, *.DSA, *.EC

El bloque de firma binario: un mensaje PKCS#7/CMS que contiene la firma sobre el .SF y la cadena de certificados. La especificación JAR reserva:

  • META-INF/*.SF — fichero de firma
  • META-INF/*.RSA — firma PKCS7 (SHA-256 + RSA)
  • META-INF/*.DSA — firma PKCS7 con DSA
  • META-INF/*.EC — firma PKCS7 con ECDSA
  • META-INF/SIG-* — firmas con algoritmos no estándar

El nombre base lo elige el firmante y no significa nada: en el corpus aparecen CIARANG.SF/CIARANG.RSA (F-Droid), 84D3000E.SF/84D3000E.RSA (Termux), 20821372.SF/20821372.RSA (FairEmail) y APKMIRRO.RSA en los contenedores .apkm. El .SF y el bloque tienen que compartir el nombre base; la extensión declara el algoritmo.

Puede haber más de un juego .SF + bloque: son firmantes distintos sobre el mismo MANIFEST.MF.

2.4 services/

El mecanismo ServiceLoader de Java: un fichero por interfaz, con el nombre completamente cualificado de la interfaz como nombre de fichero y las implementaciones dentro, una por línea. En eu.faircode.email_2318.apk:

META-INF/services/java.nio.charset.spi.CharsetProvider
META-INF/services/java.security.Provider
META-INF/services/javax.mail.Provider
META-INF/services/org.tinylog.provider.LoggingProvider
META-INF/services/d4
META-INF/services/e4

Las dos últimas líneas son el detalle interesante: d4 y e4 son nombres ofuscados por R8. El renombrado de clases alcanza a los ficheros de services/, porque su nombre es un nombre de clase. Cuando se ve un META-INF/services/ con nombres de una o dos letras, se está mirando una aplicación con R8 en modo completo.

2.5 versions/ y los multi-release JAR

META-INF/versions/<N>/ es el mecanismo de multi-release JAR de Java 9 (JEP 238): permite empaquetar en el mismo archivo una versión alternativa de una clase para cada versión del runtime. La activación exige un atributo en el manifiesto:

«The manifest entry Multi-Release: true must be set to create a Multi-Release JAR File»

En el corpus hay 15 APK con entradas bajo META-INF/versions/, con rutas como META-INF/versions/9/OSGI-INF/MANIFEST.MF o META-INF/versions/11/…, y ninguno de los 15 lleva Multi-Release en su MANIFEST.MF. Son restos que vienen dentro de los .jar de las dependencias y que el empaquetador copió sin filtrar.

⚠️ sin verificar: no se ha localizado documentación de AOSP sobre si ART implementa la resolución multi-release. La observación anterior es del corpus, no de la especificación.

2.6 *.kotlin_module

Un fichero binario por módulo de Kotlin, con el nombre META-INF/<módulo>_<buildType>.kotlin_module. Contiene los metadatos que el compilador necesita para resolver funciones y propiedades de nivel superior —las que en el bytecode viven en una clase sintética FooKt—. Solo lo consume el compilador de Kotlin al enlazar contra la biblioteca; en tiempo de ejecución es peso muerto dentro de un APK. Su ausencia rompe la compilación contra esa biblioteca, no su ejecución.

2.7 Metadatos de build

Tres artefactos que AGP escribe y que sirven de huella exacta de la cadena de construcción:

Entrada Contenido
META-INF/com/android/build/gradle/app-metadata.properties Versión del formato y del plugin
META-INF/version-control-info.textproto Sistema de control de versiones y commit exacto
META-INF/<grupo>_<artefacto>.version Un fichero por dependencia AndroidX, con su versión

Contenido real de eu.faircode.email_2318.apk:

appMetadataVersion=1.1
androidGradlePluginVersion=9.2.1
repositories {
  system: GIT
  local_root_path: "$PROJECT_DIR"
  revision: "96852054a5be335f6ea971c338891ec1c97044db"
}

El version-control-info.textproto es el más jugoso de los tres: da el hash de commit exacto con el que se construyó el APK. En una aplicación de código abierto, eso permite reproducir la compilación; en una cerrada, es una fuga de información menor pero real.

3. Baseline profiles

3.1 Qué son

Un baseline profile es una lista de métodos y clases que conviene compilar por adelantado, para que ART no tenga que interpretarlos ni compilarlos con JIT en el primer arranque.

«A Baseline Profile is a Profile Guided Optimization (PGO) mechanism that improves code execution speed by about 30% from the first launch by avoiding interpretation and just-in-time (JIT) compilation steps for included code paths.»

«During installation, ART performs AOT compilation of the methods in the profile, resulting in those methods executing faster.»

Viven en dos entradas fijas del APK:

Entrada Qué es
assets/dexopt/baseline.prof El perfil binario en el formato que consume ART
assets/dexopt/baseline.profm Los metadatos que permiten transcodificar el perfil a otra versión del formato

El .profm existe porque «ART profiles formats aren't forward or backward compatible», así que profgen empaqueta metadatos con los que androidx.profileinstaller puede convertir el perfil al formato que espera el dispositivo concreto.

3.2 Formato a alto nivel

Ambos empiezan por una cabecera de 8 bytes: 4 de magia y 4 de versión, ambos terminados en \0. En eu.faircode.email_2318.apk:

baseline.prof   →  7072 6f00 3031 3000 …     "pro\0" "010\0"
baseline.profm  →  7072 6d00 3030 3200 …     "prm\0" "002\0"

que corresponden a las constantes de androidx.profileinstaller:

MAGIC_PROF  = new byte[]{'p', 'r', 'o', '\u0000'}
MAGIC_PROFM = new byte[]{'p', 'r', 'm', '\u0000'}

Detrás de la cabecera van unos pocos campos de tamaño y luego un bloque comprimido: los bytes 78 01, cabecera típica de zlib, aparecen en el offset 0x11 de baseline.prof y en el 0x14 de baseline.profm. Dentro, según la documentación del formato en AOSP, hay una lista de ficheros DEX con su checksum y su clave de perfil, y luego las secciones de clases y de métodos con sus banderas y sus mapas de bits.

La versión del formato importa y no es estable. AOSP declara hoy:

const uint8_t ProfileCompilationInfo::kProfileMagic[] = { 'p', 'r', 'o', '\0' };
const uint8_t ProfileCompilationInfo::kProfileVersion[] = { '0', '1', '5', '\0' };
const uint8_t ProfileCompilationInfo::kProfileVersionForBootImage[] = { '0', '1', '6', '\0' };

es decir 015, mientras que el fichero del corpus lleva 010. Esa distancia es exactamente el motivo por el que el .profm va al lado: el perfil que se empaqueta no tiene por qué estar en el formato del dispositivo que lo va a instalar.

3.3 Cuánto se usa

52 de los 58 APK standalone del corpus llevan las dos entradas —entre ellos FairEmail, Bitwarden, AnkiDroid, Nextcloud, OpenVPN, StreetComplete y todo el conjunto de Fossify—, siempre en pareja baseline.prof + baseline.profm. Es hoy la norma, no la excepción.

4. assets/

4.1 Frente a res/

La diferencia es de indexación, no de contenido:

«Files saved in the assets/ directory are not given a resource ID, so you can't reference them through the R class or from XML resources. Instead, you can query files in the assets/ directory like a normal file system and read raw data using AssetManager

«However, if you need access to the original filenames and file hierarchy, consider saving resources in the assets/ directory instead of res/raw/

res/ assets/
Indexado en resources.arsc No
Identificador resource ID de 32 bits Ninguno: se abre por ruta
Nombre y jerarquía original Se pierden al compilar Se conservan
Se resuelve por configuración Sí (idioma, densidad, versión) No
API Resources, R.* AssetManager.open()

Consecuencia para el análisis: al deofuscar recursos se pueden recuperar nombres desde resources.arsc, porque el nombre está en la tabla (Tabla de recursos). En assets/ no hay nada que recuperar: el nombre que hay es el nombre que puso el desarrollador. Si es ilegible, es que se eligió ilegible.

4.2 Qué se encuentra ahí

En eu.faircode.email_2318.apk, 106 entradas bajo assets/: documentación (ATTRIBUTION.md, CHANGELOG.md), una guía de configuración traducida a decenas de idiomas (SETUP-es.md, SETUP-ja.md…) y bases de datos de texto (PublicSuffixDatabase.list). Es el uso normal.

El uso que importa al analizar es el otro. assets/ es un sistema de ficheros opaco dentro del APK, sin índice y sin restricciones de nombre, y por eso es donde acaban:

  • El payload de los packers. Un packer sustituye el DEX original por un stub y guarda el código real cifrado, con frecuencia bajo assets/. Ver Packers y protectores; desempaquetarlos está fuera del alcance de este corpus.
  • Modelos de aprendizaje automático (.tflite, .onnx).
  • Bases de datos precargadas (.db, .sqlite, .realm).
  • Bibliotecas nativas escondidas, para saltarse la convención de lib/<abi>/ y cargarlas a mano tras copiarlas a disco.
  • Claves, certificados y configuración, con frecuencia cifrados de forma trivial.

Un inventario de assets/ por extensión y tamaño es una de las señales más baratas de que algo no es una aplicación corriente.

5. El lado del dispositivo: dex2oat, .odex, .vdex, .oat, .art

Nada de esta sección está dentro de un APK. Se documenta aquí porque aparece en cuanto se investiga una aplicación instalada y se confunde con el contenido del paquete.

5.1 Qué hace dex2oat

dex2oat es el compilador de ART: «takes an APK file and generates one or more compilation artifact files that the runtime loads». Se ejecuta en el dispositivo al instalar y, según la política, también en segundo plano.

Artefacto Contenido, según AOSP
.vdex «Contains some additional metadata to speed up verification, sometimes along with the uncompressed DEX code of the APK»
.odex «Contains AOT-compiled code for methods in the APK»
.art «Contains ART internal representations of some strings and classes listed in the APK, used to speed up app startup»

El .oat es el formato de contenedor del código compilado; desde Android 8 la copia del DEX original vive en el .vdex y el .odex contiene solo el código nativo.

5.2 Filtros de compilación

Lo que se compila depende del compiler filter:

Filtro Qué hace
verify «Runs only DEX code verification (no AOT compilation)»
quicken (Android 11 o anterior) Verifica y optimiza algunas instrucciones DEX para el intérprete
speed «Runs DEX code verification and AOT-compiles all methods»
speed-profile Verifica, compila AOT los métodos del perfil y optimiza la carga de sus clases

speed-profile es el que consume el baseline profile de la sección 3.

5.3 Dónde viven

El comentario del código de AOSP que construye la ruta:

// The odex file name is formed by replacing the dex_location extension with
// .odex and inserting an oat/<isa> directory. For example:
// location = /foo/bar/baz.jar
// odex_location = /foo/bar/oat/<isa>/baz.odex

Aplicado a una aplicación instalada, el base.apk vive bajo /data/app/…/<paquete>-…/ y sus artefactos aparecen en oat/<isa>/ al lado, con <isa> la arquitectura (arm64, arm, x86_64). ⚠️ no ejecutado localmente: adb no está en el PATH de esta máquina, así que no se ha listado el directorio en un dispositivo real. La forma de la ruta procede del código de AOSP citado; el prefijo exacto bajo /data/app/ varía por versión de Android y lleva sufijos aleatorios desde Android 10.

5.4 Por qué el DEX del APK sigue siendo la fuente de verdad

Tres razones, y conviene tenerlas claras antes de perder tiempo con un .odex:

  1. Son derivados y regenerables. Todo lo que hay en oat/ sale del APK. Borrarlo hace que el sistema lo reconstruya.
  2. Son específicos del dispositivo. Dependen de la arquitectura, de la versión de ART y del perfil de uso de ese usuario. Dos dispositivos con el mismo APK producen .odex distintos.
  3. El formato no es estable ni está especificado como contrato público. Cambia entre versiones de Android, y ninguna herramienta del ecosistema lo trata como formato de entrada de primera clase.

La única situación en la que el .vdex importa de verdad es cuando el APK no contiene el DEX que se ejecuta: aplicaciones de sistema entregadas ya compiladas, o un packer que genera el DEX real en ejecución. En ambos casos se está haciendo análisis dinámico, no estático, y eso es otro documento.

5.5 Perfiles en la nube

Junto al baseline profile que el desarrollador empaqueta, Play distribuye perfiles agregados del uso real:

«Cloud Profiles offer an additional form of PGO—aggregated by Google Play Store and distributed for install time compilation—together with Baseline Profiles. While Cloud Profiles are driven by real-world user interactions with the app, they take several hours to days after an update to be distributed […] Cloud Profiles only support Android devices running Android 9 (API level 28) or higher, and only scale well for apps that have a sufficiently large user base.»

Para el análisis del APK esto es irrelevante —el perfil no viaja dentro— pero explica por qué el mismo APK puede tener rendimientos distintos según cuándo se instale.

6. Otros artefactos que aparecen en APK reales

Cada uno es la firma de una pieza del stack. Todos verificados en el corpus.

Entrada Qué es Qué delata
stamp-cert-sha256 32 bytes: el SHA-256 del certificado del source stamp APK distribuido por Google Play. Su bloque compañero en el APK Signing Block es V2_SOURCE_STAMP_BLOCK_ID = 0x6dff800d
DebugProbesKt.bin Clase precompilada de kotlinx-coroutines-debug Uso de corrutinas de Kotlin. Presente en más de 25 APK del corpus
kotlin/*.kotlin_builtins Descriptores binarios de los tipos base de Kotlin Que la aplicación es Kotlin y que el empaquetador no filtró la biblioteca estándar
kotlin-tooling-metadata.json Metadatos del plugin de Kotlin: versión y targets Versión exacta del compilador de Kotlin
okhttp3/internal/publicsuffix/publicsuffixes.gz Lista de sufijos públicos que OkHttp usa para las cookies Uso de OkHttp, y con él Retrofit en la mayoría de los casos
META-INF/native-image/… Configuración de GraalVM que traen Netty y jansi Dependencias de servidor arrastradas a una aplicación móvil
androidsupportmultidexversion.txt Marca de la biblioteca multidex de soporte minSdk bajo con más de 65.536 métodos
firebase-*, com/google/firebase/… Recursos y metadatos de los SDK de Firebase Analítica, notificaciones o Crashlytics

En org.videolan.vlc_13070108.apk conviven en la raíz DebugProbesKt.bin, kotlin-tooling-metadata.json, androidsupportmultidexversion.txt, car-app-api.level, árboles enteros de org/bouncycastle/ con sus ficheros de mensajes traducidos, y —el caso más llamativo— org/fusesource/jansi/internal/native/Mac/arm64/libjansi.jnilib y org/fusesource/jansi/internal/native/Windows/x86_64/jansi.dll: binarios de macOS y de Windows dentro de un APK de Android, arrastrados desde el .jar de jansi y completamente inertes.

Cómo se lee esto: un artefacto en un sitio donde no puede ejecutarse indica que el empaquetador copió un .jar entero sin filtrar. No es un problema de seguridad, es tamaño desperdiciado y una pista muy fiable sobre la disciplina del proyecto.

7. Receta: inventario comentado por categorías

Ejecutado el 12 de agosto de 2026 con unzip y awk del sistema.

CORPUS=~/corpus-apk
unzip -l $CORPUS/org.videolan.vlc_13070108.apk | awk '
  NR>3 && NF>=4 { p=$4
    if (p ~ /^-+$/ || p=="") next
    if      (p=="AndroidManifest.xml")            k="01 manifiesto"
    else if (p ~ /^classes[0-9]*\.dex$/)          k="02 codigo DEX"
    else if (p=="resources.arsc")                 k="03 tabla de recursos"
    else if (p ~ /^res\//)                        k="04 res/"
    else if (p ~ /^assets\/dexopt\//)             k="05 baseline profile"
    else if (p ~ /^assets\//)                     k="06 assets/"
    else if (p ~ /^lib\//)                        k="07 lib/"
    else if (p ~ /^META-INF\/(MANIFEST\.MF|.*\.(SF|RSA|DSA|EC))$/) k="08 META-INF firma v1"
    else if (p ~ /^META-INF\/services\//)         k="09 META-INF services/"
    else if (p ~ /^META-INF\/versions\//)         k="10 META-INF versions/"
    else if (p ~ /\.kotlin_module$/)              k="11 kotlin_module"
    else if (p ~ /^META-INF\/.*\.version$/)       k="12 META-INF .version"
    else if (p ~ /^META-INF\//)                   k="13 META-INF otros"
    else if (p ~ /^kotlin\//)                     k="14 kotlin/ builtins"
    else if (p ~ /^okhttp3\//)                    k="15 okhttp3/"
    else                                          k="99 raiz y otros"
    c[k]++ }
  END { for (k in c) printf "%-24s %6d\n", k, c[k] }' | sort
01 manifiesto                 1
02 codigo DEX                 6
03 tabla de recursos          1
04 res/                    2424
05 baseline profile           2
06 assets/                  115
07 lib/                       4
08 META-INF firma v1          3
09 META-INF services/         7
13 META-INF otros            21
14 kotlin/ builtins           8
15 okhttp3/                   2
99 raiz y otros              24

Se lee así: seis classes*.dex (multidex a lo grande), firma v1 presente, dos ficheros de baseline profile, ocho kotlin_builtins y okhttp3/ — Kotlin más OkHttp —, y 24 entradas sin clasificar en la raíz que son las que hay que mirar a mano. La categoría 99 es la interesante: es donde se esconde lo que no sigue ninguna convención.

Y el desglose de esa categoría, que es el que da la huella del stack:

unzip -l $CORPUS/org.videolan.vlc_13070108.apk | awk '{print $4}' \
  | grep -vE "^(AndroidManifest.xml|classes[0-9]*\.dex|resources\.arsc|res/|assets/|lib/|META-INF/|kotlin/|okhttp3/|Name|----)" \
  | grep -v "^$" | head -10
DebugProbesKt.bin
androidsupportmultidexversion.txt
car-app-api.level
custom.config.conf
custom.config.yaml
debug/AndroidManifest.xml
dev/AndroidManifest.xml
kotlin-tooling-metadata.json
org/bouncycastle/pkix/CertPathReviewerMessages.properties
org/bouncycastle/pkix/CertPathReviewerMessages_de.properties

debug/AndroidManifest.xml y dev/AndroidManifest.xml son, además, un hallazgo por sí solos: manifiestos de otras variantes de compilación que acabaron dentro del APK de release.

Fuentes

  1. JAR File Specification — Oracle — https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html Consultado el 12 de agosto de 2026. De aquí salen la gramática de MANIFEST.MF, el límite de 72 bytes por línea y su continuación, los atributos x-Digest-Manifest y x-Digest, y la lista de nombres reservados de META-INF/ de las secciones 2.1 a 2.4.
  2. JEP 238: Multi-Release JAR Files — OpenJDK — https://openjdk.org/jeps/238 Consultado el 12 de agosto de 2026. De aquí sale el requisito del atributo Multi-Release: true y la estructura META-INF/versions/<N>/ de la sección 2.5.
  3. Baseline Profiles overview — Android Developers — https://developer.android.com/topic/performance/baselineprofiles/overview Consultado el 12 de agosto de 2026. De aquí salen la definición de baseline profile, la ruta assets/dexopt/baseline.prof, la descripción de la compilación AOT en instalación de la sección 3.1 y la cita completa sobre Cloud Profiles de la sección 5.5.
  4. AOSP — art/libprofile/profile/profile_compilation_info.cc — https://android.googlesource.com/platform/art/+/refs/heads/main/libprofile/profile/profile_compilation_info.cc Consultado el 12 de agosto de 2026. De aquí salen kProfileMagic, kProfileVersion y kProfileVersionForBootImage, y la descripción de las secciones del fichero de perfil de la sección 3.2.
  5. AOSP — frameworks/support/profileinstaller/.../ProfileTranscoder.java — https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-main/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/ProfileTranscoder.java Consultado el 12 de agosto de 2026. De aquí salen MAGIC_PROF y MAGIC_PROFM de la sección 3.2, que confirman la magia prm\0 observada en el corpus.
  6. App resources overview — Android Developers — https://developer.android.com/guide/topics/resources/providing-resources Consultado el 12 de agosto de 2026. De aquí salen las dos citas sobre assets/ frente a res/raw/ y la ausencia de resource ID de la sección 4.1.
  7. Configure ART — Android Open Source Project — https://source.android.com/docs/core/runtime/configure Consultado el 12 de agosto de 2026. De aquí salen la descripción de dex2oat, el contenido de .vdex, .odex y .art, y la tabla de filtros de compilación de las secciones 5.1 y 5.2.
  8. AOSP — art/runtime/oat/oat_file_assistant.cc — https://android.googlesource.com/platform/art/+/refs/heads/main/runtime/oat/oat_file_assistant.cc Consultado el 12 de agosto de 2026. De aquí sale el comentario que documenta la ruta oat/<isa>/ de la sección 5.3.
  9. AOSP — tools/apksig/.../stamp/SourceStampConstants.java — https://android.googlesource.com/platform/tools/apksig/+/refs/heads/main/src/main/java/com/android/apksig/internal/apk/stamp/SourceStampConstants.java Consultado el 12 de agosto de 2026. De aquí salen el nombre de entrada stamp-cert-sha256 y los identificadores de bloque 0x2b09189e (v1) y 0x6dff800d (v2) de la sección 6.
  10. kotlinx-metadata-jvm — JetBrains/kotlin — https://github.com/JetBrains/kotlin/blob/master/libraries/kotlinx-metadata/jvm/ReadMe.md Consultado el 12 de agosto de 2026. De aquí sale que .kotlin_module es el contenedor de metadatos de módulo de Kotlin de la sección 2.6. No se ha localizado una especificación del formato binario, solo la API de lectura y escritura.
  11. Corpus de verificación — 5,9 GB, 86 contenedores y 717 APK: 58 sueltos de F-Droid y 659 dentro de contenedores de splits. Medido el 12 de agosto de 2026. De aquí salen todos los contenidos reales citados —MANIFEST.MF, .SF, services/, app-metadata.properties, version-control-info.textproto, las magias de baseline.prof y .profm, los 32 bytes de stamp-cert-sha256—, el recuento de 15 APK con META-INF/versions/ sin Multi-Release de la sección 2.5, la tabla de la sección 6 y ambas salidas de la sección 7.