Cuando depuras apps y generas perfiles de ellas con código nativo, es útil usar herramientas de depuración que se tengan que habilitar al inicio del proceso. Para ello, debes ejecutar tu app en un proceso nuevo en lugar de clonarla desde Zygote. Los siguientes son algunos ejemplos:
- El sistema de registro realiza llamadas con strace.
- Búsqueda de errores de memoria con depuración de malloc o Address Sanitizer (ASan)
- Generación de perfiles con Simpleperf.
Cómo usar la unión de la secuencia de comandos de shell
Usar wrap.sh
es sencillo:
- Compila un APK depurable personalizado que empaquete lo siguiente:
- Una secuencia de comandos de shell denominada
wrap.sh
. Consulta Cómo crear la unión de la secuencia de comandos de shell y Paquete wrap.sh para obtener más detalles. - Cualquier otra herramienta que necesite tu secuencia de comandos de shell (p. ej., tu propio objeto binario
strace
)
- Una secuencia de comandos de shell denominada
- Instala el APK depurable en un dispositivo.
- Inicia la app.
Cómo crear la unión de la secuencia de comandos de shell
Cuando inicias un APK depurable que contiene wrap.sh
, el sistema ejecuta la secuencia de comandos y pasa el comando para iniciar la app como argumentos. La secuencia de comandos es responsable de iniciar la app, pero puede realizar cambios en cualquier entorno o argumento. La secuencia de comandos debe seguir la sintaxis MirBSD Korn shell (mksh).
El siguiente fragmento muestra la manera de escribir un archivo wrap.sh
simple que solo inicia la app:
#!/system/bin/sh exec "$@"
Depuración de malloc
Para usar la depuración de malloc a través de wrap.sh
, debes incluir la siguiente línea:
#!/system/bin/sh LIBC_DEBUG_MALLOC_OPTIONS=backtrace logwrapper "$@"
ASan
Se incluye un ejemplo de cómo hacerlo para ASan en la documentación correspondiente.
Paquete wrap.sh
Para aprovechar wrap.sh
, tu APK debe poder depurarse. Asegúrate de que el valor de android:debuggable="true"
esté configurado como <application>
en el manifiesto de Android o, si usas Android Studio, que hayas configurado una compilación de depuración en el archivo build.gradle
.
También es necesario establecer useLegacyPackaging
en true
en el archivo build.gradle
de tu app. En la mayoría de los casos, esta opción se establece en false
de forma predeterminada, por lo que te recomendamos establecerla explícitamente en true
para evitar sorpresas.
Debes empaquetar la secuencia de comandos wrap.sh
con las bibliotecas nativas de la app. Si tu app no contiene bibliotecas nativas, agrega el directorio lib manualmente al directorio del proyecto. Para cada arquitectura que admita tu aplicación, debes proporcionar una copia de la unión de la secuencia de comandos de shell en ese directorio de la biblioteca nativa.
El ejemplo que se incluye a continuación muestra el diseño del archivo para que admita las arquitecturas ARMv8 y x86-64:
# App Directory |- AndroidManifest.xml |- … |- lib |- arm64-v8a |- ... |- wrap.sh |- x86_64 |- ... |- wrap.sh
Android Studio solo empaqueta archivos .so
de los directorios lib/
; por lo tanto, si usas Android Studio, deberás colocar tus archivos wrap.sh
en los directorios src/main/resources/lib/*
para que se empaqueten correctamente.
Ten en cuenta que resources/lib/x86
aparecerá como lib.x86
en la IU, pero en realidad debería ser un subdirectorio:
Cómo depurar cuando se usa wrap.sh
Si quieres incorporar un depurador cuando usas wrap.sh
, tu secuencia de comandos de shell deberá habilitar la depuración de forma manual. La forma de hacerlo varió entre una versión y otra, por lo que este ejemplo muestra cómo agregar las opciones adecuadas para todas las actualizaciones compatibles con wrap.sh
:
#!/system/bin/sh
cmd=$1
shift
os_version=$(getprop ro.build.version.sdk)
if [ "$os_version" -eq "27" ]; then
cmd="$cmd -Xrunjdwp:transport=dt_android_adb,suspend=n,server=y -Xcompiler-option --debuggable $@"
elif [ "$os_version" -eq "28" ]; then
cmd="$cmd -XjdwpProvider:adbconnection -XjdwpOptions:suspend=n,server=y -Xcompiler-option --debuggable $@"
else
cmd="$cmd -XjdwpProvider:adbconnection -XjdwpOptions:suspend=n,server=y $@"
fi
exec $cmd