您的位置:首页 > 移动开发 > Android开发

Android下打印调试堆栈方法

2014-05-05 10:23 519 查看
打印堆栈是调试的常用方法,一般出现异常时,我们可以在跑出异常时也将堆栈情况打印出来,这样十分方便错误查找。另外实际上也有一个非常有用的功能:分析代码的行为。android代码太过庞大了,完全的静态分析经常是无从下手,因此通过打印堆栈的动态分析也十分必要。

Android打印堆栈的方法,简单归类一下

1.zygote的堆栈dump

实际上这个可以同时dumpjava线程及native线程的堆栈,对于java线程,java堆栈和native堆栈都可以得到。

使用方法很简单,直接在adbshell窗口或串口中输入:

kill-3<pid>
输出的trace会保存在/data/anr/traces.txt文件中。

如果需要在代码中,更容易控制堆栈的输出时机,可以用以下命令获取zygote的coredump:
Process.sendSignal(pid,Process.SIGNAL_QUIT);


原理和命令行是一样的。

不过需要注意两点:

adbshell可能会没有权限。
android4.2中关闭了nativethread的堆栈打印,详见dalvik/vm/Thread.cpp的dumpNativeThread方法:

dvmPrintDebugMessage(target,
"\"%s\"sysTid=%dnice=%dsched=%d/%dcgrp=%s\n",
name,tid,getpriority(PRIO_PROCESS,tid),
schedStats.policy,schedStats.priority,schedStats.group);
dumpSchedStat(target,tid);
//Temporarilydisabledcollectingnativestacksfromnon-Dalvik
//threadsbecausesometimestheymisbehave.
//dvmDumpNativeStack(target,tid);


不过对于大多数情况,可以直接将这个注释打开。

2.debuggerd的堆栈dump

debuggerd是android的一个daemon进程,负责在进程出错异常时,将进程的运行时信息给dump出来供分析。debuggerd的coredump数据,被保存在/data/tombstone/目录下(名字取的也很形象,tombstone是墓碑的意思),共可保存10个文件,当超过10个时,会覆盖重写最早生产的文件。在4.2版本中,debuggerd同时也是一个工具明了,可以在不中断进程执行的情况下打印堆栈。使用方法是:

debuggerd-b<pid>


3.java代码中打印堆栈

Java代码打印堆栈比较简单,堆栈信息获取和输出,都可以通过Throwable类的方法实现。目前通用的做法是在java进程出现需要注意的异常时,打印堆栈,然后再决定退出或挽救。通常的方法是使用exception的printStackTrace()方法:

try{
...
}catch(RemoteExceptione){
e.printStackTrace();
...
}


当然也可以只打印堆栈不退出,这样就比较方便分析代码的动态运行情况。Java代码中插入堆栈打印的方法如下:
Log.d(TAG,Log.getStackTraceString(newThrowable()));


4.C++代码中打印堆栈

C++也是支持异常处理的,异常处理库中,已经包含了获取backtrace的接口,Android也是利用这个接口来打印堆栈信息的。在Android的C++中,已经集成了一个工具类CallStack,在libutils.so中。使用方法:
#include<utils/CallStack.h>
...
CallStackstack;
stack.update();
stack.dump();


使用方式比较简单。目前Andoid4.2版本已经将相关信息解析的很到位,符号表查找,demangle,偏移位置校正都做好了。


5.C代码中打印堆栈

C代码,尤其是底层C库,想要看到调用的堆栈信息,还是比较麻烦的。CallStack肯定是不能用,一是因为其实C++写的,需要重新封装才能在C中使用,而是底层库反调上层库的函数,会造成连接器循环依赖而无法链接。不过也不是没有办法,可以通过CallStack使用的unwind及符号函数来处理。

这里需要注意的是,为解决链接问题,最好使用dlopen方式,查找需要用到的接口再直接调用,这样会比较简单。如下为相关的实现代码,只需要在要打印的文件中插入此部分代码,然后调用getCallStack()即可,无需包含头文件和修改Android.mk文件:
#defineMAX_DEPTH31
#defineMAX_BACKTRACE_LINE_LENGTH800
#definePATH"/system/lib/libcorkscrew.so"

typedefssize_t(*unwindFn)(backtrace_frame_t*,size_t,size_t);
typedefvoid(*unwindSymbFn)(constbacktrace_frame_t*,size_t,backtrace_symbol_t*);
typedefvoid(*unwindSymbFreeFn)(backtrace_symbol_t*,size_t);

staticvoid*gHandle=NULL;

staticintgetCallStack(void){
ssize_ti=0;
ssize_tresult=0;
ssize_tcount;
backtrace_frame_tmStack[MAX_DEPTH];
backtrace_symbol_tsymbols[MAX_DEPTH];

unwindFnunwind_backtrace=NULL;
unwindSymbFnget_backtrace_symbols=NULL;
unwindSymbFreeFnfree_backtrace_symbols=NULL;

//opentheso.
if(gHandle==NULL)gHandle=dlopen(PATH,RTLD_NOW);

//gettheinterfaceforunwindandsymbolanalyse
if(gHandle!=NULL)unwind_backtrace=(unwindFn)dlsym(gHandle,"unwind_backtrace");
if(gHandle!=NULL)get_backtrace_symbols=(unwindSymbFn)dlsym(gHandle,"get_backtrace_symbols");
if(gHandle!=NULL)free_backtrace_symbols=(unwindSymbFreeFn)dlsym(gHandle,"free_backtrace_symbols");

if(!gHandle||!unwind_backtrace||!get_backtrace_symbols||!free_backtrace_symbols){
ALOGE("Error!cannotgetunwindinfo:handle:%p%p%p%p",
gHandle,unwind_backtrace,get_backtrace_symbols,free_backtrace_symbols);
returnresult;
}

count=unwind_backtrace(mStack,1,MAX_DEPTH);
get_backtrace_symbols(mStack,count,symbols);

for(i=0;i<count;i++){
charline[MAX_BACKTRACE_LINE_LENGTH];

constchar*mapName=symbols[i].map_name?symbols[i].map_name:"<unknown>";
constchar*symbolName=symbols[i].demangled_name?symbols[i].demangled_name:symbols[i].symbol_name;
size_tfieldWidth=(MAX_BACKTRACE_LINE_LENGTH-80)/2;

if(symbolName){
uint32_tpc_offset=symbols[i].relative_pc-symbols[i].relative_symbol_addr;
if(pc_offset){
snprintf(line,MAX_BACKTRACE_LINE_LENGTH,"#%02dpc%08x%.*s(%.*s+%u)",
i,symbols[i].relative_pc,fieldWidth,mapName,
fieldWidth,symbolName,pc_offset);
}else{
snprintf(line,MAX_BACKTRACE_LINE_LENGTH,"#%02dpc%08x%.*s(%.*s)",
i,symbols[i].relative_pc,fieldWidth,mapName,
fieldWidth,symbolName);
}
}else{
snprintf(line,MAX_BACKTRACE_LINE_LENGTH,"#%02dpc%08x%.*s",
i,symbols[i].relative_pc,fieldWidth,mapName);
}

ALOGD("%s",line);
}

free_backtrace_symbols(symbols,count);

returnresult;
}


对sched_policy.c的堆栈调用分析如下,注意具体是否要打印,在哪里打印,还可以通过pid、uid、property等来控制一下,这样就不会被淹死在trace的汪洋大海中。
D/SchedPolicy(1350):#00pc0000676c/system/lib/libcutils.so

D/SchedPolicy(1350):#01pc00006b3a/system/lib/libcutils.so(set_sched_policy+49)

D/SchedPolicy(1350):#02pc00010e82/system/lib/libutils.so(androidSetThreadPriority+61)

D/SchedPolicy(1350):#03pc00068104/system/lib/libandroid_runtime.so(android_os_Process_setThreadPriority(_JNIEnv*,_jobject*,int,int)+7)

D/SchedPolicy(1350):#04pc0001e510/system/lib/libdvm.so(dvmPlatformInvoke+112)

D/SchedPolicy(1350):#05pc0004d6aa/system/lib/libdvm.so(dvmCallJNIMethod(unsignedintconst*,JValue*,Methodconst*,Thread*)+417)

D/SchedPolicy(1350):#06pc00027920/system/lib/libdvm.so

D/SchedPolicy(1350):#07pc0002b7fc/system/lib/libdvm.so(dvmInterpret(Thread*,Methodconst*,JValue*)+184)

D/SchedPolicy(1350):#08pc00060c30/system/lib/libdvm.so(dvmCallMethodV(Thread*,Methodconst*,Object*,bool,JValue*,std::__va_list)+271)

D/SchedPolicy(1350):#09pc0004cd34/system/lib/libdvm.so

D/SchedPolicy(1350):#10pc00049382/system/lib/libandroid_runtime.so

D/SchedPolicy(1350):#11pc00065e52/system/lib/libandroid_runtime.so

D/SchedPolicy(1350):#12pc0001435e/system/lib/libbinder.so(android::BBinder::transact(unsignedint,android::Parcelconst&,android::Parcel*,unsignedint)+57)

D/SchedPolicy(1350):#13pc00016f5a/system/lib/libbinder.so(android::IPCThreadState::executeCommand(int)+513)

D/SchedPolicy(1350):#14pc00017380/system/lib/libbinder.so(android::IPCThreadState::joinThreadPool(bool)+183)

D/SchedPolicy(1350):#15pc0001b160/system/lib/libbinder.so

D/SchedPolicy(1350):#16pc00011264/system/lib/libutils.so(android::Thread::_threadLoop(void*)+111)

D/SchedPolicy(1350):#17pc000469bc/system/lib/libandroid_runtime.so(android::AndroidRuntime::javaThreadShell(void*)+63)

D/SchedPolicy(1350):#18pc00010dca/system/lib/libutils.so

D/SchedPolicy(1350):#19pc0000e3d8/system/lib/libc.so(__thread_entry+72)

D/SchedPolicy(1350):#20pc0000dac4/system/lib/libc.so(pthread_create+160)

D/SchedPolicy(1350):#00pc0000676c/system/lib/libcutils.so

D/SchedPolicy(1350):#01pc00006b3a/system/lib/libcutils.so(set_sched_policy+49)

D/SchedPolicy(1350):#02pc00016f26/system/lib/libbinder.so(android::IPCThreadState::executeCommand(int)+461)

D/SchedPolicy(1350):#03pc00017380/system/lib/libbinder.so(android::IPCThreadState::joinThreadPool(bool)+183)

D/SchedPolicy(1350):#04pc0001b160/system/lib/libbinder.so

D/SchedPolicy(1350):#05pc00011264/system/lib/libutils.so(android::Thread::_threadLoop(void*)+111)

D/SchedPolicy(1350):#06pc000469bc/system/lib/libandroid_runtime.so(android::AndroidRuntime::javaThreadShell(void*)+63)

D/SchedPolicy(1350):#07pc00010dca/system/lib/libutils.so

D/SchedPolicy(1350):#08pc0000e3d8/system/lib/libc.so(__thread_entry+72)

D/SchedPolicy(1350):#09pc0000dac4/system/lib/libc.so(pthread_create+160)



6.其它堆栈信息查询
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: