Script shell Wrap

Durante il debug e la profilazione delle app con codice nativo, è spesso utile utilizzare strumenti di debug che devono essere attivati all'avvio del processo. Ciò richiede l'esecuzione dell'app in un nuovo processo anziché la clonazione dallo zigote. Tra gli esempi possibili:

Utilizzare lo script shell di wrapping

È facile usare wrap.sh:

  1. Compila un APK personalizzato di cui è possibile eseguire il debug che contenga quanto segue:
    • Uno script shell denominato wrap.sh. Per ulteriori dettagli, consulta Creare lo script di wrap shell e Package wrap.sh.
    • Eventuali strumenti aggiuntivi necessari per il tuo script shell, ad esempio il tuo programma binario strace.
  2. Installa l'APK di cui è possibile eseguire il debug su un dispositivo.
  3. Avvia l'app.

Creare lo script shell di wrapping

Quando avvii un APK di cui è possibile eseguire il debug che contiene wrap.sh, il sistema esegue lo script e passa il comando per avviare l'app come argomenti. Lo script è responsabile dell'avvio dell'app, ma può apportare qualsiasi modifica all'ambiente o all'argomento. Lo script deve seguire la sintassi della shell MirBSD Korn (mksh).

Lo snippet seguente mostra come scrivere un file wrap.sh semplice che avvii l'app:

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

Debug Malloc

Per utilizzare debug malloc tramite wrap.sh, devi includere la seguente riga:

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

ASan

Esiste un esempio di come eseguire questa operazione per ASan nella documentazione di ASan.

Pacchetto wrap.sh

Per poter usare wrap.sh, è necessario eseguire il debug dell'APK. Assicurati che l'impostazione android:debuggable="true" sia configurata nell'elemento <application> del file manifest Android oppure, se utilizzi Android Studio, hai configurato una build di debug nel file build.gradle.

Devi inoltre impostare useLegacyPackaging su true nel file build.gradle della tua app. Nella maggior parte dei casi, l'opzione è impostata su false per impostazione predefinita, quindi ti consigliamo di impostarla esplicitamente su true per evitare sorprese.

Devi pacchettizzare lo script wrap.sh con le librerie native dell'app. Se l'app non contiene librerie native, aggiungi manualmente la directory lib alla directory del progetto. Per ogni architettura supportata dall'app, devi fornire una copia dello script della shell di wrapping nella directory della libreria nativa.

L'esempio seguente mostra il layout dei file per supportare le architetture ARMv8 e x86-64:

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

Android Studio pacchettizza file .so solo dalle directory lib/; pertanto, se sei un utente di Android Studio, dovrai inserire i file wrap.sh nelle directory src/main/resources/lib/* in modo che vengano pacchettizzati correttamente.

Tieni presente che resources/lib/x86 verrà visualizzato nell'interfaccia utente come lib.x86, ma in realtà dovrebbe essere una sottodirectory:

Esempio di pacchettizzazione di wrap.sh in Android Studio

Esegui il debug quando utilizzi wrap.sh

Se vuoi collegare un debugger quando utilizzi wrap.sh, lo script shell dovrà attivare manualmente il debug. Le istruzioni sono diverse da una release all'altra, pertanto questo esempio mostra come aggiungere le opzioni appropriate per tutte le release che supportano 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