转自:http://gityuan.com/2017/07/11/android_debug/

一. 获取Trace

调用栈信息(Trace)是分析异常经常使用的,这里简单划分两类情况:

  • 当前线程Trace: 当前执行流所在线程的调用栈信息;
  • 目标进程Trace:可获取目标进程的调用栈,用于动态调试;

1.1 当前线程Trace

1) Java层

Thread.currentThread().dumpStack();   //方法1
Log.d(TAG,"Gityuan", new RuntimeException("Gityuan")); //方法2
new RuntimeException("Gityuan").printStackTrace(); //方法3

2) Native层

#include <utils/CallStack.h>
android::CallStack stack(("Gityuan"));

1.2 目标进程Trace

1) Java层

adb shell kill -3 [pid]     //方法1
Process.sendSignal(pid, Process.SIGNAL_QUIT) //方法2

生成trace文件保存在文件data/anr/traces.txt

2) Native层

adb shell debuggerd -b [tid] //方法1
Debug.dumpNativeBacktraceToFile(pid, tracesPath) //方法2

前两条命令输出内容相同:

  • 命令1输出到控制台
  • 命令2输出到目标文件

对于debuggerd命令,若不带参数则输出tombstones文件,保存到目录/data/tombstones

3) Kernel层

adb shell cat /proc/[tid]/stack  //方法1
WatchDog.dumpKernelStackTraces() //方法2

其中dumpKernelStackTraces()只能用于打印当前进程的kernel线程

1.3 小节

以下分别列举输出Java, Native, Kernel的调用栈方式:

类别 函数式 命令式
Java Process.sendSignal(pid, Process.SIGNAL_QUIT) kill -3 [pid]
Native Debug.dumpNativeBacktraceToFile(pid, tracesPath) debuggerd -b [pid]
Kernel WD.dumpKernelStackTraces() cat /proc/[tid]/stack

分析异常时往往需要关注的重要目录:

/data/anr/traces.txt
/data/tombstones/tombstone_X
/data/system/dropbox/

二. 时间调试

为了定位耗时过程,有时需要在关注点添加相应的systrace,而systrace可跟踪系统cpu,io以及各个子系统运行状态等信息,对于kernel是利用Linux的ftrace功能。当然也可以直接在方法前后加时间戳,输出log的方式来分析。

2.1 新增systrace

1) App

import android.os.Trace;
void foo() {
Trace.beginSection("app:foo");
...
Trace.endSection();
}

2) Java Framework

import android.os.Trace;
void foo() {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "fw:foo");
...
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}

3) Native Framework

#define ATRACE_TAG ATRACE_TAG_GITYUAN
#include <utils/Trace.h> // used for C++
#include <cutils/trace.h> // used for C
void foo() {
ATRACE_CALL();
...
}

或者

#define ATRACE_TAG ATRACE_TAG_GITYUAN
#include <utils/Trace.h> // used for C++
#include <cutils/trace.h> // used for C
void foo() {
ATRACE_BEGIN();
...
ATRACE_END();
}

2.2 打印时间戳

1) Java

import android.util.Log;
void foo(){
long startTime = System.currentTimeMillis();
...
long spendTime = System.currentTimeMillis() - startTime;
Log.i(TAG,"took " + spendTime + “ ms.”);
}

2) C/C++

#include <stdio.h>
#include <sys/time.h>
void foo() {
struct timeval time;
gettimeofday(&time, NULL); //精度us
printf("took %lld ms.\n", time.tv_sec * 1000 + time.tv_usec /1000);
}

2.3 kernel log

有时候Kernel log的输出是由级别限制,可通过如下命令查看:

adb shell cat /proc/sys/kernel/printk
4 4 1 7

参数解读:

  • 控制台日志级别:优先级高于该值的消息将被打印至控制台。
  • 缺省的消息日志级别:将用该值来打印没有优先级的消息。
  • 最低的控制台日志级别:控制台日志级别可能被设置的最小值。
  • 缺省的控制台日志级别:控制台日志级别的缺省值

日志级别:

级别 说明
KERN_EMERG 0 致命错误
KERN_ALERT 1 报告消息
KERN_CRIT 2 严重异常
KERN_ERR 3 出错
KERN_WARNING 4 警告
KERN_NOTICE 5 通知
KERN_INFO 6 常规
KERN_DEBUG 7 调试

Log相关命令

  • dmesg 或 cat /proc/kmsg
  • logcat -L 或 cat /proc/last_kmsg
  • logcat -b events -b system

三. addr2line

addr2line功能是将函数地址解析为函数名。分析过Native Crash,那么对addr2line一定不会陌生。 addr2line命令参数:

Usage: addr2line [option(s)] [addr(s)]
The options are:
@<file> Read options from <file>
-a --addresses Show addresses
-b --target=<bfdname> Set the binary file format
-e --exe=<executable> Set the input file name (default is a.out)
-i --inlines Unwind inlined functions
-j --section=<name> Read section-relative offsets instead of addresses
-p --pretty-print Make the output easier to read for humans
-s --basenames Strip directory names
-f --functions Show function names
-C --demangle[=style] Demangle function names
-h --help Display this information
-v --version Display the program's version

3.1 Native地址转换

Step 1: 获取symbols表

先获取对应版本的symbols,即可找到对应的so库。(最好是对应版本addr2line,可确保完全匹配)

Step 2: 执行addr2line命令

// 64位
cd prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin
./aarch64-linux-android-addr2line -f -C -e libxxx.so <addr1> //32位
cd /prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin
./arm-linux-androideabi-addr2line -f -C -e libxxx.so <addr1>

另外,有兴趣可以研究下development/scripts/stack,地址批量转换工具。

3.2 kernel地址转换

addr2line也适用于调试分析Linux Kernel的问题。例如,查询如下命令所对应的代码行号

[<0000000000000000>] binder_thread_read+0x2a0/0x324

Step 1: 获取符号地址

通过命令arm-eabi-nm从vmlinux找到目标方法的符号地址,其中nm和vmlinux所在目录:

  • arm-eabi-nm位于目录prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/
  • vmlinux位于目录out/target/product/xxx/obj/KERNEL_OBJ/

执行如下命令:(需要带上绝对目录)

arm-eabi-nm  vmlinux |grep binder_thread_read

则输出结果: c02b2f28 T binder_thread_read,可知binder_thread_read的符号地址为c02b2f28, 其偏移量为0x2a0,则计算后的目标符号地址= c02b2f28 + 2a0,然后再采用addr2line转换得到方法所对应的行数

Step 2: 执行addr2line命令

./aarch64-linux-android-addr2line -f -C -e vmlinux [目标地址]

注意:对于kernel调用栈翻译过程都是通过vmlinux来获取的

Android调试技巧的更多相关文章

  1. Android调试技巧之Eclipse行号和Logcat

    很多初入Android的开发者可能会发现经常遇到Force Close或ANR这样的问题,一般我们通过Android系统的错误日志打印工具Logcat可以看到出错的内容,今天一起来说下如何通过 Ecl ...

  2. 【转】你所不知道的Android Studio调试技巧

    这篇写Android studio debug技巧个人觉得写得不错,转自:http://www.jianshu.com/p/011eb88f4e0d# Android Studio目前已经成为开发An ...

  3. 你所不知道的Android Studio调试技巧

    转载:http://www.jianshu.com/p/011eb88f4e0d Android Studio目前已经成为开发Android的主要工具,用熟了可谓相当顺手.作为开发者,调试并发现bug ...

  4. Android Studio 实用调试技巧

    Android Studio 是个发工具,其自身带调式环境是很强大的,我们要摆脱只会使用Log打印日志的低效的方法,掌握高级调试技巧对每个Android开发者都是很必要的,废话少说,直入正题 调试方式 ...

  5. android studio 调试技巧(简直太好用)

    android studio 调试技巧(简直太好用) 说到android studio的调试,很多人可能会说,这有什么可讲的不就是一个断点调试么,刚开始我也是这么认为的,直到我了解之后,才发现,调试原 ...

  6. 【转】Android Eclipse调试技巧

    原文地址:https://www.cnblogs.com/tianchunming/p/5423942.html Android Eclipse调试技巧   在Android 应用程序开发中我们经常需 ...

  7. Android Eclipse调试技巧

    在Android 应用程序开发中我们经常需要调试程序,可以说调试在我们的日常开发中起着十分重要的作用,下面就以Elipse开发环境总结一下调试技巧. 一.Debug 断点调试 所谓断点调试就是指在程序 ...

  8. Android开发--环境搭建和调试技巧

    一:环境搭建 (1)我使用的环境是:window8+Java SDK+Eclipse+Android SDK+ADT 安装步骤:Java SDK-->Eclipse--->ADT---&g ...

  9. (转载) Android Studio你不知道的调试技巧

    Android Studio你不知道的调试技巧 标签: android studio 2015-12-29 16:05 2514人阅读 评论(0) 收藏 举报  分类: android(74)    ...

随机推荐

  1. 共享锁(S锁)和排它锁(X锁)

    释义 共享锁:(读取)操作创建的锁.其他用户可以并发读取数据,但任何事物都不能获取数据上的排它锁,直到已释放所有共享锁. 共享锁(S锁)又称为读锁,若事务T对数据对象A加上S锁,则事务T只能读A:其他 ...

  2. List&Map&Set的操作和遍历

    Java的三大集合即:Set.List.Map. Set:代表无序.不可重复的集合,常用的有HashSet(哈希表实现).TreeSet(红黑树实现): List:代表有序.可以重复的集合,比较常用的 ...

  3. Yii2 session的使用方法(3)

    Flash数据是一种特别的session数据,它一旦在某个请求中设置后, 只会在下次请求中有效,然后该数据就会自动被删除. 常用于实现只需显示给终端用户一次的信息, 如用户提交一个表单后显示确认信息. ...

  4. fedora26在编译s3c2440内核时make menuconfig *** Unable to find the ncurses libraries

    [root@fedora-26 linux-2.6.32.2]# make menuconfig *** Unable to find the ncurses libraries or the *** ...

  5. 软件设计模式之模板方法模式(JAVA)

    什么是模板方法模式? 定义一个操作中算法的骨架,而将这些步骤延迟到子类中,模板方法使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤. 好抽象的概念啊,文绉绉的东西就是不讨人喜欢,下面我 ...

  6. 关于微博开放平台Oauth2.0接入网站应用

    关于什么是微博开放平台及微博开放平台能做什么,咱就不做搜索引擎的搬运工了 这里直接给个链接介绍:微博开放平台 本文只是抛砖引玉,讲讲微博开放平台的基本用法,适合没接触过开放平台的朋友入门学习,老鸟就略 ...

  7. The difference between the request time and the current time is too large.阿里云oss上传图片报错

    The difference between the request time and the current time is too large. 阿里云oss上传图片的时候报错如上, 解决办法,把 ...

  8. c# 开发window服务

    http://jingyan.baidu.com/article/fa4125acb71a8628ac709226.html 安装 cmd 输入 InstallUtil.exe E:\TestApp\ ...

  9. JQ 使用toggle实现DIV的隐藏和显示

    $('.submenuA').toggle( function () { $(this).next('div').show(); }, function () { $(this).next('div' ...

  10. SpringMVC -- 梗概--源码--壹--跳转

    1.配置web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app version=&qu ...