android端点调试方法,Android 调试方法

Native

1、C/CPP

#include

ALOGD("%s %d\n", __FUNCTION__, __LINE__)

方法级别为:

VERBOSE ALOGV();

DEBUG ALOGD();

INFO ALOGI();

WARN ALOGW();

ERROR ALOGE();

2、CPP Trace 打印方法

#include

android::CallStack stack(("Debug"));

3、C语言Trace打印方法

3.1 使用C封装调用callstack so

callstacktrace.cpp

#include

extern "C" void dumpstacktrace(void);

void dumpstacktrace(void)

{

android::CallStack cs("Debug");

}

callstacktrace.h

void dumpstacktrace(void);

将callstacktrace.cpp callstacktrace.h编译成 libcallstacktrace.so 后,本地Native C程序include callstacktrace.h后调用动态库的方法来调用dumpstacktrace()

3.2 自定义函数调用 unwind

通过android工具类CallStack实现中使用的unwind调用及符号解析函数来处理,

这里需要注意的是,为解决链接问题,最好使用dlopen方式,查找需要用到的接口再直接调用

这个方法没有确认过 参考自 https://blog.csdn.net/freshui/article/details/9456889

#include "backtrace.h" /* 引入头文件 libcorkscrew-ndk/master/corkscrew/backtrace.h */

#define MAX_DEPTH 31

#define MAX_BACKTRACE_LINE_LENGTH 800

#define PATH "/system/lib/libcorkscrew.so"

typedef ssize_t (*unwindFn)(backtrace_frame_t*, size_t, size_t);

typedef void (*unwindSymbFn)(const backtrace_frame_t*, size_t, backtrace_symbol_t*);

typedef void (*unwindSymbFreeFn)(backtrace_symbol_t*, size_t);

static void *gHandle = NULL;

static int getCallStack(void){

ssize_t i = 0;

ssize_t result = 0;

ssize_t count;

backtrace_frame_t mStack[MAX_DEPTH];

backtrace_symbol_t symbols[MAX_DEPTH];

unwindFn unwind_backtrace = NULL;

unwindSymbFn get_backtrace_symbols = NULL;

unwindSymbFreeFn free_backtrace_symbols = NULL;

// open the so.

if(gHandle == NULL) gHandle = dlopen(PATH, RTLD_NOW);

// get the interface for unwind and symbol analyse

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! cannot get unwind info: handle:%p %p %p %p",

gHandle, unwind_backtrace, get_backtrace_symbols, free_backtrace_symbols );

return result;

}

count= unwind_backtrace(mStack, 1, MAX_DEPTH);

get_backtrace_symbols(mStack, count, symbols);

for (i = 0; i < count; i++) {

char line[MAX_BACKTRACE_LINE_LENGTH];

const char* mapName = symbols[i].map_name ? symbols[i].map_name : "";

const char* symbolName =symbols[i].demangled_name ? symbols[i].demangled_name : symbols[i].symbol_name;

size_t fieldWidth = (MAX_BACKTRACE_LINE_LENGTH - 80) / 2;

if (symbolName) {

uint32_t pc_offset = symbols[i].relative_pc - symbols[i].relative_symbol_addr;

if (pc_offset) {

snprintf(line, MAX_BACKTRACE_LINE_LENGTH, "#%02d pc %08x %.*s (%.*s+%u)",

i, symbols[i].relative_pc, fieldWidth, mapName,

fieldWidth, symbolName, pc_offset);

} else {

snprintf(line, MAX_BACKTRACE_LINE_LENGTH, "#%02d pc %08x %.*s (%.*s)",

i, symbols[i].relative_pc, fieldWidth, mapName,

fieldWidth, symbolName);

}

} else {

snprintf(line, MAX_BACKTRACE_LINE_LENGTH, "#%02d pc %08x %.*s",

i, symbols[i].relative_pc, fieldWidth, mapName);

}

ALOGD("%s", line);

}

free_backtrace_symbols(symbols, count);

return result;

}

Framework

1、Slog

import android.util.Slog;

Slog.d(TAG, "Debug" );

方法级别为:

VERBOSE Slog.v();

DEBUG Slog.d();

INFO Slog.i();

WARN Slog.w();

ERROR Slog.e();

2、Log

import android.util.Log;

Log.d(TAG, "Debug.." );

方法级别为:

VERBOSE Log.v();

DEBUG Log.d();

INFO Log.i();

WARN Log.w();

ERROR Log.e();

3、Trace 打印方法

Thread.currentThread().dumpStack(); //方法1

Log.d(TAG,"Debug", new RuntimeException("Debug")); //方法2

new RuntimeException("Debug").printStackTrace(); //方法3

Kernel

常规打印方法

printk("Debug...");

pr_info("Debug...");

1、Trace 打印方法

WARN_ON(1);

2、动态打印方法

Kernel def_config中需要打开以下两个宏

CONFIG_DEBUG_FS=y

CONFIG_DYNAMIC_DEBUG=y

Demo:

:/ # echo "file hub.c +p" > /sys/kernel/debug/dynamic_debug/control

:/ # echo "8 8 8 8" > /proc/sys/kernel/printk

接入U盘的操作的时候可以看到如下打印

[ 694.261724@0] hub 1-3:1.0: state 7 ports 4 chg 0000 evt 0010

[ 694.262408@0] hub 1-3:1.0: port 4, status 0101, change 0001, 12 Mb/s

动态调试的主要功能是允许动态的打开或关闭内核代码的各种提示信息,即pr_debug()/dev_debug() 之类的函数可以动态的在代码里所使用

动态调试有很多有用的特性:

* 简洁的查询语言允许打开或关闭调试的状态通过匹配以下的任意组合:

- 资源文件名

- 函数名

- 行号 (包括一定范围的行号)

- 模块名

- 格式化字符串

* 提供一个debugfs 控制文件: /dynamic_debug/control 这个文件被读取用来显示已完成的调试信息列表, 通过 cat /dynamic_debug/control 命令可以看对应的配置

跨进程打印堆栈的方式

类别

函数式

命令式

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

堆栈分析方法

A、addr2line

32bit

arm-linux-androideabi-addr2line -Cfe libsurfaceflinger.so 000000000003fc74

64bit

aarch64-linux-android-addr2line -Cfe libsurfaceflinger.so 000000000003fc74

B、GDB

使用GDB attach 对应Symbols 后使用list 命令

list *000000000003fc74

BugReport

可以使用adb bugreport命令获取系统运行的所有log信息。命令如下:

adb bugreport > /data/bugreport_out.txt

所有log信息输出到bugreport_out.txt文件中。

bugreport 有工具可以做UI可视化阅读

1、google的bettery historian开源了,开源项目的地址:

https://github.com/google/battery-historian

DumpSys

dumpsys 是一种在 Android 设备上运行的工具,可提供有关系统服务的信息。可以使用 Android 调试桥 (ADB) 从命令行调用 dumpsys,获取在连接的设备上运行的所有系统服务的诊断输出。另外前面的bugreport 命令在抓取信息的时候会把dumpsys信息也获取,这个很贴心

关于dumpsys 要写起来也可以写一篇文章了,建议参考谷歌的文章 dumpsys

调试实例

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值