標籤:
找出程式的呼叫堆疊 trace 可以知道是誰調用了這個介面,也能快速學習程式的調用流程,非常實用。但需要注意的是,不能在正式代碼中使用,只能用於調試,這個非常耗資源也會造成 log 泛濫。
下面就介紹如何在 Android Java/C++/C 程式當中列印出程式調用 trace,如果需要在其他環境中使用的話 C++/C 部分需要移植 corkscrew 庫。
Java
非常簡單,建立一個 Throwable 對象,就可以得到當前的 stack trace。下面例子是打出調用 foobar() 函數的 trace:
1 private void foobar() {2 Throwable t = new Throwable();3 Log.d(TAG, "stack trace is ", t);4 }C++
也比較簡單,使用 utils/Callstack 類即可。標頭檔位於 frameworks/native/include/utils/CallStack.h,一般無需修改 Android.mk 可直接使用。下面例子是打出調用 Foo::bar() 函數的 trace:
1 #include <utils/CallStack.h> 2 3 void Foo::bar() {4 // CallStack::CallStack(const char* logtag, int32_t ignoreDepth, int32_t maxDepth)5 CallStack *t = new CallStack("Trace", 1, 30);6 delete t;7 }C
稍微麻煩一點,需要直接調用 corkscrew/backtrace。其實 C++ 裡的 utils/Callstack 也是使用 corkscrew/backtrace,只是進行了封裝更便於使用。我們參照 CallStack.cpp 裡面代碼即可。下面例子是打出調用 foobar() 函數的 trace:
NOTE: C 不能直接調用 C++ 代碼,除非在 C++ 類中添加相應的 C wrapper,或者通過 dlsym 動態載入。
1 #include <corkscrew/backtrace.h> 2 3 void dumpStackTrace(const char* logtag, int32_t ignoreDepth, int32_t maxDepth) const { 4 static const int MAX_DEPTH = 31; 5 static const int MAX_BACKTRACE_LINE_LENGTH = 800; 6 7 if (maxDepth > MAX_DEPTH) { 8 maxDepth = MAX_DEPTH; 9 }10 backtrace_frame_t mStack[MAX_DEPTH];11 ssize_t count = unwind_backtrace(mStack, ignoreDepth + 1, maxDepth);12 if (count <= 0) {13 LOGE("Can not get stack trace");14 return;15 }16 17 backtrace_symbol_t symbols[count];18 19 get_backtrace_symbols(mStack, count, symbols);20 for (size_t i = 0; i < count; i++) {21 char line[MAX_BACKTRACE_LINE_LENGTH];22 format_backtrace_line(i, &mStack[i], &symbols[i],23 line, MAX_BACKTRACE_LINE_LENGTH);24 ALOG(LOG_DEBUG, logtag, "%s%s",25 "",26 line);27 }28 free_backtrace_symbols(symbols, count);29 }30 31 void foobar() {32 dumpStackTrace("Trace", 1, 30);33 }
標頭檔位於 system/core/include/corkscrew/backtrace.h,在 Android.mk 中還需要加入:
1 LOCAL_SHARED_LIBRARIES += libcorkscrew
如何打出Android程式調用stack trace