Android调试技巧
转自: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调试技巧的更多相关文章
- Android调试技巧之Eclipse行号和Logcat
很多初入Android的开发者可能会发现经常遇到Force Close或ANR这样的问题,一般我们通过Android系统的错误日志打印工具Logcat可以看到出错的内容,今天一起来说下如何通过 Ecl ...
- 【转】你所不知道的Android Studio调试技巧
这篇写Android studio debug技巧个人觉得写得不错,转自:http://www.jianshu.com/p/011eb88f4e0d# Android Studio目前已经成为开发An ...
- 你所不知道的Android Studio调试技巧
转载:http://www.jianshu.com/p/011eb88f4e0d Android Studio目前已经成为开发Android的主要工具,用熟了可谓相当顺手.作为开发者,调试并发现bug ...
- Android Studio 实用调试技巧
Android Studio 是个发工具,其自身带调式环境是很强大的,我们要摆脱只会使用Log打印日志的低效的方法,掌握高级调试技巧对每个Android开发者都是很必要的,废话少说,直入正题 调试方式 ...
- android studio 调试技巧(简直太好用)
android studio 调试技巧(简直太好用) 说到android studio的调试,很多人可能会说,这有什么可讲的不就是一个断点调试么,刚开始我也是这么认为的,直到我了解之后,才发现,调试原 ...
- 【转】Android Eclipse调试技巧
原文地址:https://www.cnblogs.com/tianchunming/p/5423942.html Android Eclipse调试技巧 在Android 应用程序开发中我们经常需 ...
- Android Eclipse调试技巧
在Android 应用程序开发中我们经常需要调试程序,可以说调试在我们的日常开发中起着十分重要的作用,下面就以Elipse开发环境总结一下调试技巧. 一.Debug 断点调试 所谓断点调试就是指在程序 ...
- Android开发--环境搭建和调试技巧
一:环境搭建 (1)我使用的环境是:window8+Java SDK+Eclipse+Android SDK+ADT 安装步骤:Java SDK-->Eclipse--->ADT---&g ...
- (转载) Android Studio你不知道的调试技巧
Android Studio你不知道的调试技巧 标签: android studio 2015-12-29 16:05 2514人阅读 评论(0) 收藏 举报 分类: android(74) ...
随机推荐
- phd文献阅读日志-博一下学期
博一下学期: 1.week1,2018.2.26 2006-Extreme learning machine: theory and applications 期刊来源:Huang G B, Zhu ...
- Linux服务器 java生成的图片验证码乱码问题
问题:如图所示项目中生成的图形验证码不能正常显示出需要的字体 原因: linux下没有对应的字体 查找项目中使用到系统字体的地方,如下: 解决: 1. 在本地 路径 C:\Windows\Fonts ...
- iOS: crush when save Core Data
如果一个页面拥有一个 NSFetchedResultsController 的引用,那么在这个界面将要结束时,一定要 remove 它的 observer - (void)dealloc { //.. ...
- JS性能细节学习初步总结
1,声明变量要赋初值2,尽量避免声明全局变量,可以减少与系统的重名3,当编写大量js代码时,难免会遇到命名冲突,这是可以通过模拟命名空间方式 来避免冲突4,尽量避免使用全局变量,搜索全局变量是 ...
- Oracle高级查询之CONNECT BY
为了方便大家学习和测试,所有的例子都是在Oracle自带用户Scott下建立的. Oracle中的select语句可以用start with ... connect by prior ...子句实现递 ...
- VBscript实现开机自动启动,自动复制原件后启动
set fso = createobject("scripting.filesystemobject") set ws = createobject("wscript.s ...
- OpenGL中的光照技术(翻译)
Lighting:https://www.evl.uic.edu/julian/cs488/2005-11-03/index.html 光照 OpenGL中的光照(Linghting)是很重要的,为什 ...
- 8 -- 深入使用Spring -- 7... Spring 整合 Struts 2
8.7 Spring 整合 Struts2 8.7.1 启动Spring 容器 8.7.2 MVC框架与Spring整合的思考 8.7.3 让Spring管理控制器 8.7.4 使用自动装配
- Centos6.3 下使用 Tomcat-6.0.43 非root用户 部署 生产环境 端口转发方式
一.安装JDK环境 方法一. 官方下载链接 http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260 ...
- css背景图等比例缩放,盒子随背景图等比例缩放
很多时候我们给网站了一个大banner,但是随着屏幕的变化,背景会变形,我们知道background-size可以实现背景图等比例缩放,但是,我们想让下面的盒子根据缩放后背景图的高度,也能自动向上挤. ...