Eseguire il debug del codice della piattaforma Android nativa

Questa sezione riassume gli strumenti utili e i relativi comandi per il debug, tracciamento e profilazione del codice della piattaforma Android nativa durante lo sviluppo funzionalità a livello di piattaforma.

Nota: le pagine di questa sezione e di altre sezioni all'interno di questo sito consiglia l'uso di adb insieme ai Argomento setprop per eseguire il debug di alcuni aspetti di Android. In Android 7.x e versioni precedenti, i nomi delle proprietà avevano un limite di lunghezza di 32 caratteri. Questo significava che per creare una proprietà di wrapping con il nome dell'app, era necessario troncare il nome per adattarlo. In Android 8.0 e versioni successive, è molto più elevato e non dovrebbe essere troncato.

Questa pagina illustra le nozioni di base relative ai dump degli arresti anomali rilevati nell'output di logcat. Altre pagine contengono molti più dettagli diagnosticare gli arresti anomali nativi esplorare i servizi di sistema . dumpsys, visualizzazione memoria nativa, rete, e RAM dei dati, usando AddressSanitizer per rilevare la memoria di bug nel codice nativo, problemi di prestazioni (include systrace) e l'utilizzo Debugger.

Distretti di incidenti e lapidi

Quando si avvia un eseguibile collegato dinamicamente, vengono utilizzati diversi gestori di segnali registrato che, in caso di arresto anomalo, causano la scrittura di un dump di arresto anomalo di base in logcat e un file tombstone più dettagliato da scrivere su /data/tombstones/. La tombstone è un file con dati aggiuntivi sul processo che si è arrestato in modo anomalo. In particolare, contiene delle analisi dello stack per tutti i thread nel processo di arresto anomalo (non solo per il thread che ha catturato ), una mappa di memoria completa e un elenco di tutti i descrittori dei file aperti.

Prima di Android 8.0, gli arresti anomali venivano gestiti dal debuggerd e debuggerd64 daemon. In Android 8.0 e versioni successive, crash_dump32 e crash_dump64 vengono riprodotti quando necessario.

Il dumper degli arresti anomali può collegarsi solo se non c'è altro sono già collegati, il che significa che l'utilizzo di strumenti come strace lldb impediscono il dump degli arresti anomali.

Output di esempio (con timestamp e informazioni non pertinenti rimossi):

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'Android/aosp_angler/angler:7.1.1/NYC/enh12211018:eng/test-keys'
Revision: '0'
ABI: 'arm'
pid: 17946, tid: 17949, name: crasher  >>> crasher <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xc
    r0 0000000c  r1 00000000  r2 00000000  r3 00000000
    r4 00000000  r5 0000000c  r6 eccdd920  r7 00000078
    r8 0000461a  r9 ffc78c19  sl ab209441  fp fffff924
    ip ed01b834  sp eccdd800  lr ecfa9a1f  pc ecfd693e  cpsr 600e0030

backtrace:
    #00 pc 0004793e  /system/lib/libc.so (pthread_mutex_lock+1)
    #01 pc 0001aa1b  /system/lib/libc.so (readdir+10)
    #02 pc 00001b91  /system/xbin/crasher (readdir_null+20)
    #03 pc 0000184b  /system/xbin/crasher (do_action+978)
    #04 pc 00001459  /system/xbin/crasher (thread_callback+24)
    #05 pc 00047317  /system/lib/libc.so (_ZL15__pthread_startPv+22)
    #06 pc 0001a7e5  /system/lib/libc.so (__start_thread+34)
Tombstone written to: /data/tombstones/tombstone_06

L'ultima riga di output fornisce la posizione della tombstone completa su disco.

Se hai i file binari senza striping disponibili, puoi ottenere una descrizione rilassati con le informazioni sul numero di riga incollando la pila in development/scripts/stack:

development/scripts/stack

Suggerimento: per praticità, se hai eseguito lunch, allora stack è già presente su $PATH, pertanto non è necessario fornire il percorso completo.

Output di esempio (basato sull'output logcat precedente):

Reading native crash info from stdin
03-02 23:53:49.477 17951 17951 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
03-02 23:53:49.477 17951 17951 F DEBUG   : Build fingerprint: 'Android/aosp_angler/angler:7.1.1/NYC/enh12211018:eng/test-keys'
03-02 23:53:49.477 17951 17951 F DEBUG   : Revision: '0'
03-02 23:53:49.477 17951 17951 F DEBUG   : ABI: 'arm'
03-02 23:53:49.478 17951 17951 F DEBUG   : pid: 17946, tid: 17949, name: crasher  >>> crasher <<<
03-02 23:53:49.478 17951 17951 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xc
03-02 23:53:49.478 17951 17951 F DEBUG   :     r0 0000000c  r1 00000000  r2 00000000  r3 00000000
03-02 23:53:49.478 17951 17951 F DEBUG   :     r4 00000000  r5 0000000c  r6 eccdd920  r7 00000078
03-02 23:53:49.478 17951 17951 F DEBUG   :     r8 0000461a  r9 ffc78c19  sl ab209441  fp fffff924
03-02 23:53:49.478 17951 17951 F DEBUG   :     ip ed01b834  sp eccdd800  lr ecfa9a1f  pc ecfd693e  cpsr 600e0030
03-02 23:53:49.491 17951 17951 F DEBUG   :
03-02 23:53:49.491 17951 17951 F DEBUG   : backtrace:
03-02 23:53:49.492 17951 17951 F DEBUG   :     #00 pc 0004793e  /system/lib/libc.so (pthread_mutex_lock+1)
03-02 23:53:49.492 17951 17951 F DEBUG   :     #01 pc 0001aa1b  /system/lib/libc.so (readdir+10)
03-02 23:53:49.492 17951 17951 F DEBUG   :     #02 pc 00001b91  /system/xbin/crasher (readdir_null+20)
03-02 23:53:49.492 17951 17951 F DEBUG   :     #03 pc 0000184b  /system/xbin/crasher (do_action+978)
03-02 23:53:49.492 17951 17951 F DEBUG   :     #04 pc 00001459  /system/xbin/crasher (thread_callback+24)
03-02 23:53:49.492 17951 17951 F DEBUG   :     #05 pc 00047317  /system/lib/libc.so (_ZL15__pthread_startPv+22)
03-02 23:53:49.492 17951 17951 F DEBUG   :     #06 pc 0001a7e5  /system/lib/libc.so (__start_thread+34)
03-02 23:53:49.492 17951 17951 F DEBUG   :     Tombstone written to: /data/tombstones/tombstone_06
Reading symbols from /huge-ssd/aosp-arm64/out/target/product/angler/symbols
Revision: '0'
pid: 17946, tid: 17949, name: crasher  >>> crasher <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xc
     r0 0000000c  r1 00000000  r2 00000000  r3 00000000
     r4 00000000  r5 0000000c  r6 eccdd920  r7 00000078
     r8 0000461a  r9 ffc78c19  sl ab209441  fp fffff924
     ip ed01b834  sp eccdd800  lr ecfa9a1f  pc ecfd693e  cpsr 600e0030
Using arm toolchain from: /huge-ssd/aosp-arm64/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin/

Stack Trace:
  RELADDR   FUNCTION                   FILE:LINE
  0004793e  pthread_mutex_lock+2       bionic/libc/bionic/pthread_mutex.cpp:515
  v------>  ScopedPthreadMutexLocker   bionic/libc/private/ScopedPthreadMutexLocker.h:27
  0001aa1b  readdir+10                 bionic/libc/bionic/dirent.cpp:120
  00001b91  readdir_null+20            system/core/debuggerd/crasher.cpp:131
  0000184b  do_action+978              system/core/debuggerd/crasher.cpp:228
  00001459  thread_callback+24         system/core/debuggerd/crasher.cpp:90
  00047317  __pthread_start(void*)+22  bionic/libc/bionic/pthread_create.cpp:202 (discriminator 1)
  0001a7e5  __start_thread+34          bionic/libc/bionic/clone.cpp:46 (discriminator 1)

Puoi usare stack su un'intera lapide. Esempio:

stack < FS/data/tombstones/tombstone_05

Questa operazione è utile se hai appena decompresso una segnalazione di bug nella directory corrente. Per ulteriori informazioni su come diagnosticare arresti anomali e tombstone nativi, consulta Diagnostica degli arresti anomali nativi.

Recupero di un'analisi dello stack o di un tombstone da un processo in esecuzione

Puoi utilizzare lo strumento debuggerd per ottenere uno stack dump da un processo in esecuzione. Dalla riga di comando, richiama debuggerd utilizzando un ID di processo (PID) per eseguire il dump di un tomba completa a stdout. Per ottenere solo lo stack per ogni thread in durante la procedura, includi il flag -b o --backtrace.

Comprendi una rilassata complessa

Quando un'app ha un arresto anomalo, lo stack tende a essere piuttosto complesso. Il seguente esempio dettagliato evidenzia molte delle complessità del caso:

    #00 pc 00000000007e6918  /system/priv-app/Velvet/Velvet.apk (offset 0x346b000)
    #01 pc 00000000001845cc  /system/priv-app/Velvet/Velvet.apk (offset 0x346b000)
    #02 pc 00000000001847e4  /system/priv-app/Velvet/Velvet.apk (offset 0x346b000)
    #03 pc 00000000001805c0  /system/priv-app/Velvet/Velvet.apk (offset 0x346b000) (Java_com_google_speech_recognizer_AbstractRecognizer_nativeRun+176)

I frame #00–#03 provengono dal codice JNI nativo che è stato memorizzato non compresso nell'APK per salvare il disco anziché essere estratti in un file .so separato. Lo strumento di svolgimento dello stack Android 9 e versioni successive non hanno bisogno del file .so estratto per far fronte a questo problema comune. cover specifica per Android.

I frame #00-#02 non hanno nomi di simboli perché sono stati eliminati dallo sviluppatore.

Il frame 03 mostra che, quando sono disponibili i simboli, vengono utilizzati dallo strumento di svvolgimento.

    #04 pc 0000000000117550  /data/dalvik-cache/arm64/system@priv-app@Velvet@Velvet.apk@classes.dex (offset 0x108000) (com.google.speech.recognizer.AbstractRecognizer.nativeRun+160)

Il frame 04 è codice Java compilato in anticipo. Il vecchio rilassamento si sarebbe fermato qui, non è possibile per rilassarti in Java.

    #05 pc 0000000000559f88  /system/lib64/libart.so (art_quick_invoke_stub+584)
    #06 pc 00000000000ced40  /system/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+200)
    #07 pc 0000000000280cf0  /system/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+344)
    #08 pc 000000000027acac  /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+948)
    #09 pc 000000000052abc0  /system/lib64/libart.so (MterpInvokeDirect+296)
    #10 pc 000000000054c614  /system/lib64/libart.so (ExecuteMterpImpl+14484)

I frame #05-#10 provengono dall'implementazione dell'interprete ART. Lo strumento di svolgimento dello stack nelle release precedenti ad Android 9 avrebbe mostrato questi frame senza il contesto del frame 11 che spiega il codice interpretato dall'interprete. Questi frame sono utili se stai eseguendo il debug di ART. Se stai eseguendo il debug di un'app, puoi ignorarle. Alcuni strumenti, come simpleperf, ometti automaticamente questi frame.

    #11 pc 00000000001992d6  /system/priv-app/Velvet/Velvet.apk (offset 0x26cf000) (com.google.speech.recognizer.AbstractRecognizer.run+18)

Il frame 11 è il codice Java che viene interpretato.

    #12 pc 00000000002547a8  /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.780698333+496)
    #13 pc 000000000025a328  /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
    #14 pc 000000000027ac90  /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+920)
    #15 pc 0000000000529880  /system/lib64/libart.so (MterpInvokeVirtual+584)
    #16 pc 000000000054c514  /system/lib64/libart.so (ExecuteMterpImpl+14228)

I frame da 12 a 16 rappresentano l'implementazione stessa dell'interprete.

    #17 pc 00000000002454a0  /system/priv-app/Velvet/Velvet.apk (offset 0x1322000) (com.google.android.apps.gsa.speech.e.c.c.call+28)

Il frame 17 è il codice Java che viene interpretato. Questo metodo Java corrisponde ai frame dell'interprete #12–#16.

    #18 pc 00000000002547a8  /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.780698333+496)
    #19 pc 0000000000519fd8  /system/lib64/libart.so (artQuickToInterpreterBridge+1032)
    #20 pc 00000000005630fc  /system/lib64/libart.so (art_quick_to_interpreter_bridge+92)

I frame #18–#20 sono la VM stessa, il codice per la transizione da codice Java compilato a codice Java interpretato.

    #21 pc 00000000002ce44c  /system/framework/arm64/boot.oat (offset 0xdc000) (java.util.concurrent.FutureTask.run+204)

Il frame #21 è il metodo Java compilato che chiama il metodo Java nel passaggio 17.

    #22 pc 0000000000559f88  /system/lib64/libart.so (art_quick_invoke_stub+584)
    #23 pc 00000000000ced40  /system/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+200)
    #24 pc 0000000000280cf0  /system/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+344)
    #25 pc 000000000027acac  /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+948)
    #26 pc 0000000000529880  /system/lib64/libart.so (MterpInvokeVirtual+584)
    #27 pc 000000000054c514  /system/lib64/libart.so (ExecuteMterpImpl+14228)

I frame da #22 a #27 sono l'implementazione dell'interprete, ovvero fanno una chiamata al metodo da in un metodo compilato.

    #28 pc 00000000003ed69e  /system/priv-app/Velvet/Velvet.apk (com.google.android.apps.gsa.shared.util.concurrent.b.e.run+22)

Il frame 28 è il codice Java che viene interpretato.

    #29 pc 00000000002547a8  /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.780698333+496)
    #30 pc 0000000000519fd8  /system/lib64/libart.so (artQuickToInterpreterBridge+1032)
    #31 pc 00000000005630fc  /system/lib64/libart.so (art_quick_to_interpreter_bridge+92)

I frame da #29 a #31 sono un'altra transizione tra il codice compilato e il codice interpretato.

    #32 pc 0000000000329284  /system/framework/arm64/boot.oat (offset 0xdc000) (java.util.concurrent.ThreadPoolExecutor.runWorker+996)
    #33 pc 00000000003262a0  /system/framework/arm64/boot.oat (offset 0xdc000) (java.util.concurrent.ThreadPoolExecutor$Worker.run+64)
    #34 pc 00000000002037e8  /system/framework/arm64/boot.oat (offset 0xdc000) (java.lang.Thread.run+72)

I frame #32–#34 sono frame Java compilati che chiamano direttamente l'altro. In questo caso la chiamata nativa equivale allo stack di chiamate Java.

    #35 pc 0000000000559f88  /system/lib64/libart.so (art_quick_invoke_stub+584)
    #36 pc 00000000000ced40  /system/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+200)
    #37 pc 0000000000280cf0  /system/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+344)
    #38 pc 000000000027acac  /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+948)
    #39 pc 0000000000529f10  /system/lib64/libart.so (MterpInvokeSuper+1408)
    #40 pc 000000000054c594  /system/lib64/libart.so (ExecuteMterpImpl+14356)

I frame da 35 a 40 sono l'interprete stesso.

    #41 pc 00000000003ed8e0  /system/priv-app/Velvet/Velvet.apk (com.google.android.apps.gsa.shared.util.concurrent.b.i.run+20)

Il frame #41 è il codice Java che viene interpretato.

    #42 pc 00000000002547a8  /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.780698333+496)
    #43 pc 0000000000519fd8  /system/lib64/libart.so (artQuickToInterpreterBridge+1032)
    #44 pc 00000000005630fc  /system/lib64/libart.so (art_quick_to_interpreter_bridge+92)
    #45 pc 0000000000559f88  /system/lib64/libart.so (art_quick_invoke_stub+584)
    #46 pc 00000000000ced40  /system/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+200)
    #47 pc 0000000000460d18  /system/lib64/libart.so (art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char const*)+104)
    #48 pc 0000000000461de0  /system/lib64/libart.so (art::InvokeVirtualOrInterfaceWithJValues(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, jvalue*)+424)
    #49 pc 000000000048ccb0  /system/lib64/libart.so (art::Thread::CreateCallback(void*)+1120)

I frame da #42 a #49 sono la VM stessa. Questa volta è il codice che avvia Java su un nuovo thread.

    #50 pc 0000000000082e24  /system/lib64/libc.so (__pthread_start(void*)+36)
    #51 pc 00000000000233bc  /system/lib64/libc.so (__start_thread+68)

I frame da #50 a #51 indicano l'inizio di tutti i thread. Questo è il libc nuovo codice di inizio del thread.