Durante il debug e la profilazione delle app con codice nativo, spesso è utile usare strumenti di debug che devono essere abilitati all'avvio del processo. Ciò richiede esegui l'app seguendo un nuovo processo anziché clonarla dalla zigote. Ecco alcuni esempi:
- Tracciamento delle chiamate di sistema con strace.
- Ricerca di bug di memoria con debug malloc o Sanitizzatore di indirizzi (ASan).
- Profilazione con Simpleperf.
Utilizzare lo script shell di wrapping
Usare wrap.sh
è facile:
- Compila un APK personalizzato di cui è possibile eseguire il debug che pacchettizzi quanto segue:
- Uno script shell denominato
wrap.sh
. Consulta Crea lo script shell di wrapping e Package wrap.sh per ulteriori dettagli. - Eventuali strumenti aggiuntivi di cui il tuo script shell ha bisogno (ad esempio il tuo file binario
strace
).
- Uno script shell denominato
- Installa l'APK di cui è possibile eseguire il debug su un dispositivo.
- Avvia l'app.
Crea 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ò rendere qualsiasi ambiente o argomento
modifiche. Lo script deve seguire
Sintassi della shell MirBSD Korn (mksh).
Il seguente snippet mostra come scrivere un file wrap.sh
semplice che
avvia l'app:
#!/system/bin/sh exec "$@"
Debug Malloc
Per utilizzare
debug malloc
tramite wrap.sh
, dovresti includere la seguente riga:
#!/system/bin/sh LIBC_DEBUG_MALLOC_OPTIONS=backtrace logwrapper "$@"
ASan
È disponibile un esempio di come eseguire questa operazione per ASan nel Documentazione ASan.
Pacchetto wrap.sh
Per poter usare wrap.sh
, deve essere possibile eseguire il debug del tuo APK. Assicurati che
android:debuggable="true"
è configurata in
<application>
nel tuo file manifest Android oppure, se utilizzi Android Studio,
che hai configurato una build di debug
build.gradle
.
È inoltre necessario impostare useLegacyPackaging
a true
nel file build.gradle
dell'app. Nella maggior parte dei casi, questa opzione è impostata
a false
per impostazione predefinita, quindi ti consigliamo di impostarlo esplicitamente su true
per
per evitare sorprese.
Devi pacchettizzare lo script wrap.sh
con le librerie native dell'app. Se
la tua app non contiene librerie native, aggiungi manualmente la directory lib a
della directory del progetto. Per ogni architettura supportata dall'app, devi:
fornire una copia dello script wrap shell nella directory della libreria nativa.
L'esempio seguente mostra il layout di file per supportare sia ARMv8 che x86-64 delle architetture:
# App Directory |- AndroidManifest.xml |- … |- lib |- arm64-v8a |- ... |- wrap.sh |- x86_64 |- ... |- wrap.sh
Android Studio pacchettizza solo i file .so
dalle directory lib/
, quindi se
sei un utente di Android Studio, devi inserire i tuoi file wrap.sh
nel
src/main/resources/lib/*
directory, in modo che vengano pacchettizzate
in modo corretto.
Tieni presente che resources/lib/x86
verrà visualizzato nell'UI come
lib.x86
, ma in realtà dovrebbe essere una sottodirectory:
Esegui il debug quando si utilizza wrap.sh
Se vuoi collegare un debugger quando utilizzi wrap.sh
, lo script shell
attivare manualmente il debug. Le modalità di esecuzione sono state diverse da un'uscita all'altra,
quindi questo esempio mostra come aggiungere le opzioni appropriate per tutte le release che
Supporto di 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