Android里调用callstack(转)

Android里调用callstack(转),第1张

概述1.        为什么要打印函数调用堆栈?打印调用堆栈可以直接把问题发生时的函数调用关系打出来,非常有利于理解函数调用关系。比如函数A可能被B/C/D调用,如果只看代码,B/C/D谁调用A都有可能,如果打印出调用堆栈,直接就把谁调的打出来了。不仅如此,打印函数调用堆栈还有另一个好

1.        为什么要打印函数调用堆栈?

打印调用堆栈可以直接把问题发生时的函数调用关系打出来,非常有利于理解函数调用关系。比如函数A可能被B/C/D调用,如果只看代码,B/C/D谁调用A都有可能,如果打印出调用堆栈,直接就把谁调的打出来了。

不仅如此,打印函数调用堆栈还有另一个好处。在AndroID代码里,函数命名很多雷同的,虚函数调用,几个类里的函数名相同等,即使用source insight工具看也未必容易看清函数调用关系。如果用了堆栈打印,很容易看到函数调用逻辑。

那么一个问题来了,AndroID/kernel本身在发生问题(kernel panic, tombstone, …)时,都可以打出详细的堆栈信息,这里干嘛还要费劲研究打堆栈?答案是发生问题时的堆栈的确很详细,但这里研究的是不影响(准确说是基本不影响)系统运行的境况下,打印出某个情形下的堆栈信息,这个对源代码逻辑研究很有帮助。或者是说,在未发生kernel panic, tombstone的时候,我们需要打印出堆栈信息。

 

2.        linux Kernel

Kernel里最简单,直接有几现成的函数可以使用:

dump_stack() 这个函数打出当前堆栈和函数调用backtrace后接着运行

WARN_ON(x) 这个函数跟dump_stack很像,它有个条件,如果条件满足了就把stack打出来。

打印出来的结果都在kernel log里,一般dmesg命令就可以看到了

 

3.        Native C++

AndroID在新版(至少5.0, 6.0)里加入了CallStack类,这个类可以打出当前的backtrace。用法很简单:

前面确保包含头文件#include <utils/CallStack.h> 

AndroID.mk的库依赖列表(LOCAL_SHARED_liBRARIES)里包含libutilscallstack,一般都已经包含了。

然后在要打印堆栈处加入androID::CallStack cs(“My CallStack DeBUG”);

“My CallStack DeBUG”是在logcat输出的TAG,这里可以自己定义。如果上下文已经在androID namespace里,”androID::”前缀就不必加了。

Native C++的输出log可以在logcat里看到。

 

注意,在网上的一些文档里说要这么用:

CallStack stack; 

stack.update(); 

stack.dump();

这样做已经不行了,在新版AndroID里编译不过。

 

4.        Native C

AndroID对C的堆栈打印支持不太好。过去网上的文章一般是推荐libcorkscrew.so,并加入大段代码来unwind_backtrace。新版AndroID上libcorkscrew已经被拿掉了,网上的加载libcorkscrew库的方法自然就不能用了。

 

一个简单方法是用C语言调C++的函数,对,就是extern “C”。

先在项目里加入一个c++文件,比如callstack.cpp,里面是:

#include <utils/CallStack.h>extern "C" voID dumPing_callstack(voID);voID dumPing_callstack(voID){    androID::CallStack cs("My CallStack DeBUG");}

在项目里再加入一个c++的头文件,比如callstack.h,里面是:

voID dumPing_callstack(voID);

 

在AndroID.mk里源文件列表LOCAL_SRC_fileS里加入callstack.cpp,并确保libutilscallstack在依赖列表里。

在native C里include callstack.h后直接调用dumPing_callstack()就可以了。

这个log也可以在logcat里看到。

 

For Celadon:

callstack.cpp:

#include "callstack.h"#include <utils/CallStack.h>extern "C" {    voID dump_stack02(voID)   {        //androID::CallStack stack;        //stack.update();        //stack.dump("INTEL-MESA");       androID::CallStack cs("INTEL-MESA");       cs.update();       cs.log("INTEL-MESA", ANDROID_LOG_ERROR, "");   }}

callstack.h:

#ifndef _CALLBACK_H#define _CALLBACK_H#ifdef __cplusplusextern "C" {#endif    voID dump_stack02(voID);#ifdef __cplusplus}#endif#endif

in AndroID.mk, add libutilscallstack in LOCAL_SHARED_liBRARIES

 LOCAL_SHARED_liBRARIES := \+   libutilscallstack \

in Makefile.sources, add the callstack.cpp and callstack.h like below

@@ -2,4 +2,6 @@ C_SOURCES := \    virgl_drm_public.h \    virgl_drm_winsys.c \    virgl_drm_winsys.h \-   virtgpu_drm.h+   virtgpu_drm.h \+   callstack.cpp \+   callstack.h

 

in the file you want to add callstack:

调用 dump_stack02();

 

还需要

$ adb root

$ adb remount

$ adb push out/target/product/caas/vendor/lib64/egl/libGLES_mesa.so /vendor/lib64/egl/$ adb push out/target/product/caas/vendor/lib/egl/libGLES_mesa.so /vendor/lib/egl/$ adb push out/target/product/caas/vendor/lib64/dri/i965_dri.so /vendor/lib64/dri/$ adb push out/target/product/caas/vendor/lib/dri/i965_dri.so /vendor/lib/dri/

 

然后

$ adb shell sync

最后把QEMU停掉,再启动。

 

5.        Java

Java最简单,它的backtrace最详细,连文件名和行号都打出来了:

Exception e = new Exception("haha");

e.printstacktrace();

log在logcat里看以看到。

 

大部分内容转自: http://blog.sina.com.cn/s/blog_7213e0310102wtge.HTML

总结

以上是内存溢出为你收集整理的Android里调用callstack(转)全部内容,希望文章能够帮你解决Android里调用callstack(转)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1019476.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存