Android使用Google Breakpad进行崩溃日志管理

2023-05-16


开发过程中,最担心的问题就是程序崩溃,而且还不知道崩溃的原因,现在使用Google Breakpad来跟踪崩溃的位置,非常方便;由于目前使用Mac系统开发,Google Breadpad处理Android崩溃日志时需要Linux环境,借助 vagrant 可以非常方便地在Mac使用Ubuntu环境。


有了vagrant以后就方便了~


$ varant ssh
$ cd /vagrant
$ sudo apt-get update
$ sudo apt-get install build-essential
$ svn checkout http://google-breakpad.googlecode.com/svn/trunk/ google-breakpad-read-only
$ cd google-breakpad-read-only
$ ./configure
$ make
  

执行完上面的命令将会在

  • google-breakpad-read-only/src/processor 目录下生成minidump_stackwalk 工具,用于导出crash log.
  • google-breakpad-read-only/src/tools/linux/dump_syms 目录下生成 dump_syms工具,用于导出符号文件
  • google-breakpad-read-only/src/client/linux 目录下生成 libbreakpad_client.a。

  1. 如果编译遇到 “cc1plus: warnings being treated as errors “错误,请将google-breakpad-read-only/Makefile文件中”* -Werror* “删除,重新编译。
  2. 如果make的时候遇到 “/lib64/libc.so.6: version `GLIBC_2.14’ not found “错误,说明 glibc 没有安装,安装方法请移步:http://my.oschina.net/zhangxu0512/blog/262275

集成 google-breakpad到Android项目中

1. 添加google-beakpad代码:
  • 方法一:

    • 拷贝 libbreakpad_client.a 到 jni 目录下。
    • 打开android项目的 Android.mk文件,在 LOCAL_PATH := $(call my-dir) 下加入如下代码:

include $(CLEAR_VARS)  
LOCAL_MODULE := breakpad_client  
LOCAL_MODULE_FILENAME := breakpad_client  
LOCAL_SRC_FILES := libbreakpad_client.a  
include $(PREBUILT_STATIC_LIBRARY)
  
  • 方法二:

$(call import-module,google-breakpad-read-only/android/google_breakpad) 
  
  • 方法三:
    • 将 google-breakpad 源代码里面的src文件夹拷贝到项目的jni目录下;
    • 修改Android.mk文件:
    LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := breakpad_client
LOCAL_CPP_EXTENSION := .cc .cpp
LOCAL_ARM_MODE := arm
LOCAL_SRC_FILES := \
    main.cpp \
    src/client/linux/crash_generation/crash_generation_client.cc \
    src/client/linux/handler/exception_handler.cc \
    src/client/linux/handler/minidump_descriptor.cc \
    src/client/linux/log/log.cc \
    src/client/linux/minidump_writer/linux_dumper.cc \
    src/client/linux/minidump_writer/linux_ptrace_dumper.cc \
    src/client/linux/minidump_writer/minidump_writer.cc \
    src/client/linux/microdump_writer/microdump_writer.cc \
    src/client/linux/dump_writer_common/ucontext_reader.cc \
    src/client/linux/dump_writer_common/seccomp_unwinder.cc \
    src/client/linux/dump_writer_common/thread_info.cc \
    src/client/minidump_file_writer.cc \
    src/common/android/breakpad_getcontext.S \
    src/common/convert_UTF.c \
    src/common/md5.cc \
    src/common/string_conversion.cc \
    src/common/linux/elfutils.cc \
    src/common/linux/file_id.cc \
    src/common/linux/guid_creator.cc \
    src/common/linux/linux_libc_support.cc \
    src/common/linux/memory_mapped_file.cc \
    src/common/linux/safe_readlink.cc
LOCAL_C_INCLUDES        := $(LOCAL_PATH)/src/common/android/include \
                           $(LOCAL_PATH)/src                        
LOCAL_C_INCLUDES += $(NDK_ROOT)/sources/cxx-stl/stlport/stlport
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
LOCAL_EXPORT_LDLIBS     := -llog
LOCAL_LDLIBS    := -llog
LOCAL_LDLIBS += $(NDK_ROOT)/sources/cxx-stl/stlport/libs/armeabi/libstlport_static.a
include $(BUILD_SHARED_LIBRARY)
2. 加入对googole-breakpad的引用:

LOCAL_WHOLE_STATIC_LIBRARIES += breakpad_client
  
3. 包含搜索路径:

$GOOGLE_BREAKPAD_PATH/src  
$GOOGLE_BREAKPAD_PATH/src/common/android/include 
  

本文使用的是第三种集成方法。

4. 添加google breakpad 的 c++代码:
#include <jni.h>
#include <time.h>   
#include <stdlib.h> 
#include "com_test_crash_TestCrash.h"
#include "client/linux/handler/exception_handler.h"
#include "client/linux/handler/minidump_descriptor.h"
#include "log.h"

google_breakpad::ExceptionHandler* exceptionHandler;

JavaVM *jvm = NULL;

void onNativeCrash(const char* info) {
    JNIEnv *env = 0;
    int result = jvm->GetEnv((void **) &env, JNI_VERSION_1_6);
    if (result != JNI_OK) {
        LOGE("%s", "jvm->GetEnv null");
        return;
    }
    jclass crashPinClass = env->FindClass(
            "com/test/crash/TestCrash");
    if (crashPinClass == NULL) {
        LOGE("%s", "FindClass com/test/crash/TestCrash null");
        return;
    }
    jmethodID crashReportMethod = env->GetStaticMethodID(crashPinClass,
            "onNativeCrash", "(Ljava/lang/String;)V");
    if (crashReportMethod == NULL) {
        LOGE("%s", "GetMethod onNativeCrash null");
        return;
    }
    jstring crashInfo = env->NewStringUTF(info);
    env->CallStaticVoidMethod(crashPinClass, crashReportMethod, crashInfo);
}

// 崩溃回调
bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
        void* context, bool succeeded) {
    LOGE("Dump path: %s\n", descriptor.path());
    onNativeCrash("");
    return succeeded;
}

extern "C" jint JNI_OnLoad(JavaVM *vm, void* /*reserved*/) {
    LOGE("JNI_OnLoad");
    jvm = vm;
    return JNI_VERSION_1_6;
}

#ifdef __cplusplus
extern "C" {
#endif

// 通过java代码调用initial()方法传人dmp文件保存的路径
JNIEXPORT void JNICALL Java_com_test_crash_TestCrash_initial(JNIEnv* env, jobject obj, jstring filepath) {
    LOGE("The Momo native crash initial.");
    const char *path = env->GetStringUTFChars(filepath, 0);
    google_breakpad::MinidumpDescriptor descriptor(path);
    exceptionHandler = new google_breakpad::ExceptionHandler(descriptor, NULL, DumpCallback, NULL,
            true, -1);
}

// native crash 测试代码
JNIEXPORT void JNICALL Java_com_test_crash_TestCrash_crash(JNIEnv *,
        jobject) {
    LOGE("The test native crash.");
    volatile int* a = (int*)(NULL);
    *a = 1;
}

#ifdef __cplusplus
}
#endif
5. 编译C++代码成.so文件(步骤略),通过加载libbreakpad_client.so,调用initial()初始化之后,就开始崩溃捕获。
public class TestCrash {
    // 加载动态链接库(加载.so最好放在application中)
    static {
        try {
            System.loadLibrary("breakpad_client");
        } catch (Error e) {
            e.printStackTrace();
        }
    }

    // 初始化
    public native void initial(String filePath);

    // native crash测试代码方法
    public native void crash();
}
6. 解析生成的dmp文件:
  • 回到ubuntu环境,建立一个Dump目录:

$ mkdir Dump 
  
  • 分别将生成的.dmp文件、minidump_stackwalk、dump_syms、android项目下的obj/local/armeabi/libxxx.so库拷贝到Dump目录。( 特别说明:libxxx.so文件必须是obj/local/armeabi/ 文件夹下的,这个里面so文件包含了debug信息,相对lib下的so文件来说体积很大,有可能上百兆。)

    创建好的Dump文件夹路径在“个人 —> ubuntu —> Dump”;

  • 执行生成符号文件命令:


$ cd /Dump  
$ dump_syms libxxx.so > libxxx.so.sym 
  
  • 查看libxxx.so.sym文件内容,头部会有,BB0351B14DDA42A6D36FA6EA358B49D50 这样的字符串:

$ head -n1 libxxx.so.sym

MODULE Linux arm BB0351B14DDA42A6D36FA6EA358B49D50 libxxx.so
  
  • 继续执行命令:

$ mkdir -p symbols/libxxx.so/BB0351B14DDA42A6D36FA6EA358B49D50/  
$ mv libxxx.so.sym symbols/libxxx.so/BB0351B14DDA42A6D36FA6EA358B49D50/ 
  
  • 导出崩溃堆栈信息文件( 确保.dmp文件和 symbols目录是同级的 ):

$ ./minidump_stackwalk filename.dmp symbols > crashed.log
  
7. 打开 crashed.log 文件:

Thread 0 (crashed)
 0  libxxx.so!Java_com_test_crash_TestCrash [TestCrash.cpp : 68 + 0x8]
     r0 = 0x00000027    r1 = 0xc3dab5eb    r2 = 0x00000001    r3 = 0x00000000
     r4 = 0x0000026a    r5 = 0x12f99f20    r6 = 0x12d63e00    r7 = 0x75c4a1b0
     r8 = 0x1302b9e0    r9 = 0xb4f07800   r10 = 0x0000003a   r12 = 0xb6e98929
     fp = 0x0000003a    sp = 0xbebb8f58    lr = 0xa289aafc    pc = 0xa289ab04
  
  • [TestCrash.cpp : 68 + 0x8]:定位到TestCrash.cpp的 第68行,从左到右第8个字符 ,产生的崩溃。
8. 如果没有生成符号文件,则 crashed.log 文件中的信息如下:


 
Thread 0 (crashed)
0 libxxx.so + 0xa289ab04
r0 = 0x00000027 r1 = 0xc3dab5eb r2 = 0x00000001 r3 = 0x00000000
r4 = 0x0000026a r5 = 0x12f99f20 r6 = 0x12d63e00 r7 = 0x75c4a1b0
r8 = 0x1302b9e0 r9 = 0xb4f07800 r10 = 0x0000003a r12 = 0xb6e98929
fp = 0x0000003a sp = 0xbebb8f58 lr = 0xa289aafc pc = 0xa289ab04

  • 通过上面的信息,我们没办法直观的看出哪里导致的崩溃,所以需要使用NDK中的arm-linux-androideabi-addr2line 工具定位崩溃;
  • arm-linux-androideabi-addr2line 路径为:$NDK_ROOT/toolchains/arm-linux-androideabi-4.8/prebuilt/darwin-x86/bin/arm-linux-androideabi-addr2line

  • usage: arm-linux-androideabi-addr2line -C -f -e <库路径> <内存地址>


arm-linux-androideabi-addr2line -C -f -e project/test/obj/local/armeabi/libxxx.so 0xa289ab04
  

这时候就可以在终端中看到是 libxxx.so 中的哪个文件的那一行发生异常了,接下来可以使用日志追踪有问题的代码了。



参考:http://blog.linguofeng.com/archive/2014/04/02/google-breakpad-android.html


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android使用Google Breakpad进行崩溃日志管理 的相关文章

  • 每次我尝试将任何内容上传到 android 模拟器时都会出现 IOException

    我使用的是 Windows 7 Ultimate 64 位版本和带有 Android 插件的 Eclipse 3 5 每次我创建一个新项目并尝试发布它时 都会收到如下错误 2010 02 15 22 48 10 EPG3 Uploading
  • C# 与 JAVA 接口实例

    我不知道该如何回答我的问题 它是关于Android可以实例化接口的 我正在尝试用 C 来做 现在我非常确定 Java 和 C 的规则是不能创建抽象和接口的实例 但我很想知道Android是如何做到这一点的 在 Android 中你可以这样做
  • 如何更改Appcompat主题中的TimePicker线条颜色?

    如何更改 Appcompat 主题中所选数字之间的 TimePicker 线条颜色 线条是蓝色的 但我需要橙色线条 我将 TimePickerDialog 与 ContextThemeWrapper 一起使用 TimePickerDialo
  • 简单对话框中的 ViewPager

    我想在对话框中使用 ViewPager 但失败了 这是所有代码 对话框中显示两个片段 Layouts main xml
  • Android 错误 - close() 从未在数据库上显式调用

    我应该在代码的哪里调用 close LogCat 返回此错误 close 从未在数据库上显式调用 android database sqlite DatabaseObjectNotClosedException 应用程序未关闭此处打开的游标
  • 有没有办法隐藏 TextView 中的文本?

    有没有办法隐藏 TextView 中的部分 但不是全部 文本 我尝试使用 AbsoluteSizeSpan 将大小设置为 0 但这没有任何我看到的视觉效果 你可以将大小设置为 1 但实际上你会得到凹凸不平的线条 而不是可读的文本 很可爱 但
  • 使用 Android NDK r5b 链接静态库时出现问题 [重复]

    这个问题在这里已经有答案了 最近升级到 NDK r5b 构建失败 并出现对静态库中函数的 未定义引用 这是错误 home brian workspace VoiceEngineDemo obj local armeabi v7a objs
  • Moshi 无法解析 nullable

    你好 希望你能帮助我 使用 kotlin Retrofit2 moshi 我从 https api spacexdata com v3 launches 获取数据并解析它 一切都很顺利 我得到的属性如下 flight number miss
  • Mediaplayer 播放几次后停止播放

    我有一个按钮 按下它会播放一个随机声音剪辑 然后播放另一个声音剪辑 然后通过一个媒体播放器播放另一个声音剪辑 但是多次按下该按钮 15 20 次 后 所有音频都会停止 我在播放最后一个音频剪辑后释放媒体播放器 所以我不认为这是原因 有什么指
  • 如何从android中的webview获取选定的文本?

    我需要从网络视图中获取选定的文本 为此 我这样说 webView loadUrl javascript Android getHtml window getSelection toString 在我的触摸事件中 触摸事件效果很好 Andro
  • 为什么抽屉布局中的视图强制缩放以填充屏幕

    这是我的测试代码
  • Android:等待 firebase valueEventListener

    我正在尝试使用信号量来等待我的 firebase valueEventListener 我有一个用户信息活动 其中包含用户必须填写的 6 个不同字段 当用户保存他 她的信息时 我想进行 全有或全无 类型的检查 某些用户信息不能重复 例如用户
  • Android:如何在双 SIM 卡手机中获取两张 SIM 卡的 SIM ID

    我想获取双 SIM 卡手机中两个 SIM 卡的 SIM 序列号 ID 有什么方法可以获取它们吗 提前致谢 import java lang reflect Method import android content Context impo
  • 从 JSON 数组创建标记 php mySQL Google Maps v2 android

    我正在尝试从 mySQL 数据库在 Google Maps v2 上创建标记 但它不起作用 地图确实出现了 但没有标记 谁能告诉我出了什么问题以及我需要改变什么 我也尝试过让 getDouble 为 getDouble 0 和 getDou
  • 如何在应用程序中创建会话对象

    在我的应用程序中 我想创建一个用于登录和注销的会话 我不知道如何使用会话 任何人都可以通过提供一些示例来帮助我 我认为会话对象应该是在应用程序开始运行时声明和初始化的静态对象 我遇到了这个问题 并决定将我的会话对象放入 utils 类中 该
  • 直接在应用程序中评价 Google Play 应用程序 [重复]

    这个问题在这里已经有答案了 我需要在我的 Android 应用程序中设置费率选项 我找到了这个link http www androidsnippets com prompt engaged users to rate your app i
  • Firebase API 初始化失败,java.lang.reflect.InitationTargetException

    我在我的应用程序中使用 firebase 身份验证 数据库和存储服务 之前运行良好 我已经添加了 firebase 云消息传递设置 如文档中所述 但应用程序在运行时崩溃了 我调查了这个问题大约 4 个小时并尝试了不同的解决方案 就像保持所有
  • 如何从MediaCodec获取解码格式?

    我正在与MediaCodec 我用它来解码 mp4 video MediaCodec 将视频解码为YUV格式 但我需要得到RGBA 一切都很好 但我发现有几种可能的格式 例如YUV420 YUV422等等 因此 据我所知 要进行转换 我需要
  • 如何在按下硬件主页按钮时关闭所有活动?

    我有一个应用程序 其中有 5 个活动 一个菜单活动和另外 4 个子活动附加到菜单屏幕 所以我可以选择任何活动 然后返回菜单 假设我像这样四处走动 菜单 gt 活动 1 gt 菜单 gt 活动 3 gt 活动 2 gt 菜单 现在我按 主页
  • Jetpack 中的波浪框组成

    有没有办法用Canvas制作一个顶部有波浪形的盒子 我想知道这个效果是否可以直接用Canvas来实现 不需要有滚动动画 不太清楚你为什么在谈论Canvas 要裁剪这样的视图 您可以使用自定义Shape并将其应用到您的视图中Modifier

随机推荐

  • Python爬虫项目之NBA球员可视化分析

    Python爬虫学习之NBA球员可视化分析 前言 最近刚上完Python选修课 一直挺喜欢Python的 觉得Python的简洁优美的代码像是在写诗一样让人看了赏心悦目 其次就是他强大的第三方库是其他语言所不能媲美的 有很多你需要用的功能
  • postgresql时间戳与时间的转换

    日期转时间戳 span class token keyword select span EXTRACT span class token punctuation span epoch span class token keyword FRO
  • python xml文件解析

    1 解析 1 1 解析方式 Python 有三种 XML 解析方式 xff1a SAX xff08 simple API for XML xff09 DOM xff08 Document Object Model xff09 Element
  • python输出列表去掉中括号

    可以使用 join的方法进行输出 xff0c 因为 join处理的是字符串 xff0c 所以需要进行类型转换 list1 span class token operator 61 span span class token punctuat
  • postgresql取出分组的第一条数据

    span class token comment 根据编号分组后取第一条数据 span span class token keyword SELECT span span class token operator span span cla
  • git 清空本地修改

    span class token function git span checkout span class token keyword span span class token comment 本地所有修改的 没有的提交的 xff0c
  • 关于Ubuntu卸载Python导致的终端没了

    解决方式 sudo upgrade fix missing sudo apt install ubuntu desktop
  • elasticsearch wildcard查询取消大小写

    https stackoverflow com questions 51107349 elasticsearch wildcard case sensitive 添加case insensitive 参数即可 GET test 005 se
  • window VNC Viewer设置屏幕分配率

    问题 xff1a 远程时 xff0c 显示的界面不会跟着本机屏幕大小而自动调节 xff0c 导致无法在页面中完全显示屏幕的内容 解决1 xff1a 打开VNC Viewer xff0c 选择Options xff0c 在Scale to w
  • .net core 中使用MongoDB

    https www thecodebuzz com exception filters in net core https www mongodb com docs drivers csharp https www mongodb com
  • 使用代理下载国外源registry.k8s.io镜像,并传到docker hub私有镜像库

    日常的生产开发中 xff0c 免不了从国外拉取镜像 xff0c 但有个问题 xff0c 我们可能访问不到那个镜像源 xff0c 因此需要使用代理 https labs play with docker com 具体步骤 使用docker h
  • python 操作neo4j

    安装依赖包 pip span class token function install span neo4j 使用 span class token keyword class span span class token class nam
  • neo4j获取不同维度关联关系

    插入数据 CREATE span class token punctuation span 小北 朋友圈 span class token punctuation span 姓名 span class token string 34 小北
  • neo4j结合gds实现最短路径算法

    背景 xff1a Neo4j自带的cypher语句中的 shortestpath allShortestPaths 返回值内容非常有限 xff0c 不易处理 在实际生产环境中可用性极低 xff0c 且若带where条件查询时 xff0c 查
  • C#解决中文乱码

    字符串乱码 可以使用Regex Unescape函数解决 字符串写入文件乱码 使用File AppendAllText 或者File WriteAllText path string Encoding ASCII
  • JS中的异步详解

    一 xff1a 异步是什么 xff1f 同步和异步是两种模式 34 同步模式 34 就是指后一个任务等待前一个任务结束 xff0c 然后再执行 xff0c 程序的执行顺序与任务的排列顺序是一致的 同步的 34 异步模式 34 则完全不同 x
  • C语言截取某个字符之前的字符串

    uint32 size 61 0 int p char str 61 34 fadhjkfhadl fhdjfkhla dfjkadlf 34 char str2 61 34 34 p 61 0 for int k 61 0 strlen
  • Xlib: extension “XInputExtension“ missing on display “:1.0“

    ubuntu 安装vscode之后点击生成的图标无法打开 xff08 没有图标记得重启 xff09 xff0c 建议在安装地址直接打开可以看到报错信息 如果是root用户 xff0c 可能需要 no sandbox参数才能启动 继续执行 c
  • matlab的帮助文档切换成中文(求助贴)

    Matlab的帮助文档切换成中文 xff08 求助贴 xff09 题主的matlab版本 xff1a 2018a 系统win10 问题描述 xff1a 当使用matlab时 xff0c 有时需要使用help 语句查看一些关键字的用法 xff
  • Android使用Google Breakpad进行崩溃日志管理

    开发过程中 xff0c 最担心的问题就是程序崩溃 xff0c 而且还不知道崩溃的原因 xff0c 现在使用Google Breakpad来跟踪崩溃的位置 xff0c 非常方便 xff1b 由于目前使用Mac系统开发 xff0c Google