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
(http://stackoverflow.com/questions/11731229/dladdr-doesnt-return-the-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 . 感謝.

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

  1. Android Studio 创建的app放到Android 源码下编译

    文章目录 环境 步骤 创建一个Android Studio 新项目 编写编译脚本 Android.mk Android.bp 环境 Android Studio版本: Android Studio D ...

  2. android源码下编译apk内无so,Android源码编译反思

    [初步构想] 如果是在一台PC上先完整的编译一次Android源码,然后将整个编译好的源码移到另一台PC,然后再在移到的PC上编译,这样估计是可以减少时间的吧? [初步测试] 初步测试结果,很令我感动 ...

  3. Android源码下 进行cts测试 和 cts的注意事项。

    2019独角兽企业重金招聘Python工程师标准>>> 1,. build/envsetup.sh 2,make cts 3,android设备打开usb-debugging模式,最 ...

  4. android device目录,Android源码下device目录的分析

    一般源码的编译前都会执行lunch命令,选择编译目标: source build/envsetup.sh lunch BUILD_BUILDTYPE 其中BUILDTYPE可以为user.userde ...

  5. Android 源码开发系列(二)Android SIM/USIM

    随着手机的普及,大家从非智能机到智能机的转变,从没有操作系统的定制机到智能手机,但唯一没有变的是,手机中的SIM,今天我们就来谈谈手机中SIM卡相关的内容.在日常生活中,SIM卡就是一张很小的卡片,但 ...

  6. android用什么更新应用程序,如何在Android上更新应用程序 教你如何更新安卓手机APP...

    您从Play商店下载的大多数Android应用程序都会出于各种原因而定期提供更新:添加功能,错误修复,提高安全性...了解如何在Android智能手机上管理应用程序以及如何使它们保持最新. 如果您想要 ...

  7. android源码opengrok,搭建OpenGrok 快速索引android源码

    openggrok可以快速浏览源码,查找相关文件及函数等. 代码再服务器,本地使用opengrok搜索. 搭建环境等都在服务器进行. 注意:一下配置均在服务器进行,打开网址均在本地进行. 代码再云上, ...

  8. android点击下拉历史记录,如何在Android上删除浏览历史记录-万兴恢复专家

    第4部分:如何在Android上永久清除历史记录? 只需删除数据或使用恢复出厂设置无法永久擦除Android.在恢复过程的帮助下,数据很容易恢复,Avast已经证明了这一点.dr.fone工具包 - ...

  9. android 源码分析 内置 sd storage,Android开罐头———外部存储与内部存储完全解析...

    context.getExternalFilesDir(),Environment.getExternalStorageDirectory(),傻傻分不清?到底什么算安卓手机的external sto ...

最新文章

  1. 数据数字mongodb 模糊查询以及$type使用
  2. 快速搭建一个restful风格的springboot项目
  3. [学习笔记] 如果你愿意学那么你是可以看的懂的 —— 群论与 burnside 引理和 polya 定理
  4. node-包管理工具 npm
  5. java 页面级缓存_用CashFilter实现页面级缓存实践
  6. python统计数据分析基础教程_Python数据分析基础教程:NumPy学习指南(第2版)
  7. angualrjs学习总结二(作用域、控制器、过滤器)
  8. 如何读懂3GPP协议
  9. 使用Zxing及豆瓣API
  10. 知识图谱概论(二):概念具象化描述
  11. linux sfc模拟器,PSP适用SFC模拟器Snes9x完全使用教程
  12. linux下安装drcom方法
  13. 微信小程序全屏背景图
  14. 重新发现业务架构:银行数字化转型经验与方法分析
  15. 智能车浅谈——抗干扰技术软件篇
  16. 列表表达式爬取红牛分公司数据
  17. 我平时整理的一个生成机器码的类(转载)
  18. 推荐系统:协同过滤及其利弊
  19. Server U 的使用
  20. 线性代数与解析几何——Part4 欧式空间 酉空间

热门文章

  1. 浅尝JQ AJAX
  2. 【mysql】悲观锁和乐观锁的实现原理
  3. 线上BUG 处理并分析原因
  4. dbutils mysql_使用DBUtils控制mysql事务
  5. 测试 软通动力软件测试机试_5000字长文,计算机保研机试介绍及准备策略!高分过过过!...
  6. Mysql8.0 15安装后怎么打开_mysql-8.0.15-winx64 解压版安装 图文详解
  7. 记者“卧底”程序猿的故事
  8. 我如何开始学习Web开发
  9. 前端人员必须掌握哪些技术?常见缓存种类有什么?
  10. 面试容易问的 JavaScript 知识点,你知道几个?