LearnHouse

[轉]Android NDK Tombstone/Crash 分析

覺得很重要,所以備份一下
資料來源:https://woshijpf.github.io/android/2016/06/14/Android-NDK-Tombstone-Crash-%E5%88%86%E6%9E%90.html

前言

作為程序員,調試 Bug 永遠是最痛苦的一件事情,而在所有的 Bug當中訪問非法內存又是最最讓人崩潰和最難發現的一個問題。

通常我們調試程序 Bug 的方法主要有下面 3 種:

  1. 打印日誌信息 這種方法通過在代碼中可能出現 Bug 的位置添加一些日誌輸出語句來跟蹤整個程序的執行過程或者查看關鍵變量的值等等。
  2. 單步調試 這個方法則主要使用到了調試工具,例如 gdb 和 Visual Studio 中內置的調試器。這些高級的工具使得我們可以在程序中任何位置設置斷點,或者查看相關變量的值,或者更進一步直接查看 CPU 中寄存器的值。
  3. 分析崩潰後的錯誤信息 這種方法則主要是分析程序崩潰之後產生的錯誤信息相關文件來確定產生 Bug 的原因和位置。

Android 開發中常見 Crash 的情況

在 Android 開發中,程序 Crash 分三種情況:

  • 未捕獲的異常
  • ANR(Application Not Responding)
  • 閃退(NDK 程序引發錯誤)

其中未捕獲的異常根據 logcat 打印的堆棧信息很容易定位錯誤。

ANR錯誤也好查,Android規定,應用與用戶進行交互時,如果5秒內沒有響應用戶的操作,則會引發ANR錯誤,並彈出一個系統提示框,讓用戶選擇繼續等待或立即關閉程序。並會在/data/anr目錄下生成一個traces.txt文件,記錄系統產生anr異常的堆棧和線程信息。

如果是閃退,這問題比較難查,通常是項目中用到了 NDK 引發某類致命的錯誤導致閃退。因為 NDK 是使用 C/C++ 來進行開發,熟悉 C/C++ 的程序員都知道,指針和內存管理是最重要也是最容易出問題的地方,稍有不慎就會遇到諸如內存地址訪問錯誤、使用野指針、內存洩露、堆棧溢出、初始化錯誤、類型轉換錯誤、數字除0等常見的問題,導致最後都是同一個結果:程序崩潰。它不會像在 Java 層產生的異常時彈出“xxx程序無響應,是否立即關閉”之類的提示框。當發生 NDK 錯誤後,logcat 打印出來的那堆日誌根據看不懂,更別想從日誌當中定位錯誤的根源。

那麼我們該怎麼調試引發 Crash 的 NDK 程序呢?

哈哈,好在 Google 早就料到了我們寫的 NDK 代碼肯定會漏洞百出。首先,當 NDK 程序在發生 Crash 時,它會在路徑 /data/tombstones/ 下產生導致程序 Crash 的文件 tombstone_xx。並且 Google 還在 NDK 包中為我們提供了一系列的調試工具,例如 addr2lineobjdumpndk-stack

Tombstone

Linux 信號機制

在介紹 Tombstone 之前,我們首先補充一個 Linux 信號機制的知識。

信號機制是 Linux 進程間通信的一種重要方式,Linux 信號一方面用於正常的進程間通信和同步,如任務控制(SIGINT, SIGTSTP,SIGKILL, SIGCONT,……);另一方面,它還負責監控系統異常及中斷。 當應用程序運行異常時, Linux 內核將產生錯誤信號並通知當前進程。 當前進程在接收到該錯誤信號後,可以有三種不同的處理方式。

  • 忽略該信號。
  • 捕捉該信號並執行對應的信號處理函數(signal handler)。
  • 執行該信號的缺省操作(如 SIGSEGV, 其缺省操作是終止進程)。

當 Linux 應用程序在執行時發生嚴重錯誤,一般會導致程序 crash。其中,Linux 專門提供了一類 crash 信號,在程序接收到此類信號時,缺省操作是將 crash 的現場信息記錄到 core 文件,然後終止進程。

Crash 信號列表:

Signal Description
SIGSEGV Invalid memory reference.
SIGBUS Access to an undefined portion of a memory object.
SIGFPE Arithmetic operation error, like divide by zero.
SIGILL Illegal instruction, like execute garbage or a privileged instruction
SIGSYS Bad system call.
SIGXCPU CPU time limit exceeded.
SIGXFSZ File size limit exceeded.

什麼 Tombstone?

Android Native 程序本質上就是一個 Linux 程序,因此當它在執行時發生嚴重錯誤,也會導致程序 crash,然後產生一個記錄 crash 的現場信息的文件,而這個文件在 Android 系統中就是 tombstone 文件。

Tombstone 英文的本意是墓碑,我覺得用這個單詞來表示程序 Crash 之後產生的現場死亡信息真的再恰當不過了,tombstone 文件的確就像墓碑一樣記錄了死亡了的進程的基本信息(例如進程的進程號,線程號),死亡的地址(在哪個地址上發生了 Crash),死亡時的現場是什麼樣的(記錄了一系列的堆棧調用信息)等等。

因此,分析出現 Crash 的原因和代碼位置最重要的就是分析這個 tombstone 文件。

tombstone 文件位於路徑 /data/tombstones/ 下,

root@x86:/data/tombstones # ls
tombstone_00
tombstone_01

它的主要內容如下所示:

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'Android-x86/android_x86/x86:5.1.1/LMY48W/woshijpf04211939:eng/test-keys'
Revision: '0'
ABI: 'x86'
pid: 1019, tid: 1019, name: surfaceflinger  >>> /system/bin/surfaceflinger <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x4
    eax a6265c06  ebx b7467d88  ecx b7631a22  edx a6265c06
    esi 00000000  edi b6867140
    xcs 00000073  xds 0000007b  xes 0000007b  xfs 00000000  xss 0000007b
    eip b745a639  ebp bfcfc1e8  esp bfcfc150  flags 00010282

backtrace:
    #00 pc 00006639  /system/lib/libui.so (android::Fence::waitForever(char const*)+41)
    #01 pc 00034b86  /system/lib/libsurfaceflinger.so
    #02 pc 0003229e  /system/lib/libsurfaceflinger.so
    #03 pc 0002cb9c  /system/lib/libgui.so (android::BufferQueue::ProxyConsumerListener::onFrameAvailable(android::BufferItem const&)+652)
    #04 pc 000342f4  /system/lib/libgui.so (android::BufferQueueProducer::queueBuffer(int, android::IGraphicBufferProducer::QueueBufferInput const&, android::IGraphicBufferProducer::QueueBufferOutput*)+2580)
    #05 pc 0004eafb  /system/lib/libgui.so (android::Surface::queueBuffer(ANativeWindowBuffer*, int)+411)
    #06 pc 0004ce06  /system/lib/libgui.so (android::Surface::hook_queueBuffer(ANativeWindow*, ANativeWindowBuffer*, int)+38)
    #07 pc 00014bc6  /system/lib/egl/libGLES_android.so
    #08 pc 00017f73  /system/lib/egl/libGLES_android.so (eglSwapBuffers+163)
    #09 pc 00015fdb  /system/lib/libEGL.so (eglSwapBuffers+203)
    #10 pc 000013ea  /system/lib/hw/hwcomposer.x86.so
    #11 pc 00034730  /system/lib/libsurfaceflinger.so
    #12 pc 000256d4  /system/lib/libsurfaceflinger.so
    #13 pc 00024bf4  /system/lib/libsurfaceflinger.so
    #14 pc 000236fb  /system/lib/libsurfaceflinger.so
    #15 pc 0002338a  /system/lib/libsurfaceflinger.so
    #16 pc 0001e0ff  /system/lib/libsurfaceflinger.so
    #17 pc 0001d9ce  /system/lib/libutils.so (android::Looper::pollInner(int)+926)
    #18 pc 0001db73  /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+67)
    #19 pc 0001e561  /system/lib/libsurfaceflinger.so
    #20 pc 00022ce7  /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::run()+39)
    #21 pc 00000ca3  /system/bin/surfaceflinger
    #22 pc 0001365a  /system/lib/libc.so (__libc_init+106)
    #23 pc 00000da8  /system/bin/surfaceflinger

stack:
         bfcfc110  00000000  
         bfcfc114  b6839270  
         bfcfc118  00000000  
         bfcfc11c  00000000  
         bfcfc120  b68394e0  
         bfcfc124  00000002  
         bfcfc128  00000002  
         bfcfc12c  b75d8185  /system/lib/libutils.so (android::RefBase::incStrong(void const*) const+53)
         bfcfc130  b6839270  
         bfcfc134  bfcfc1e8  [stack]
         bfcfc138  00000002  
         bfcfc13c  a6265c06  
         bfcfc140  b7467d88  /system/lib/libui.so
         bfcfc144  00000000  
         bfcfc148  b6867140  
         bfcfc14c  b745a639  /system/lib/libui.so (android::Fence::waitForever(char const*)+41)
    #00  bfcfc150  b683af18  
         bfcfc154  bfcfc1e8  [stack]
         bfcfc158  00000000  
         bfcfc15c  00000000  
         bfcfc160  00000000  
         bfcfc164  b683af18  
         bfcfc168  b75ec9c4  /system/lib/libutils.so
         bfcfc16c  b75d8285  /system/lib/libutils.so (android::RefBase::weakref_type::decWeak(void const*)+37)
         bfcfc170  00000000  
         bfcfc174  00000000  
         bfcfc178  00000000  
         bfcfc17c  00000000  
         bfcfc180  b7642968  /system/lib/libsurfaceflinger.so
         bfcfc184  bfcfc1e8  [stack]
         bfcfc188  b6867140  
         bfcfc18c  b7622b87  /system/lib/libsurfaceflinger.so

tombstone 文件解析

第一次看到 tombstone 文件時,我也是一頭霧水,一臉懵逼,加上調 Bug 時本來就煩躁的心情,簡直不想多看它一眼。但是沒辦法,導致 Crash 的原因只有在這裡才能找到,所以我們硬著頭皮也要去分析啊(最好還是在心情比較平靜時去調 Bug 吧,這樣效率可能會更好一點)。

tombstone 文件它主要由下面幾部分組成:

  • Build fingerprint
  • Crashed process and PIDs
  • Terminated signal and fault address
  • CPU registers
  • Call stack
  • Stack content of each call

但是也不是 tombstone 中的信息我們都需要分析,我們最主要的就是分析 Crashed process and PIDsTerminated signal and fault addressCall stack 部分。

Crashed process and PIDs 信息

從上面 tombstone 文件中的第 5 行中我們可以看到 Crash 掉進程的基本信息,如下所示:

pid: 1019, tid: 1019, name: surfaceflinger  >>> /system/bin/surfaceflinger <<<

如果 pid 等於 tid ,那麼就說明這個程序是在主線程中 Crash 掉的,name 的屬性則表示 Crash 進程的名稱以及在文件系統中位置。

Terminated signal and fault address 信息

在上面 tombstone 文件中的第 6 行中我們可以看到程序是因為什麼信號導致了 Crash 以及出現錯誤的地址,如下所示:

signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x4

這裡的信息說明出現進程 Crash 的原因是因為程序產生了段錯誤的信號,訪問了非法的內存空間,而訪問的非法地址是 0x4。

Call Stack 信息

調用棧信息是分析程序崩潰的非常重要的一個信息,它主要記錄了程序在 Crash 前的函數調用關係以及當前正在執行函數的信息,它對應的是我們 tombstone 文件中 backtrace 符號開始的信息,上面例子中的 backtrace 的信息如下所示:

backtrace:
    #00 pc 00006639  /system/lib/libui.so (android::Fence::waitForever(char const*)+41)
    #01 pc 00034b86  /system/lib/libsurfaceflinger.so
    #02 pc 0003229e  /system/lib/libsurfaceflinger.so
    #03 pc 0002cb9c  /system/lib/libgui.so (android::BufferQueue::ProxyConsumerListener::onFrameAvailable(android::BufferItem const&)+652)
    #04 pc 000342f4  /system/lib/libgui.so (android::BufferQueueProducer::queueBuffer(int, android::IGraphicBufferProducer::QueueBufferInput const&, android::IGraphicBufferProducer::QueueBufferOutput*)+2580)

在上面的輸出信息中, ##00,#01,#02……等表示的都是函數調用棧中棧幀的編號,其中編號越小的棧幀表示著當前最近調用的函數信息,所以棧幀標號 #00 表示的就是當前正在執行並導致程序 Crash 函數的信息。

在棧幀的每一行中,pc 後面的 16 進制數值表示的是當前函數正在執行語句的在共享鏈接庫或者可執行文件中的位置,然後 /system/lib/libui.so 則表示的是當前執行指令是在哪個文件當中,後面的小括號則是註明對應的是哪個函數。

例如,在上面的例子中,我們就可以定位到是程序是在 Fence::waitForever(char const* )中出現了錯誤,但是具體在那一行呢,我們還不是特別清楚,所以就需要我們進一步地使用更加高級的工具來幫助我們解析 tombstone 中有關調用棧的信息。

定位 Crash 源碼位置的工具

前面我們簡要地介紹了 tombstone 文件的結構以及每個部分的相關含義,我們可以得到導致程序 Crash 掉的主要原因是什麼(根據 Signal 的類型),也知道了是在主線程還是在子線程中掛掉了,但是我們對程序具體在代碼中的哪個位置掛掉了,還不是特別清楚,最多還只是通過 backtrace 中的棧幀的信息大概定位到位於哪個函數中,但具體是哪個文件哪個函數那一行還是不清楚的。所以,我們接下來就需要借助一些更加高級的工具來定位 Bug 在代碼中的具體位置。

說明

Google 提供的 Android NDK 開發包中已經為我們提供了非常便利好用的解析工具了,我們主要使用了下面兩種工具來解析 tombstone:

  • addr2line
  • ndk-stack

所以,在使用這兩種工具之前,你首先得把 Android NDK 工具包在你的電腦上安裝好。

addr2line

addr2line 是 NDK 中用來獲得指定動態鏈接庫文件或者可執行文件中指定地址對應的源代碼信息,它位於 NDK 包中的如下位置中:

$NDK_HOME/toolchains/x86-4.6/prebuilt/linux-x86/bin/i686-linux-android-addr2line

其中 NDK_HOME 表示你 NDK 的安裝路徑。 雖然在 Linux 中同樣有 addr2line 命令了,但是它與 NDK 中提供的 addr2line 指令還是略有差別的,所以我們可以使用 alias 來將 shell 中默認的 addr2line 指令鏈接的 NDK 的上述路徑中,命令如下所示:

alias addr2line='$NDK_HOME/toolchains/x86-4.6/prebuilt/linux-x86/bin/i686-linux-android-addr2line'

這樣之後,我們就可以在 Linux 中的 shell 環境中來直接使用 addr2line 命令了。 addr2line 命令的各個參數的含義如下所示:

woshijpf@woshijpf-OptiPlex-9020:~/newspace/android-x86/out/target/product/x86/symbols/system/lib$ addr2line -h
Usage: addr2line [option(s)] [addr(s)]
 Convert addresses into line number/file name pairs.
 If no addresses are specified on the command line, they will be read from stdin
 The options are:
  @<file>                Read options from <file>
  -a --addresses         Show addresses
  -b --target=<bfdname>  Set the binary file format
  -e --exe=<executable>  Set the input file name (default is a.out)
  -i --inlines           Unwind inlined functions
  -j --section=<name>    Read section-relative offsets instead of addresses
  -p --pretty-print      Make the output easier to read for humans
  -s --basenames         Strip directory names
  -f --functions         Show function names
  -C --demangle[=style]  Demangle function names
  -h --help              Display this information
  -v --version           Display the program's version

addr2line: supported targets: elf64-x86-64 elf32-i386 elf32-x86-64 a.out-i386-linux pei-i386 pei-x86-64 elf64-l1om elf64-k1om elf64-little elf64-big elf32-little elf32-big pe-x86-64 pe-i386 plugin srec symbolsrec verilog tekhex binary ihex
Report bugs to <http://www.sourceware.org/bugzilla/>

addr2line 的基本用法如下所示:

woshijpf@woshijpf-OptiPlex-9020:~/newspace/android-x86/out/target/product/x86/symbols/system/lib$ addr2line -f -e libui.so 00006639
_ZN7android5Fence11waitForeverEPKc
/home/woshijpf/newspace/android-x86/frameworks/native/libs/ui/Fence.cpp:59

哈哈,使用了 addr2line 工具之後,我們終於看到 libui.so 文件中地址 00006639 對應的源碼是什麼了,它對應的是 Android 系統源碼中 /home/woshijpf/newspace/android-x86/frameworks/native/libs/ui/Fence.cpp:59 處代碼(因為上面的 tombstone 文件是由於 Android 系統中的 surfaceFlinger 進程崩潰而產生的,所以它對應的源碼也是 Android 系統中有關 SurfaceFlinger 部分的源碼)。

ndk-stack

Android NDK 自從版本 r6開始, 提供了一個工具 ndk-stack。這個工具能自動分析 tombstone 文件, 能將崩潰時的調用內存地址和 c++ 代碼一行一行對應起來.

ndk-stack 工具同樣也位於 NDK 包中,它的路徑如下所示:

$NDK_HOME/ndk-stack

ndk-stack 的使用說明如下所示:

Usage:
   ndk-stack -sym <path> [-dump <path>]

      -sym  Contains full path to the root directory for symbols.
      -dump Contains full path to the file containing the crash dump.
            This is an optional parameter. If ommited, ndk-stack will
            read input data from stdin

其中,

  • dump 參數很容易理解, 即 dump 下來的 log 文本文件. ndk-stack會分析此文件,這裡我們就是指定我們從 Android 系統中獲取到的 tombstone(這個需要通過 adb pull 的方式拉取到本地的宿主機中) 文件存放的位置。
  • sym 參數就是你android項目下,編譯成功之後,obj目錄下的文件。

由於 ndk-stack 主要是用來分析用 C++ 編寫的單獨的 NDK 程序,所以下面就以解析一個 NDK 程序運行時 Crash 後產生的 tombstone 為例,tombstone 文件的內容如下所示:

// tombstone_01 文件內容
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'Android-x86/android_x86/x86:5.1.1/LMY48W/woshijpf04211939:eng/test-keys'
Revision: '0'
ABI: 'x86'
pid: 2125, tid: 2125, name: androidvncserve  >>> androidvncserver <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
    eax 00000000  ebx b76ffff4  ecx b6a37000  edx 00000000
    esi 00000000  edi 00000000
    xcs 00000073  xds 0000007b  xes 0000007b  xfs 00000000  xss 0000007b
    eip b75a4ec5  ebp bfa9bd08  esp bfa9bbf0  flags 00010246

backtrace:
    #00 pc 0004bec5  /system/bin/androidvncserver
    #01 pc 0004e3e4  /system/bin/androidvncserver
    #02 pc 0001365a  /system/lib/libc.so (__libc_init+106)
    #03 pc 0001060c  /system/bin/androidvncserver

stack:
         bfa9bbb0  bfa9bbc8  [stack]
         bfa9bbb4  b72c6fb0  /system/lib/libdvnc_flinger_sdk22.so
         bfa9bbb8  b72c7004  /system/lib/libdvnc_flinger_sdk22.so
         bfa9bbbc  b72c5b26  /system/lib/libdvnc_flinger_sdk22.so (readfb_flinger+38)
         bfa9bbc0  b68ae080  
         bfa9bbc4  00000000  
         bfa9bbc8  00000000  
         bfa9bbcc  00000000  
         bfa9bbd0  00000000  
         bfa9bbd4  b76ffff4  /system/bin/androidvncserver
         bfa9bbd8  b76a5e20  /system/bin/androidvncserver
         bfa9bbdc  b75ac181  /system/bin/androidvncserver
         bfa9bbe0  b75ac16b  /system/bin/androidvncserver
         bfa9bbe4  b76ffff4  /system/bin/androidvncserver
         bfa9bbe8  bfa9bd08  [stack]
         bfa9bbec  b75a579b  /system/bin/androidvncserver
    #00  bfa9bbf0  00000012  
         bfa9bbf4  bfa9bc1c  [stack]
         bfa9bbf8  00000000  
         bfa9bbfc  00000000  
         bfa9bc00  bfa9bc14  [stack]
         bfa9bc04  00000000  
         bfa9bc08  00000000  
         bfa9bc0c  b7498825  /system/lib/libc.so (je_free+453)
         bfa9bc10  0000000e  
         bfa9bc14  00000400  
         bfa9bc18  00000000  
         bfa9bc1c  b749538a  /system/lib/libc.so (je_malloc+778)
         bfa9bc20  0000000c  
         bfa9bc24  00000065  
         bfa9bc28  00000000  
         bfa9bc2c  b6a37000  
         ........  ........
    #01  bfa9bd10  b6bb7300  
         bfa9bd14  00001b58  
         bfa9bd18  b76aa954  /system/bin/androidvncserver
         bfa9bd1c  0000000b  
         bfa9bd20  00000005  
         bfa9bd24  00000000  
         bfa9bd28  00000000  
         bfa9bd2c  00000005  
         bfa9bd30  00000006  
         bfa9bd34  00000005  
         bfa9bd38  00000000  
         bfa9bd3c  00000000  
         bfa9bd40  00000000  
         bfa9bd44  bfa9bd24  [stack]
         bfa9bd48  b754f9c8  /system/bin/linker
         bfa9bd4c  b7557bd8  /system/bin/linker
         ........  ........
    #02  bfa9bed0  00000001  
         bfa9bed4  bfa9bf14  [stack]
         bfa9bed8  bfa9bf1c  [stack]
         bfa9bedc  00000000  
         bfa9bee0  b7556fec  /system/bin/linker
         bfa9bee4  bfa9bf10  [stack]
         bfa9bee8  00000000  
         bfa9beec  b7556fec  /system/bin/linker
         bfa9bef0  bfa9bf10  [stack]
         bfa9bef4  00000000  
         bfa9bef8  bfa9bf0c  [stack]
         bfa9befc  b756960d  /system/bin/androidvncserver
    #03  bfa9bf00  bfa9bf10  [stack]
         bfa9bf04  00000000  
         bfa9bf08  b756960d  /system/bin/androidvncserver
         bfa9bf0c  b7569612  /system/bin/androidvncserver
         bfa9bf10  00000001  
         bfa9bf14  bfa9cb05  [stack]
         bfa9bf18  00000000  
         bfa9bf1c  bfa9cb16  [stack]
         bfa9bf20  bfa9cb35  [stack]
         bfa9bf24  bfa9cb48  [stack]
         bfa9bf28  bfa9cba3  [stack]
         bfa9bf2c  bfa9cbae  [stack]
         bfa9bf30  bfa9cbc1  [stack]
         bfa9bf34  bfa9cbdc  [stack]
         bfa9bf38  bfa9cbe7  [stack]
         bfa9bf3c  bfa9cbfd  [stack]

使用 ndk-stack 處理之後的結果:

woshijpf@woshijpf-OptiPlex-9020:~/android_workspace/droidVNCserver-real$ ndk-stack -sym obj/local/x86/ -dump ~/android-x86-debug-log/tombstone_01
********** Crash dump: **********
Build fingerprint: 'Android-x86/android_x86/x86:5.1.1/LMY48W/woshijpf04211939:eng/test-keys'
pid: 2125, tid: 2125, name: androidvncserve  >>> androidvncserver <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
Stack frame #00 pc 0004bec5  /system/bin/androidvncserver: Routine update_screen_16 in /home/woshijpf/android_workspace/droidVNCserver-real/jni/vnc/updateScreen.c:68
Stack frame #01 pc 0004e3e4  /system/bin/androidvncserver: Routine main in /home/woshijpf/android_workspace/droidVNCserver-real/jni/vnc/droidvncserver.c:805
Stack frame #02 pc 0001365a  /system/lib/libc.so (__libc_init+106)
Stack frame #03 pc 0001060c  /system/bin/androidvncserver: Unable to locate routine information for address 1060c in module obj/local/x86//androidvncserver
Stack frame #00 pc 0007bf71  /system/lib/libc.so (nanosleep+17)
Stack frame #01 pc 00047ed6  /system/lib/libc.so (usleep+70)
Stack frame #02 pc 0004fa6b  /system/bin/androidvncserver: Routine camera_io in /home/woshijpf/android_workspace/droidVNCserver-real/jni/vnc/camera_io.c:557
Stack frame #03 pc 0004af6a  /system/bin/androidvncserver: Routine receive_camera in /home/woshijpf/android_workspace/droidVNCserver-real/jni/vnc/droidvncserver.c:273
Stack frame #04 pc 00022168  /system/lib/libc.so (__pthread_start(void*)+56)
Stack frame #05 pc 0001cc69  /system/lib/libc.so (__start_thread+25)
Stack frame #06 pc 000137c6  /system/lib/libc.so (__bionic_clone+70)
Stack frame #00 pc 0007cc33  /system/lib/libc.so (recvfrom+19)
Stack frame #01 pc 00050cdb  /system/bin/androidvncserver: Routine handle_connections in /home/woshijpf/android_workspace/droidVNCserver-real/jni/vnc/gui.c:105
Stack frame #02 pc 00022168  /system/lib/libc.so (__pthread_start(void*)+56)
Stack frame #03 pc 0001cc69  /system/lib/libc.so (__start_thread+25)
Stack frame #04 pc 000137c6  /system/lib/libc.so (__bionic_clone+70)

經過 ndk-stack地這麼處理之後,我們就非常直接明了地看到了每個棧幀中調用函數的內存地址和程序源碼的關係。是不是感覺很爽啊!

總結

Android NDK 程序的系統調試其實也沒那麼複雜,雖然它長著一副恐怖的外表,但是只要掌握了正確的方法,瞭解 Tombstone 文件中關鍵信息的含義,學會使用 addr2line 和 ndk_stack 這兩個超級方便的工具,那麼一步一步找出導致 NDK 程序 Crash 的 Bug 就非常 Easy 了。 但上面的這些工作也還只是幫助你快速地定位到你的代碼出現問題的位置,具體的 Bug 還是需要你進一步地根據業務邏輯來分析代碼。

posted by admin in 程式&軟體 and have No Comments

Place your comment

Please fill your data and comment below.
Name
Email
Website
Your comment