Android Native層函數調用堆棧打印通用方法

Android爲方便Native層打印函數的調用堆棧,專門在system/core/libutils下設計了CallStack.cpp類
如果需要打印Native的stack只需要在自己的代碼的mk文件中添加對libutils.so添加依賴,在類文件中include <utils/CallStack.h> 頭文件。

實現方法如下:

.cpp文件
#include <utils/CallStack.h>

CallStack stack("powered by gaojian");

在編譯文件添加對libutils.so的依賴,如下:

Android.mk
LOCAL_SHARED_LIBRARIES += libutils

該方案的缺點:

  1. 需要修改編譯文件,有時候依賴libutils會不成功
  2. 只能在cpp文件中使用,無法在.c文件中使用

爲解決該問題,本人百度、google研究了個遍,各種攻略都以失敗告終,自己也相當鬱悶,
難道就沒有一個簡單通用方法在c/c++文件中打印堆棧嗎?
答案是肯定的

自己去研究了下CallStack .cpp,突發靈感,只要稍微對CallStack .cpp做修改,即可搞定這個問題!!!!

上代碼:

修改system/core/libutils/CallStack.cpp代碼

diff --git a/libutils/CallStack.cpp b/libutils/CallStack.cpp
old mode 100644
new mode 100755
index bd6015e..56bcf60
--- a/libutils/CallStack.cpp
+++ b/libutils/CallStack.cpp
@@ -26,6 +26,14 @@
 
 #include <backtrace/Backtrace.h>
 
+extern "C" {
+void call_stack_fun(const char* value){
+    char buf[100];
+    memset(buf, 0, sizeof(buf));
+    snprintf(buf, sizeof(buf),"SGJ_%s",value);
+    android::CallStack mCallStack(buf);
+}
+}
 namespace android {
 
 CallStack::CallStack() {

編譯出libutils.so,重命名爲libutilscallstack.so(當然也可以不重命名,主要是怕和原so衝突)

然後在想打印trace的C或者C++方法中通過 dlopendlsym方法去調用該方法,代碼如下

--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -64,6 +64,8 @@
 #include "api2/CameraDeviceClient.h"
 #include "utils/CameraTraces.h"
 
+#include <dlfcn.h>
+
 namespace {
     const char* kPermissionServiceName = "permission";
 }; // namespace anonymous
@@ -181,6 +183,14 @@ void CameraService::onFirstRef()
 {
     ALOGI("CameraService process starting");
 
+    void * prt_stack_lib = dlopen("/system/lib/libutilscallstack.so",RTLD_LAZY);
+    ALOGE("SGJ dlopen %s:",dlerror());
+    void(*prt_stack_fun)(const char*) = (void (*)(const char *))dlsym(prt_stack_lib,"call_stack_fun");
+    if (prt_stack_fun!=NULL) {
+        prt_stack_fun("onFirstRef");
+    }
+    dlclose(prt_stack_lib);
+
     BnCameraService::onFirstRef();
 
     // Update battery life tracking if service is restarting

運行結果如下:

然後通過
addr2line -C -f -e newcdr 00026cb3
查看定位代碼。
如果在使用過程中,存在類型轉換失敗的編譯問題時,可以嘗試下:

#include <dlfcn.h>
void * prt_stack_lib = dlopen("/system/lib/libutilscallstack.so",RTLD_LAZY);
if (prt_stack_lib==NULL) ALOGE("SGJ dlopen %s:",dlerror());
void*  prt = dlsym(prt_stack_lib,"call_stack_fun");
if (prt != NULL) {
    void (*prt_stack_fun)(const char *)  = reinterpret_cast<void (*)(const char *)>(prt);
    prt_stack_fun("createBufferQueue");
}
dlclose(prt_stack_lib);

bingo!!!

分享下這個成果,如果覺得有用,麻煩幫點個贊,哈哈。。。請叫我雷鋒

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章