Android各种获取代码调用栈的方法[补]

打印调用栈不用说,基本上每位开发者都会用到,讨论几个方法,以前也说过,http://blog.csdn.net/freshui/article/details/9456889 再次简单整理一下吧,啰嗦就啰嗦了 :)

基本分两大类,一类是静态的,要把打印语句插入到代码中,一类是动态的,需要看的时候,查看一下,实时观测各线程调用栈情况。

静态方法

1. Java中打印调用栈

比较简单,利用Throwable,直接log中打印出来:

[java] view plain copy

  1. Log.d(TAG, Log.getStackTraceString(new Throwable()));

2. C++中打印调用栈

也是比较简单,直接利用CallStack类

[cpp] view plain copy

  1. #include <utils/CallStack.h>
  2. ...
  3. CallStack stack("FUCK");
  4. ...

CallStack从4.3开始,重写了下,现在使用比较简单了,实例化的地方就直接打印了。

3. C中打印调用栈

以前写的方法,又复杂又不好用(版本更新,很多库和接口都变了)。其实,在C中打印调用栈,也是超级简单。只要随便找一个C++的源文件,实现一个函数就可以了:

[cpp] view plain copy

  1. #include <utils/CallStack.h>
  2. extern "C" void printCallStack();
  3. void printCallStack() {
  4. CallStack stk("Fuck");
  5. }

这可以添加在Android现有code中,也可以自己新增一个cpp的文件编进来。 想要打印的地方,直接调用即可:

[cpp] view plain copy

  1. ...
  2. extern void printCallStack();
  3. void test_c_code() {
  4. ...
  5. printCallStack();
  6. ...
  7. }
  8. ...

注意:

  • C++代码的printCallStack声明一定要有extern "C",否则c++的mangle后的符号,C中是不认的
  • 添加后注意库的链接,还有命名空间别搞错了。

另外,以上方法实际上也就适用在汇编中打印CallStack,都一样的~~
以上CallStack方法, NDK中不好用,而且旧版本可能有兼容性问题,NDK想用的话,需要处理一下,不过不保证每家做出来的都一样(理论上google没统一的,可能都可能不保险..),应用包进去的话,估计要小心点。

4. 内核态代码中打印调用栈

内核看调用栈,也是比较简单的,直接在要看的地方,加入:

[html] view plain copy

  1. WARN_ON(1);

静态打印的问题:

  1. 静态打印调用栈,需要修改代码,重新编译运行
  2. 对于底层函数,或者调用次数很多的函数,会出现海量流氓log,没法真正分析了。

解决方法,改代码这个没法解决,针对流氓log,可以想一些办法:

  1. callStack的地方,条件触发,根据上下文,设置条件触发
  2. 不好以上下文设条件的,可以根据进程名/uid等设置触发条件
  3. 可以用大绝招:自己定义property设条件,可以在shell串口通过改变property值来toggle log开关。

动态方法

动态的话,其实ADB连上DDMS后,查看更方便,Java堆栈查看起来特别顺手,这里只看shell命令的几种方式:

1. Dump Java调用栈

java调用栈实际也包含了native的栈和内核栈,比较全一些,看的也更清晰。使用方式也很简单:

[html] view plain copy

  1. kill -3 <pid>

由于是虚拟机帮忙的,目前只适用于虚拟机进程(即java进程)
2. Dump native栈
    用Debuggerd很容易获取native栈信息,这个可以当采样或者分析卡住或死锁问题。

[html] view plain copy

  1. debuggerd -b <pid>

注意这个对java进程,是得不到java调用栈的,不过得到的是虚拟机执行java指令时的虚拟机调用栈,debugger 虚拟机必用。
3. 查看内核栈
    比较难,大多系统没有开放,看不到,不过调试版本可以。
    查看方法是:

[html] view plain copy

  1. cat /proc/<pid>/task/<tid>/stack

不过最新Naugot上的调用栈,看起来最新的不做demangle了:

[html] view plain copy

  1. "main" prio=5 tid=1 Native
  2. | group="main" sCount=1 dsCount=0 obj=0x748ef6b8 self=0xa638b400
  3. | sysTid=1774 nice=0 cgrp=default sched=0/0 handle=0xaa74b534
  4. | state=S schedstat=( 0 0 0 ) utm=18 stm=193 core=0 HZ=100
  5. | stack=0xbf403000-0xbf405000 stackSize=8MB
  6. | held mutexes=
  7. kernel: SyS_epoll_wait+0x23c/0x2d1
  8. kernel: SyS_epoll_pwait+0x70/0xe1
  9. kernel: sysenter_do_call+0x12/0x22
  10. native: #00 pc ffffe424  [vdso] (__kernel_vsyscall+16)
  11. native: #01 pc 000779ab  /system/lib/libc.so (__epoll_pwait+43)
  12. native: #02 pc 00020cb0  /system/lib/libc.so (epoll_pwait+112)
  13. native: #03 pc 00020d0e  /system/lib/libc.so (epoll_wait+62)
  14. native: #04 pc 00018f1b  /system/lib/libutils.so (_ZN7android6Looper9pollInnerEi+203)
  15. native: #05 pc 00018d84  /system/lib/libutils.so (_ZN7android6Looper8pollOnceEiPiS1_PPv+68)
  16. native: #06 pc 000d38c3  /system/lib/libandroid_runtime.so (_ZN7android18NativeMessageQueue8pollOnceEP7_JNIEnvP8_jobjecti+77)
  17. native: #07 pc 000d3934  /system/lib/libandroid_runtime.so (???)
  18. native: #08 pc 007b1c0c  /system/framework/x86/boot-framework.oat (Java_android_os_MessageQueue_nativePollOnce__JI+136)
  19. at android.os.MessageQueue.nativePollOnce(Native method)
  20. at android.os.MessageQueue.next(MessageQueue.java:323)
  21. at android.os.Looper.loop(Looper.java:136)
  22. at android.app.ActivityThread.main(ActivityThread.java:6119)
  23. at java.lang.reflect.Method.invoke!(Native method)
  24. at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
  25. at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

这有点蛋疼,读起来有点难受,看提交记录,是为了绕某个bug:

[html] view plain copy

  1. commit 7c903fbacfaf449fb4f7a9fa2f1a1b6ba2db5330
  2. Author: Josh Gao <[email protected]>
  3. Date:   Tue Mar 22 11:29:17 2016 -0700
  4. Don‘t demangle symbol names.
  5. Bug: http://b/27299236
  6. Change-Id: I3a698c6d93e262fd78e743c1e6e946b054b9dcd1

当然,这些动态看的调用栈,通过adb bugreport或dumpstate命令,都能得到。如果有bug的话,可以先保存一份bugreport,存下了放在后面慢慢看,然后再来解刨场景分析。

时间: 2024-08-04 01:03:54

Android各种获取代码调用栈的方法[补]的相关文章

android native HAL程序 java程序 linux kernel打印调用栈的方法

android native HAL程序 java程序 linux kernel打印调用栈的方法 关于android java打出调用栈的方法 1)方法一:refs:frameworks/base/services/java/com/android/server/ActivityManagerService.javastartProcessLocked(){Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "amProcessStart&quo

Android中使用代码截图的各种方法总结

1,基于Android SDK的截屏方法 (1)主要就是利用SDK提供的View.getDrawingCache()方法.网上已经有很多的实例了.首先创建一个android project,然后进行Layout,画一个按键(res/layout/main.xml): <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android

Linux下手动获取当前调用栈

被问到如何手动获取当前的调用栈,之前碰到过一时没记起来,现在回头整理一下. 其原理是:使用backtrace()从栈中获取当前调用各层函数调用的返回地址,backtrace_symbols()将对应地址翻译成对应的符号信息,这两个函数在execinfo.h中声明.详细用法见后面的example.这里强调几处需要注意的地方,在man里头也有说明 1,inline函数无返回地址,因此在结果中不显示 2,需要给linker指定对应的参数,才能保证有对应的符号名称信息,GNU工具链是指定-rdynami

Android中获取屏幕长宽的方法

package com.kale.screen; import android.annotation.SuppressLint; import android.app.Activity; import android.graphics.Point; import android.os.Bundle; import android.util.Log; import android.view.Display; public class MainActivity extends Activity {

Windows下获取Dump文件以及进程下各线程调用栈的方法总结(转)

1. Dump文件的用途 Dump文件, 主要用于诊断一个进程的运行状态,尤其是碰到崩溃(Crash)或者挂起(hang)不响应时,需要分析它的工作状态.  除了平时常见的attach到这个进程, 分析Dump文件就成了一个重要的手段了. 相信一些做软件维护和支持的工程师在这方面深有体会, 比如某天某时,客户说, 呀, 糟糕, 服务器进程挂掉了, 怎么回事? 然后,看看了日志文件,也没有什么可用的信息.  技术支持告诉他, 按某步骤生成一个dump文件来看看...... 2. 如何生成Dump文

URL转Drawable之 Android中获取网络图片的三种方法

转载自: http://doinone.iteye.com/blog/1074283 Android中获取网络图片是一件耗时的操作,如果直接获取有可能会出现应用程序无响应(ANR:Application Not Responding)对话框的情况.对于这种情况,一般的方法就是耗时操作用线程来实现.下面列三种获取url图片的方法: 1.直接获取:(容易:ANR,不建议) [java] view plain copy mImageView = (ImageView)this.findViewById

Android中获取网络图片的三种方法

android中获取网络图片是一件耗时的操作,如果直接获取有可能会出现应用程序无响应(ANR:Application Not Responding)对话框的情况.对于这种情况,一般的方法就是耗时操作用线程来实现.下面列三种获取url图片的方法: 1.直接获取:(容易:ANR,不建议) mImageView = (ImageView)this.findViewById(R.id.imageThreadConcept) ; Drawable drawable = loadImageFromNetwo

Android下获取FPS的几种方法

FPS(Frames Per Second)是关乎Android用户体验最为重要的指标之一,而在VR中更是如此.为了评估VR系统.VR SDK及Unity应用的性能,通常会实时获取FPS并将其显示出来. Android下获取FPS的方法有很多种,本文将介绍三种最为简单易行的方法.三种方法的共同点是都无需root,兼容性好,但又各具特色. 第一种方法,使用GameBench,它的特点是图表显示,非常直观.相对其他跑分软件,它测出的数据更为客观准确.GameBench只能监测前台应用的FPS,无法获

Android之获取本地图片并压缩方法

这两天在做项目时,做到上传图片功能一块时,碰到两个问题,一个是如何获取所选图片的路径,一个是如何压缩图片,在查了一些资料和看了别人写的后总算折腾出来了,在此记录一下. 首先既然要选择图片,我们就先要获取本地所有的图片,Android已经为我们封装好了该意图. 1 Intent intent = new Intent(Intent.ACTION_PICK, null);//从列表中选择某项并返回所有数据 2 intent.setDataAndType( 3 MediaStore.Images.Me