• (android 源码下开发应用程序) 如何在 Android 各 level ( 包含 user space 與 kernel space ) 使用dump call stack的方法


    http://janbarry0914.blogspot.com/2014/07/androiddump-call-stack.html

    dump call stack


    [文章重點]

    了解 Android 各 level ( UI, framework 與 HAL) 與 kernel 間, 如何印出 call stack, 方便追 code 與 debug

    [文章目錄]
    1. kernel call stack
    2. Android Java layer
    3. Android framework ( written by c++)
    4. Android HAL ( written by c )
    5. Call Stack 沒有出現 function name

    kernel call stack

    如果想知道call stack,也就是說, 我們想知道是誰call到func_foo(). 此時,我們可以利用 dump_stack(),放在你想dump back trace的地方就OK囉.
     
    void func_foo(void){
     
      int a=3;
      ...
      
      dump_stack();

      ...

    }

    Java layer call stack
    在Java檔案, 可以使用下述方法得到dump call stack


    public void foo(boolean state, int flags) {
     ...
     Log.d(TAG,"xxxx", new Throwable());
     ...
    }


    C++ layer call stack

    在C/C++ 檔案, Android 已經有寫了frameworks/native/libs/utils/CallStack.cpp 供我們使用


    #include <utils/CallStack.h>
    ...
    void foo(void) {
    ...
       android::CallStack stack;
       stack.update();
       stack.dump("XXX");

    ...
    }


    如果你所使用是Android 4.4 之後
    請改用


    #include <utils/CallStack.h>
    ...
    void foo(void) {
    ...
       android::CallStack stack;
       stack.update( );
       stack.log("XXX");

    ...
    }

    在Android.mk 記得要加


    LOCAL_SHARED_LIBRARIES += libutils


    C layer call stack

    由於C去call C++需要做一些宣告, 所以將它獨立出來方便使用(dump_stack.cpp與 dump_stack.h)


    dump_stack.h

    #ifdef __cplusplus
    extern "C" {
    #endif

     void dump_stack_android(void);
     
    #ifdef __cplusplus
    }
    #endif


    dump_stack.cpp


    #include "dump_stack.h"
    #include <utils/CallStack.h>

    using namespace android;
    extern "C"{
     void dump_stack_android(void)
     {
    CallStack stack;
    stack.update();
    stack.dump("XXX");
     }
    }


    如果你所使用是Android 4.4 之後
    請改用


    #include "dump_stack.h"
    #include <utils/CallStack.h>

    using namespace android;
    extern "C"{
     void dump_stack_android(void)
     {
    CallStack stack;
    stack.update();
    stack.log("XXX");
     }
    }


    同樣地, Android.mk也需要修改


    LOCAL_SRC_FILES :=
            …...
            dump_stack.cpp

    LOCAL_SHARED_LIBRARIES += libutils


    接下來在C file中要使用時只要


    extern void dump_stack_android();


    void function_a()
    {
     …
     dump_stack_android();
     …
    }


    [ Call Stack 沒有出現 function name]
    有時我們會發現在C++ 或 C 語言中使用 CallStack , 在 call dump 中並沒有出現 function name


    D/XXX (  147): #00  pc 00001b90  /system/lib/hw/audio.primary.mrvl.so (dump_stack_android+19)
    D/XXX (  147): #01  pc 00004b56  /system/lib/hw/audio.primary.mrvl.so
    D/XXX (  147): #02  pc 0001f828  /system/lib/libaudioflinger.so
    D/XXX (  147): #03  pc 00019138  /system/lib/libaudioflinger.so
    D/XXX (  147): #04  pc 00023bb6  /system/lib/libaudioflinger.so
    D/XXX (  147): #05  pc 0000e9fe  /system/lib/libutils.so (android::Thread::_threadLoop(void*)+213)
    D/XXX (  147): #06  pc 0000e530  /system/lib/libutils.so
    D/XXX (  147): #07  pc 0000d208  /system/lib/libc.so (__thread_entry+72)
    D/XXX (  147): #08  pc 0000d3a4  /system/lib/libc.so (pthread_create+240)


    我們追一下 CallStack 是如何被實作
    先回顧一下 CallStack 是如何被使用 (以 Android 4.4 為例)

     CallStack stack;  
     stack.update();  
     stack.log();  
    


    先看一下 update( ) function 的定義 ( it is under system/core/include/utils/CallStack.h)

       // Immediately collect the stack traces for the specified thread.  
       void update(int32_t ignoreDepth=1, int32_t maxDepth=MAX_DEPTH, pid_t tid=CURRENT_THREAD);  
    

    所以透過 update( ) function, 我們可以設定想看哪一個 thread 並 dump 出多少層的 call stack, 如果都沒寫, 就是以當前的 thread 去做 call stack dump, update( ) function 會將實際可以 dump 多少的 frame 給抓出來, 其中 frame 的數量記錄在 mCount 變數, 各 frame 的資訊則記錄在 mStack[ ] 裡面, 接下來再透過 log( ) function 把 call stack 裡的 program counter 所記載的記憶體位址去把相對應的 function name 給解析出來.

     log( )  
     |--> print( )  
        |--> get_backtrace_symbols( )  
    


    看一下 get_backtrace_symbols( ) 在做些什麼

    void get_backtrace_symbols(const backtrace_frame_t* backtrace, size_t frames,
        backtrace_symbol_t* backtrace_symbols) {

       ... 
    for (size_t i = 0; i < frames; i++) {
           ...
               Dl_info info;
               if (dladdr((const void*)frame->absolute_pc, &info) && info.dli_sname) {
                symbol->relative_symbol_addr = (uintptr_t)info.dli_saddr
                        - (uintptr_t)info.dli_fbase;
                symbol->symbol_name = strdup(info.dli_sname);
                symbol->demangled_name =
                           demangle_symbol_name(symbol->symbol_name);
               }
          ...
    }
    release_my_map_info_list(milist);
    }


    這是因為它是使用 dladdr() 去讀取該share lib的 dynamic symbol 而獲取 function name
    但是如果該 function 是宣告成 static, 該 function name 就不會出現在 dynamic symbol 裡 (你可以使用 arm-linux-androideabi-nm -D xxxx.so | grep the_function_name , 如果沒有出現, 就表示該 funciton name 並不在 dynamic symbol 裡),  遇到這情況就只好使用 add2line 指令去讀 out folder 下的 symbol 了, 各位可以參考我另一篇文章 http://janbarry0914.blogspot.tw/2011/07/android-crash-tombstone.html . 感謝.
  • 相关阅读:
    python ddt数据驱动框架
    yarn的安装和使用【转】
    辅助色选取思路
    echarts y轴起始坐标值设置
    mapbox 图层视角设置
    vue-cli2使用store存储全局变量
    vue 数组不响应解决办法
    echarts之dataZoom配置项【转】
    Vue中使用地图平台MapboxGL【转载】
    快速入门MapboxGL【转载】
  • 原文地址:https://www.cnblogs.com/welhzh/p/4922435.html
Copyright © 2020-2023  润新知