博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
(android 源码下开发应用程序) 如何在 Android 各 level ( 包含 user space 與 kernel space ) 使用dump call stack的方法...
阅读量:5887 次
发布时间:2019-06-19

本文共 4145 字,大约阅读时间需要 13 分钟。

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://gmrix.baihongyu.com/

你可能感兴趣的文章
C++中的堆,栈,静态内存区,常量区
查看>>
动态SQL实现与注意事项(有返回值与无返回值动态SQL 实现)
查看>>
java struts2 debug
查看>>
解析 PHP 中 session 的实现原理以及大网站应用应该注意的问题
查看>>
[转].net mvc + vuejs 的项目结构
查看>>
Centos7安装Redis
查看>>
简单够用的设计
查看>>
javascript权威指南--学习笔记
查看>>
梦断代码阅读笔记02
查看>>
git和tortoisegit下载
查看>>
53. Maximum Subarray
查看>>
flask踩坑和排坑记录
查看>>
iOS UITableView 微信页面
查看>>
得到一定范围内的随机数
查看>>
使用Nodejs获取博客园博客数据并处理转发
查看>>
2003终端服务器授权,120天试用期限制
查看>>
springboot项目创建(myeclipse2017)
查看>>
Auto-encoder 在异常检测中的应用
查看>>
C#委托的介绍(delegate、Action、Func、predicate)
查看>>
mysql 中判断表是否存在 以及表存在则删除
查看>>