在Android hal层堆栈打印,可使用android::CallStack实现。
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
- 将上述两个文件加入目标源码的Android.mk或者Android.bp中,同时添加"libcutils"、 "libutils"、"libutilscallstack"动态库。
cc_binary {
name: "my_test_bin",
...
srcs: [
"dumptest.cpp",
],
...
shared_libs: [
"libcutils",
"libutils",
"libutilscallstack",
],
}
- 在需要打印堆栈的地方调用接口函数dumping_callstack()。
void dumping_callstack(void)
{
android::CallStack cs("dumptest");
}
- 在logcat中过滤dumptest即可获得堆栈
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使用方法
- 将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。
-
将libdumpstack.so拷贝到目标板卡对应目录system/lib (32bit)或者system/lib64 (64bit),修改文件权限为664。
-
在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)
......