Android 系统常用 debug 方法

465 阅读2分钟

一、打印 log

1.1 Framework Java

导入包:

import android.util.Log

定义,以 Log.v 为例:

/**
 * Send a {@link #VERBOSE} log message.
 * @param tag Used to identify the source of a log message.  It usually identifies
 *        the class or activity where the log call occurs.
 * @param msg The message you would like logged.
 * @return A positive value if the message was loggable (see {@link #isLoggable}).
 */
public static int v(@Nullable String tag, @NonNull String msg) {
    return println_native(LOG_ID_MAIN, VERBOSE, tag, msg);
}

文件路径:/frameworks/base/core/java/android/util/Log.java。

1.2 Framework Native

导入头文件:

#include <log/log.h>

定义,以 ALOGV 为例:

/*
 * Simplified macro to send a verbose log message using the current LOG_TAG.
 */
#ifndef ALOGV
#define __ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
#if LOG_NDEBUG
#define ALOGV(...)                   \
  do {                               \
    __FAKE_USE_VA_ARGS(__VA_ARGS__); \
    if (false) {                     \
      __ALOGV(__VA_ARGS__);          \
    }                                \
  } while (false)
#else
#define ALOGV(...) __ALOGV(__VA_ARGS__)
#endif
#endif

文件路径:/system/logging/liblog/*。

1.3 Kernel

通过 printk 函数。

二、打印 trace

2.1 Framework Java

导入包:

import android.os.Trace;

常用的方法有 beginSectionendSection 等。源码示例:

// /frameworks/base/core/java/android/view/View.java
public void layout(int l, int t, int r, int b) {
    if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {
        if (isTraversalTracingEnabled()) {
            Trace.beginSection(mTracingStrings.onMeasureBeforeLayout);
        }
        onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
        if (isTraversalTracingEnabled()) {
            Trace.endSection();
        }
        mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
    }
    
    ...
}

文件路径:/frameworks/base/core/java/android/os/Trace.java。

2.2 Framework Native

2.2.1 Trace.h

导入头文件:

#include <utils/Trace.h>

常用的有 ATRACE_CALLATRACE_NAMEATRACE_INT 等。

文件路径:/system/core/libutils/include/utils/Trace.h 和 /system/core/libcutils/include/cutils/trace.h。

2.2.2 TraceUtils.h

导入头文件:

#include <gui/TraceUtils.h>

gui 下的 trace 工具主要提供了 ATRACE_FORMAT 函数,可以按照 printf 格式打印 trace。

文件路径:/frameworks/native/libs/gui/include/gui/TraceUtils.h。

三、打印堆栈

3.1 Framework Java

通过异常打印堆栈:

new Exception.printsStackTrace();

3.2 Framework Native

导入头文件:

#include <utils/callStack.h>

在 Android.bp 中添加库 libutilscallstack(大部分模块都已经包含):

shared_libs:[
    "libutilscallstack",
]

用法:

android::callStack cs("TAG");

3.3 Kernel

3.3.1 dump_stack 函数

导入头文件:

#include <asm/ptrace.h>

用法:

dump_stack();

3.3.2 WARN_ON 函数

导入头文件:

#include<linux/kernel.h>

用法:

WARN_ON(condition);

四、常用系统接口

AOSP system 目录下是 Android 的底层库,多翻看这一部分代码可以发现很多方便的接口,这里当个个人记录。

4.1 获取系统属性

  • 在 framework Java 层可以使用 SystemProperties 类中的方法。
  • 在 framework native 层可以使用 property_get 相关函数,或者 base::GetProperty 相关函数。

4.2 读取文件

使用 ReadFdToString 可以将文件读取到字符串中。

五、解析堆栈

addr2line

使用 addr2line 工具可以解析 C/C++ 堆栈。addr2line 工具可以在 Android NDK 中可以找到,其路径取决于 NDK 版本,也可以使用构建时生成的 addr2line 可执行文件,其路径取决于构建时使用的编译配置。

我一般使用如下格式的命令:

llvm-addr2line -c -i -e $symbol -f $offset

oatdump

用于解析虚拟机生成的二进制文件,包括 odex/odx/ko 等文件。目前用得不多,后续可能会补充。