Android hal层堆栈打印

2,219 阅读4分钟

在Android hal层堆栈打印,可使用android::CallStack实现。

1.在目标源码中直接调用堆栈打印函数接口

  1. 在目标源码中包含如下cpp与h文件。
// 堆栈打印接口cpp文件,dumptest.cpp
#include <utils/CallStack.h>
#include "dumptest.h"

struct export_vtable exports = {
    dumping_callstack,
};

void dumping_callstack(void)
{
    android::CallStack cs("dumptest");
}
//dumptest.h
#ifndef __DUMPTEST_H__
#define __DUMPTEST_H__

#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif /* __cplusplus */

void dumping_callstack(void);

struct export_vtable {
    void (*callstack)(void);
};

#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

#endif
  1. 将上述两个文件加入目标源码的Android.mk或者Android.bp中,同时添加"libcutils"、 "libutils"、"libutilscallstack"动态库。
cc_binary {
    name: "my_test_bin",
    ...
    srcs: [
        "dumptest.cpp",
    ],
    ...
    shared_libs: [
        "libcutils",
        "libutils",
        "libutilscallstack",
    ],
}
  1. 在需要打印堆栈的地方调用接口函数dumping_callstack()。
void dumping_callstack(void)
{
    android::CallStack cs("dumptest");
}
  1. 在logcat中过滤dumptest即可获得堆栈

1642127756(1).jpg

2.将dumptest.cpp编译成so供其他模块使用

2.1使用场景

在hal层某些原生库中,不能直接调用第一种方法中的接口进行堆栈打印。例如bionic中的libc库,直接使用则编译会报错。因为cc_library_static表示编译成 Native 静态库。添加编译"libcutils"、 "libutils"、"libutilscallstack"动态库会编译出错。不过,可将dumptest.cpp编译成so,然后动态open进行使用。

cc_library_static {
    defaults: ["libc_defaults"],
    srcs: [
        ...
        "bionic/system_property_api.cpp",
        "bionic/system_property_set.cpp",
        ...
    ],
    //添加动态库
    shared_libs: [
        "libcutils",
        "libutils",
        "libutilscallstack",
    ],
    name: "libc_bionic_ndk",
}

mmm bionic/libc/后,编译报错如下:

error: bionic/libc/Android.bp:992:1: dependency "libcutils" of "libc_bionic_ndk" missing variant:
 os:android, image:ramdisk, arch:arm_armv8-2a_cortex-a55, sdk:, link:shared
 
error: bionic/libc/Android.bp:992:1: dependency "libutils" of "libc_bionic_ndk" missing variant:
 os:android, image:ramdisk, arch:arm_armv8-2a_cortex-a55, sdk:, link:shared
 
error: bionic/libc/Android.bp:992:1: dependency "libutilscallstack" of "libc_bionic_ndk" missing variant:
  os:android, image:ramdisk, arch:arm_armv8-2a_cortex-a55, sdk:, link:shared
2.2使用方法
  1. 将dumptest.cpp与dumptest.h放入文件夹dumpstack中,然后编写Android.bp或者Android.mk进行编译,如下是Android.bp的示例。
cc_library_shared{
    name: "libdumpstack",
    srcs: [
        "dumpstack/dumptest.cpp",
    ],
    cflags: [
        "-Wall",
        "-Werror",
        "-Wno-error=date-time",
    ],
    include_dirs: [
        "dumpstack",
    ],
    shared_libs: [
        "libcutils",
        "libutils",
        "libutilscallstack",
    ],
}

编译后可在out目录system/lib (32bit)或者system/lib64 (64bit)中找到产物libdumpstack.so。

  1. 将libdumpstack.so拷贝到目标板卡对应目录system/lib (32bit)或者system/lib64 (64bit),修改文件权限为664。

  2. 在bionic中的libc库源文件中进行使用。

2.3使用示例

android/bionic/libc/bionic/system_property_set.cpp__system_property_set(const char* key, const char* value)中添加堆栈打印。

#include <stdio.h>
#include <dlfcn.h>

struct export_vtable {
    void (*callstack)(void);
};

static void check_and_callcheck(const char *key_name)
{
    void* dlhandle = NULL;
    struct export_vtable* imports = NULL;
    const char DUMPTEST_SO_NAME[] = "/system/lib/libdumpstack.so";

    async_safe_format_log(ANDROID_LOG_WARN, "libc", "%s key: %s is changing!\n", __func__, key_name);
    dlhandle = dlopen(DUMPTEST_SO_NAME, RTLD_NOW);
    if (!dlhandle) {
        async_safe_format_log(ANDROID_LOG_ERROR, "libc", "%s dlopen error\n", __func__);
        return ;
    }

    imports = static_cast<struct export_vtable *>(dlsym(dlhandle, "exports"));
    if (imports) {
        async_safe_format_log(ANDROID_LOG_ERROR, "libc", "%s dlsym error\n", __func__);
        imports->callstack();
    }
    dlclose(dlhandle);
}

__BIONIC_WEAK_FOR_NATIVE_BRIDGE
int __system_property_set(const char* key, const char* value) {
    ...
    check_and_callcheck(key);
    ...
}

logcat | grep dumpstack打印结果:

01-13 20:38:16.120348  1177  1375 D dumpstack: #00 pc 000013fd  /system/lib/libdumpstack.so (dumping_callstack+36)
01-13 20:38:16.121164  1177  1375 D dumpstack: #01 pc 0004460f  /apex/com.android.runtime/lib/bionic/libc.so (__system_property_set+146)
01-13 20:38:16.121259  1177  1375 D dumpstack: #02 pc 00066735  /system/lib/libandroid_runtime.so (android::(anonymous namespace)::SystemProperties_set(_JNIEnv*, _jobject*, _jstring*, _jstring*)+144)
01-13 20:38:16.121289  1177  1375 D dumpstack: #03 pc 001f6283  /system/framework/arm/boot-framework.oat (art_jni_trampoline+130)
01-13 20:38:16.121313  1177  1375 D dumpstack: #04 pc 000d39d5  /apex/com.android.art/lib/libart.so (art_quick_invoke_stub_internal+68)
01-13 20:38:16.121336  1177  1375 D dumpstack: #05 pc 004eada5  /apex/com.android.art/lib/libart.so (art_quick_invoke_static_stub+276)
01-13 20:38:16.121359  1177  1375 D dumpstack: #06 pc 0012bd3f  /apex/com.android.art/lib/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+166)
01-13 20:38:16.121392  1177  1375 D dumpstack: #07 pc 0023f1ef  /apex/com.android.art/lib/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+254)
01-13 20:38:16.121449  1177  1375 D dumpstack: #08 pc 00236eaf  /apex/com.android.art/lib/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+738)
01-13 20:38:16.121473  1177  1375 D dumpstack: #09 pc 004dec37  /apex/com.android.art/lib/libart.so (MterpInvokeStatic+490)
01-13 20:38:16.121505  1177  1375 D dumpstack: #10 pc 000ce594  /apex/com.android.art/lib/libart.so (mterp_op_invoke_static+20)
01-13 20:38:16.121528  1177  1375 D dumpstack: #11 pc 0039ed98  /system/framework/framework.jar (offset 0x855000) (android.os.SystemProperties.set+120)
01-13 20:38:16.121551  1177  1375 D dumpstack: #12 pc 004dee95  /apex/com.android.art/lib/libart.so (MterpInvokeStatic+1096)
01-13 20:38:16.121573  1177  1375 D dumpstack: #13 pc 000ce594  /apex/com.android.art/lib/libart.so (mterp_op_invoke_static+20)
......