前言
Native 崩溃的捕获, 一直是一个比较令人头疼的问题, 即使是开发阶段的 Native 崩溃也是非常的难以定位, 这里的解决方案是使用 google 的 Breakpad
一. 捕获 Native 异常
想要捕获 Native 异常, 我们需要编译 google 提供的 breakpad 库, 这个库中有 android 运行时库 liblog.so 的依赖, 因此在 Android Studio 中直接编译是最好的选择
一) 编译动态库
将 src 中的源码拷贝到 AS 工程目录下, 其 CMakeLists 的编写方式如下
cmake_minimum_required(VERSION 3.4.1)
# 添加 cmake 参数
set(ENABLE_INPROCESS ON)
set(ENABLE_OUTOFPROCESS ON)
set(ENABLE_LIBCORKSCREW ON)
set(ENABLE_LIBUNWIND ON)
set(ENABLE_LIBUNWINDSTACK ON)
set(ENABLE_CXXABI ON)
set(ENABLE_STACKSCAN ON)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=implicit-function-declaration")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ")
if (${ENABLE_INPROCESS})
add_definitions(-DENABLE_INPROCESS)
endif ()
if (${ENABLE_OUTOFPROCESS})
add_definitions(-DENABLE_OUTOFPROCESS)
endif ()
# 添加使用的头文件
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/common/android/include
)
# 需要编译的文件列表
file(
GLOB
BREAKPAD_SOURCES_LIST
${CMAKE_CURRENT_SOURCE_DIR}/client/linux/crash_generation/crash_generation_client.cc
${CMAKE_CURRENT_SOURCE_DIR}/client/linux/dump_writer_common/thread_info.cc
${CMAKE_CURRENT_SOURCE_DIR}/client/linux/dump_writer_common/ucontext_reader.cc
${CMAKE_CURRENT_SOURCE_DIR}/client/linux/handler/exception_handler.cc
${CMAKE_CURRENT_SOURCE_DIR}/client/linux/handler/minidump_descriptor.cc
${CMAKE_CURRENT_SOURCE_DIR}/client/linux/log/log.cc
${CMAKE_CURRENT_SOURCE_DIR}/client/linux/microdump_writer/microdump_writer.cc
${CMAKE_CURRENT_SOURCE_DIR}/client/linux/minidump_writer/linux_dumper.cc
${CMAKE_CURRENT_SOURCE_DIR}/client/linux/minidump_writer/linux_ptrace_dumper.cc
${CMAKE_CURRENT_SOURCE_DIR}/client/linux/minidump_writer/minidump_writer.cc
${CMAKE_CURRENT_SOURCE_DIR}/client/minidump_file_writer.cc
${CMAKE_CURRENT_SOURCE_DIR}/common/convert_UTF.c
${CMAKE_CURRENT_SOURCE_DIR}/common/md5.cc
${CMAKE_CURRENT_SOURCE_DIR}/common/string_conversion.cc
${CMAKE_CURRENT_SOURCE_DIR}/common/linux/elfutils.cc
${CMAKE_CURRENT_SOURCE_DIR}/common/linux/file_id.cc
${CMAKE_CURRENT_SOURCE_DIR}/common/linux/guid_creator.cc
${CMAKE_CURRENT_SOURCE_DIR}/common/linux/linux_libc_support.cc
${CMAKE_CURRENT_SOURCE_DIR}/common/linux/memory_mapped_file.cc
${CMAKE_CURRENT_SOURCE_DIR}/common/linux/safe_readlink.cc
)
# 汇编文件列表
file(
GLOB
BREAKPAD_ASM_SOURCE_LIST
${CMAKE_CURRENT_SOURCE_DIR}/common/android/breakpad_getcontext.S
)
set_source_files_properties(${BREAKPAD_ASM_SOURCE_LIST} PROPERTIES LANGUAGE C)
# 生成 libbreakpad.so 库
add_library(
breakpad
SHARED
${BREAKPAD_SOURCES_LIST}
${BREAKPAD_ASM_SOURCE_LIST}
)
# 为 breakpad 添加链接库
target_link_libraries(
breakpad
log
)
好的, 如此一来, 我们便可以获得 libbreakpad.so 动态库, 就可以利用它愉快的进行 bug 捕获了
native crash 捕获
#include <stdio.h>
#include <jni.h>
#include <android/log.h>
#include "client/linux/handler/exception_handler.h"
#include "client/linux/handler/minidump_descriptor.h"
#define LOG_TAG "Native-Crash"
#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
bool DumpCallback(const google_breakpad::MinidumpDescriptor &descriptor,
void *context,
bool succeeded) {
ALOGE("===============Native-Cash================");
ALOGE("Dump path: %s\n", descriptor.path());
return succeeded;
}
extern "C"
JNIEXPORT void JNICALL
Java_com_sharry_lib_nativecrashcather_NativeCrashCatcherManager_nativeInit(JNIEnv *env,
jclass type,
jstring path_) {
const char *path = env->GetStringUTFChars(path_, 0);
// 注册 native 捕获器
google_breakpad::MinidumpDescriptor descriptor(path);
static google_breakpad::ExceptionHandler eh(descriptor, NULL, DumpCallback, NULL, true, -1);
env->ReleaseStringUTFChars(path_, path);
}
一旦检测到 native 的 crash 便会将 crash 数据 dump 到磁盘
E/google-breakpad: ==========init handlers_installed==========
E/Native-Crash: ===============Native-Cash================
E/Native-Crash: Dump path: /storage/emulated/0/crashDump/33a9d33b-3f53-4274-4fb82182-abc09c3a.dmp
.dmp 文件是不可读的, 需要通过 google 提供的工具进行解析
二. 解析 dmp 文件
dmp 的解析工具为 minidump_stackwalk, 需要编译后才能使用
minidump_stackwalk 的编译
编译平台
MacOS
编译方式
// 1. 在源码目录下输入
./configure
// 2. 执行 Makefile
make
// 3. 安装到执行目录
make install
执行完成之后, 在 src/processor/ 下便可以找到编译好的 minidump_stackwalk 文件了
命令行解析 .dmp 文件
➜ ./minidump_stackwalk crash.dmp >crashLog.txt
crashLog.txt 这就是 dmp 的可读文件了
Operating system: Android
0.0.0 Linux 3.18.71-14176914 #1 SMP PREEMPT Wed Mar 13 16:22:55 KST 2019 armv8l
CPU: arm
ARMv1 Qualcomm part(0x51002150) features: half,thumb,fastmult,vfpv2,edsp,neon,vfpv3,tls,vfpv4,idiva,idivt
4 CPUs
GPU: UNKNOWN
Crash reason: SIGSEGV /SEGV_MAPERR
Crash address: 0x0
Process uptime: not available
Thread 0 (crashed)
...
总结
native 异常捕获的成本比起 java 异常要困难的多, 并且 dmp 的文件还需要通过工具反编译之后才能看, 更是增加了 native 异常的监管难度