En Android 8.0 y versiones posteriores, la interfaz de herramientas de ART (ART TI) expone ciertos elementos internos del tiempo de ejecución y permite que los generadores de perfiles y los depuradores influyan en el comportamiento del tiempo de ejecución de las apps. Se puede usar para implementar herramientas de rendimiento de última generación que se proporcionan para implementar agentes nativos en otras plataformas.
Las funciones internas del entorno de ejecución se exponen a los agentes que se cargaron en el proceso del entorno de ejecución.
Se comunican con ART a través de llamadas directas y devoluciones de llamada. El entorno de ejecución admite varios agentes para que se puedan separar diferentes problemas de perfilación ortogonal. Los agentes se pueden proporcionar al inicio del entorno de ejecución (cuando se invocan dalvikvm
o app_process
) o adjuntarse a un proceso que ya se está ejecutando.
Debido a que la capacidad de instrumentar y modificar el comportamiento de la app y del entorno de ejecución es muy potente, se integraron dos medidas de seguridad en la TI de ART:
- En primer lugar, el código que expone la interfaz del agente, JVMTI, se implementa como un complemento del entorno de ejecución, no como un componente principal del entorno de ejecución. Es posible que se restrinja la carga de complementos para que se bloquee a los agentes de encontrar cualquiera de los puntos de interfaz.
- En segundo lugar, tanto la clase
ActivityManager
como el proceso de tiempo de ejecución solo permiten que los agentes se unan a apps depurables. Los desarrolladores de las apps depurables las aprobaron para que se analicen y se instrumenten, y no se distribuyen a los usuarios finales. Google Play Store no permite la distribución de apps depurables. Esto garantiza que las apps normales (incluidos los componentes principales) no se puedan instrumentar ni manipular.
Diseño
En la Figura 1, se muestra el flujo general y la interconexión en una app instrumentada.

El complemento libopenjdkjvmti
de ART expone el TI de ART, que está
diseñado para adaptarse a las necesidades y restricciones de la plataforma:
- La redefinición de clases se basa en archivos
Dex
, que contienen solo una definición de clase, en lugar de archivos de clase. - Las APIs del lenguaje Java para la instrumentación y la redefinición no se exponen.
La TI de ART también admite los generadores de perfiles de Android Studio.
Carga o adjunta un agente
Para adjuntar un agente al inicio del entorno de ejecución, usa este comando para cargar el complemento JVMTI y el agente determinado:
dalvikvm -Xplugin:libopenjdkjvmti.so -agentpath:/path/to/agent/libagent.so …
No hay medidas de seguridad cuando se carga un agente en el inicio del entorno de ejecución, por lo que debes tener en cuenta que un entorno de ejecución iniciado de forma manual permite la modificación completa sin medidas de seguridad. (Esto permite realizar pruebas de ART).
Nota: Esto no se aplica a las apps normales (incluido el servidor del sistema) en un dispositivo. Las apps se bifurcan desde un zygote que ya está en ejecución, y un proceso de zygote no puede cargar agentes.
Para adjuntar un agente a una app que ya se está ejecutando, usa este comando:
adb shell cmd activity attach-agent [process] /path/to/agent/libagent.so[=agent-options]
Si aún no se cargó el complemento JVMTI, adjuntar un agente carga el complemento y la biblioteca del agente.
Un agente solo se puede conectar a una app en ejecución que esté marcada como depurable (parte del manifiesto de la app, con el atributo android:debuggable
establecido en true
en el nodo de la app). Tanto la clase ActivityManager
como el ART realizan verificaciones antes de permitir que se adjunte un agente. La clase ActivityManager verifica la información actual de la app (derivada de los datos de la clase PackageManager) para el estado depurable, y el entorno de ejecución verifica su estado actual, que se estableció cuando se inició la app.
Ubicaciones de los agentes
El entorno de ejecución debe cargar agentes en el proceso actual para que el agente
pueda vincularse directamente con él y comunicarse con él. El ART en sí es independiente
de la ubicación específica de la que proviene el agente. La cadena se usa para una llamada a dlopen
. Los permisos del sistema de archivos y las políticas de SELinux limitan la carga real.
Para entregar agentes que se puedan ejecutar en una app depurable, haz lo siguiente:
- Incorpora el agente en el directorio de la biblioteca del APK de la app.
- Usa
run-as
para copiar el agente en el directorio de datos de la app.
APIs
Se agregó el siguiente método a android.os.Debug
.
/** * Attach a library as a jvmti agent to the current runtime, with the given classloader * determining the library search path. * Note: agents may only be attached to debuggable apps. Otherwise, this function will * throw a SecurityException. * * @param library the library containing the agent. * @param options the options passed to the agent. * @param classLoader the classloader determining the library search path. * * @throws IOException if the agent could not be attached. * @throws a SecurityException if the app is not debuggable. */ public static void attachJvmtiAgent(@NonNull String library, @Nullable String options, @Nullable ClassLoader classLoader) throws IOException {
Otras APIs de Android
El comando attach-agent es visible para el público. Este comando adjunta un agente JVMTI a un proceso en ejecución:
adb shell 'am attach-agent com.example.android.displayingbitmaps \'/data/data/com.example.android.displayingbitmaps/code_cache/libfieldnulls.so=Ljava/lang/Class;.name:Ljava/lang/String;\''
Los comandos am start -P
y am
start-profiler/stop-profiler
son similares al comando attach-agent.
JVMTI
Esta función expone la API de JVMTI a los agentes (código nativo). Entre las funciones importantes, se incluyen las siguientes:
- Redefinir una clase
- Seguimiento de la asignación de objetos y la recolección de elementos no utilizados
- Iterar sobre todos los objetos de un montón, siguiendo el árbol de referencias de los objetos
- Inspecciona las pilas de llamadas de Java.
- Suspender (y reanudar) todos los subprocesos
Es posible que haya diferentes capacidades disponibles en las diferentes versiones de Android.
Compatibilidad
Esta función necesita compatibilidad con el entorno de ejecución principal, que solo está disponible en Android 8.0 y versiones posteriores. Los fabricantes de dispositivos no necesitan realizar ningún cambio para implementar esta función. Forma parte del AOSP.
Validación
CTS prueba lo siguiente en Android 8 y versiones posteriores:
- Pruebas que los agentes adjuntan a apps depurables y no se adjuntan a apps no depurables.
- Prueba todas las APIs de JVMTI implementadas
- Prueba que la interfaz binaria para agentes es estable
Se agregaron pruebas adicionales a Android 9 y versiones posteriores, y se incluyen en las pruebas de CTS de esas versiones.