Encapsuler le script shell

Lors du débogage et du profilage d'applications avec du code natif, il est souvent utile d'utiliser des outils de débogage qui doivent être activés au démarrage du processus. Cela nécessite d'exécuter votre application dans un processus récent plutôt que de le cloner à partir du processus zygote. Exemples :

Utiliser le script shell d'encapsulation

L'utilisation de wrap.sh est simple :

  1. Compilez un fichier APK débogable personnalisé qui regroupe les éléments suivants :
  2. Installez le fichier APK débogable sur un appareil.
  3. Lancez l'application.

Créer le script shell d'encapsulation

Lorsque vous lancez un fichier APK débogable contenant wrap.sh, le système exécute le script et transmet la commande pour démarrer l'application en tant qu'arguments. Le script est chargé de démarrer l'application, mais peut apporter des modifications à l'environnement ou aux arguments. Le script doit suivre la syntaxe du shell MirBSD Korn (mksh).

L'extrait de code suivant montre comment écrire un fichier wrap.sh simple qui démarre simplement l'application :

#!/system/bin/sh
exec "$@"

Débogage malloc

Pour utiliser le débogage malloc via wrap.sh, vous devez inclure la ligne suivante :

#!/system/bin/sh
LIBC_DEBUG_MALLOC_OPTIONS=backtrace logwrapper "$@"

ASan

La documentation ASan fournit un exemple de procédure pour ASan.

Package wrap.sh

Pour bénéficier de wrap.sh, le fichier APK doit être débogable. Assurez-vous que le paramètre android:debuggable="true" est configuré dans l'élément <application> du fichier manifeste Android, ou si vous utilisez Android Studio, que vous avez configuré une version de débogage dans le fichier build.gradle.

Vous devez également définir useLegacyPackaging sur true dans le fichier build.gradle de votre application. Dans la plupart des cas, cette option est définie sur false par défaut. Vous pouvez donc définir cette option explicitement sur true pour éviter toute surprise.

Vous devez empaqueter le script wrap.sh avec les bibliothèques natives de l'application. Si votre application ne contient pas de bibliothèques natives, ajoutez le répertoire lib manuellement au répertoire de votre projet. Pour chaque architecture compatible avec votre application, vous devez fournir une copie du script shell d'encapsulation dans ce répertoire natif de la bibliothèque.

L'exemple suivant présente la mise en page du fichier compatible avec les architectures ARMv8 et x86-64 :

# App Directory
|- AndroidManifest.xml
|- …
|- lib
   |- arm64-v8a
      |- ...
      |- wrap.sh
   |- x86_64
      |- ...
      |- wrap.sh

Android Studio empaquette uniquement les fichiers .so des répertoires lib/. Dès lors, si vous utilisez Android Studio, vous devez placer les fichiers wrap.sh dans les répertoires src/main/resources/lib/* pour qu'ils soient correctement empaquetés.

Notez que resources/lib/x86 s'affiche dans l'interface utilisateur sous la forme lib.x86, mais il s'agit en réalité d'un sous-répertoire :

Exemple de package wrap.sh dans Android Studio

Effectuer un débogage avec wrap.sh

Si vous souhaitez associer un débogueur lorsque vous utilisez wrap.sh, votre script shell doit activer manuellement le débogage. Étant donné que les étapes varient en fonction des versions, cet exemple montre comment ajouter les options appropriées pour toutes les versions compatibles avec 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