このセクションでは、プラットフォーム レベルの機能の開発時にネイティブ Android プラットフォーム コードのデバッグ、トレース、プロファイリングを行うための便利なツールと関連コマンドの概要を紹介します。
注: このセクションとこのサイト内の他のページでは、Android の特定の要素をデバッグするために adb
を setprop
引数と組み合わせて使用することを推奨しています。Android 7.x 以前では、プロパティ名の長さは 32 文字以内に制限されていました。つまり、アプリ名で wrap プロパティを作成するには、この制限に合わせてアプリ名も短縮する必要がありました。Android 8.0 以降では許容される長さが大幅に拡張されたため、事実上短縮する必要がなくなりました。
このページでは、logcat 出力内にあるクラッシュ ダンプに関する基本事項を説明します。他のページでは、ネイティブ コードでのクラッシュの診断、dumpsys
によるシステム サービスの調査、ネイティブ メモリ、ネットワーク、RAM の使用量の表示、AddressSanitizer によるネイティブ コードのメモリバグの検出、パフォーマンスの問題についての評価(systrace を含む)、デバッガの使用について詳細に説明しています。
クラッシュ ダンプと Tombstone
ダイナミック リンクされた実行可能ファイルが開始されると、いくつかのシグナル ハンドラが登録されます。クラッシュが発生すると、基本的なクラッシュ ダンプが logcat に書き込まれ、より詳細な tombstone ファイルが /data/tombstones/
に出力されます。tombstone は、クラッシュしたプロセスに関する追加のデータを含むファイルです。具体的には、(シグナルをキャッチしたスレッドだけでなく)クラッシュ プロセス内におけるすべてのスレッドのスタック トレース、完全なメモリマップ、すべてのオープン ファイル記述子のリストが含まれます。
Android 8.0 より前では、クラッシュは debuggerd
デーモンと debuggerd64
デーモンによって処理されていました。Android 8.0 以降では、必要に応じて crash_dump32
と crash_dump64
が生成されます。
クラッシュ ダンパーは、他にまだ何もアタッチされていない場合にのみアタッチできます。つまり、strace
や lldb
などのツールを使用すると、クラッシュ ダンプの発生が回避されます。
出力例(タイムスタンプと無関係な情報を削除済み):
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 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
出力の最終行は、ディスク上の完全な tombstone の場所を示します。
ストリップされていないバイナリが利用できる場合、スタックを development/scripts/stack
に貼り付けることにより、行番号情報を含むより詳細なアンワインドを取得できます。
development/scripts/stack
ヒント: 簡便化のため、lunch
を実行していれば stack
はすでに $PATH
にあるため、完全なパスを指定する必要はありません。
出力例(上記の logcat 出力に基づく):
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)
tombstone 全体に stack
を使用できます。例:
stack < FS/data/tombstones/tombstone_05
これは、現在のディレクトリにバグレポートを解凍した直後の場合に有用です。ネイティブ コードでのクラッシュと tombstone の診断の詳細については、ネイティブ コードでのクラッシュの診断をご覧ください。
実行中のプロセスからスタック トレース / tombstone を取得する
debuggerd
ツールを使用して、実行中のプロセスからスタックダンプを取得できます。コマンドラインから、プロセス ID(PID)を使用して debuggerd
を起動し、完全な tombstone を stdout
にダンプします。プロセス内におけるすべてのスレッドのスタックだけを取得するには、-b
または --backtrace
フラグを指定します。
複雑なアンワインドを理解する
アプリがクラッシュすると、スタックはかなり複雑になる傾向があります。次の詳細な例では、さまざまな複雑性に焦点を当てます。
#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)
フレーム #00~#03 は、個別の .so
ファイルに展開する代わりに、ディスク スペースを節約するため APK に解凍して保存したネイティブ JNI コードからのスタックです。Android 9 以降のスタック アンワインダーは、この一般的な Android 固有のケースに対処するための展開済み .so
ファイルを必要としません。
フレーム #00~#02 にはシンボル名がありません(デベロッパーによってストリップされたため)。
フレーム #03 は、シンボルが利用可能な場合、アンワインダーがそれらを使用することを示します。
#04 pc 0000000000117550 /data/dalvik-cache/arm64/system@priv-app@Velvet@Velvet.apk@classes.dex (offset 0x108000) (com.google.speech.recognizer.AbstractRecognizer.nativeRun+160)
フレーム #04 は、事前コンパイル済み Java コードです。古いアンワインダーはここで停止し、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)
フレーム #05~#10 は、ART インタープリタ実装からのスタックです。Android 9 より前のリリースのスタック アンワインダーの場合、インタープリタがどのコードを解釈していたかを説明するフレーム #11 のコンテキストなしでこれらのフレームを示します。これらのフレームは ART そのものをデバッグする場合には活用できますが、アプリをデバッグする場合は無視できます。一部のツール(simpleperf
など)では、これらのフレームは自動的に省略されます。
#11 pc 00000000001992d6 /system/priv-app/Velvet/Velvet.apk (offset 0x26cf000) (com.google.speech.recognizer.AbstractRecognizer.run+18)
フレーム #11 は、解釈されている Java コードです。
#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)
フレーム #12~#16 は、インタープリタ実装そのものです。
#17 pc 00000000002454a0 /system/priv-app/Velvet/Velvet.apk (offset 0x1322000) (com.google.android.apps.gsa.speech.e.c.c.call+28)
フレーム #17 は、解釈されている Java コードです。この Java メソッドは、フレーム #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)
フレーム #18~#20 は VM そのものであり、コンパイル済み Java コードから解釈済み Java コードに変換されるコードです。
#21 pc 00000000002ce44c /system/framework/arm64/boot.oat (offset 0xdc000) (java.util.concurrent.FutureTask.run+204)
フレーム #21 は、#17 の Java メソッドを呼び出すコンパイル済み Java メソッドです。
#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)
フレーム #22~#27 はインタープリタ実装であり、解釈済みコードからコンパイル済みメソッドへのメソッド呼び出しを行います。
#28 pc 00000000003ed69e /system/priv-app/Velvet/Velvet.apk (com.google.android.apps.gsa.shared.util.concurrent.b.e.run+22)
フレーム #28 は、解釈されている Java コードです。
#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)
フレーム #29~#31 は、コンパイル済みコードと解釈済みコードの間のもう一つの変換です。
#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)
フレーム #32~#34 は、相互呼び出しを直接行うコンパイル済み Java フレームです。このケースでは、ネイティブ コールスタックは 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)
フレーム #35~#40 はインタープリタそのものです。
#41 pc 00000000003ed8e0 /system/priv-app/Velvet/Velvet.apk (com.google.android.apps.gsa.shared.util.concurrent.b.i.run+20)
フレーム #41 は、解釈されている Java コードです。
#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)
フレーム #42~#49 は VM そのものです。ここでは、新しいスレッドで Java の実行を開始するコードです。
#50 pc 0000000000082e24 /system/lib64/libc.so (__pthread_start(void*)+36) #51 pc 00000000000233bc /system/lib64/libc.so (__start_thread+68)
フレーム #50~#51 は、すべてのスレッドの開始方法を示します。これは libc
の新しいスレッドの開始コードです。