笔记:Android常规Crash方案

引言:Crash崩溃在Android程序开发中总是会遇见的,在本地调试的还好我没通常可以通过logcat日志打印来分析输出的日志 定位到问题。但是上了线各种复杂的环境就没那么好处理。这时候通常我会集成像Bugly这种sdk来分析问题。但是Bugly又是怎么做到crash的采集呢?

Crash分类:

  • Java层崩溃Crash:

Java层的崩溃一般比较好捕捉 java中的Thread提供了异常处理接口 Thread.UncaughtExceptionHandler

public class CrashHanler  implements  Thread.UncaughtExceptionHandler{
    private static Thread.UncaughtExceptionHandler mDefaultExceptionHandler;
    private static Context mContext;

    public static void init(Context context){
        mContext = context;
        //获取默认ExceptionHandler
        mDefaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
        //设置程序开发者的自行异常处理器 发生异常会回调到 uncaughtException
        Thread.setDefaultUncaughtExceptionHandler(new CrashHanler());
    }

    @Override
    public void uncaughtException(@NonNull Thread thread, @NonNull Throwable throwable) {
        //异常回调处理方法
        File crashFileDir = new File(mContext.getExternalFilesDir("crashReport"),"crash_info");
        if(!crashFileDir.exists())
            crashFileDir.mkdirs();
        long time = System.currentTimeMillis();
        String dateTimeStr = DateFormat.format("yyyy年MM月dd日 HH时mm分ss秒",time).toString();
        String dateTimeFileStr = DateFormat.format("yyyyMMssHHmmss",time).toString();
        File crashFile = new File(crashFileDir,dateTimeFileStr+".log");
        //使用打印流打印到文件分
        try {
            PrintWriter pw = new PrintWriter(crashFile);
            pw.println("crash发生线程:"+ thread.getName());
            pw.println("时间:"+dateTimeStr);
            pw.println("设备与APP版本信息:"+getDevicePhoneInfo());
            pw.println("错误堆栈:");
            throwable.printStackTrace(pw);
            pw.close();
        } catch (FileNotFoundException e) {

            e.printStackTrace();
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }finally {
            if(mDefaultExceptionHandler!=null)
                mDefaultExceptionHandler.uncaughtException(thread,throwable);
        }
    }

    private static String getDevicePhoneInfo() throws PackageManager.NameNotFoundException {...}
}

捕获记录文件.png
  • Native层崩溃Crash:

集成 google 的 breakpad 框架

ndk部分.png

JNI部分,先写native方法

public static native void initNativeCrash(String path);

native实现

#include 
#include 
#include "breakpad/src/client/linux/handler/exception_handler.h"
#include "breakpad/src/client/linux/handler/minidump_descriptor.h"
extern "C"
JNIEXPORT void JNICALL
Java_com_chenx_crashreportproject_CrashReportManager_testNativeCrash(JNIEnv *env, jclass clazz) {
    __android_log_print(ANDROID_LOG_INFO,"testNative","xxxxxxx test NDK Native crash. xxxxxxxx");
    int *p = NULL;
    *p = 10;
 }
 bool DumpCallback(const google_breakpad::MinidumpDescriptor &descriptor,
         void* context,
                   bool succeeded){
    __android_log_print(ANDROID_LOG_ERROR,"native","native crash:%s",descriptor.path());
     return false;
}

 extern "C"
 JNIEXPORT void JNICALL
 Java_com_chenx_crashreportproject_CrashReportManager_initNativeCrash(JNIEnv *env,jclass clazz,jstring filepath){
     const char* path = env->GetStringUTFChars(filepath,0);
     __android_log_print(ANDROID_LOG_INFO, "native", "===> %s", path);
     google_breakpad::MinidumpDescriptor descriptor(path);
     static google_breakpad::ExceptionHandler eh(descriptor, NULL, DumpCallback,
                                                 NULL, true, -1);
     env->ReleaseStringUTFChars(filepath,path);
}
1.通过linux的信号分发机制我们设置我们自己异常处理器就可以捕抓到native层的错误 但是文件我们是打不开的。这个时候如果是window系统 我们可以用minidump工具来转文件 minidump位于:AndroidStudio 安装目录下的\bin\lldb\bin
minidump目录.png
2.然后通过cmd运行命令

minidump_stackwalk C:\Users\86136\Desktop\b47fc729-680c-4a62-7fd8b3ad-9ad095d9.dmp >myCrash.txt
这样就可以得到我们可读的crash文件

myCrash文件的一部分.jpg

3.再通过ndk目录下的aar64-linux-android-addr2line 工具来确定定位错误位置
native crash定位

项目源码:https://gitee.com/DaiMaZhiJia/CrashReportProject

你可能感兴趣的:(笔记:Android常规Crash方案)