美文网首页第三方扩展
崩溃处理,ACRA核心流程简析

崩溃处理,ACRA核心流程简析

作者: ImmortalHalfWu | 来源:发表于2016-10-16 17:34 被阅读541次
    ACRA

    2016/10/02
    上海
    Read the fucking source code。

        ACRA Application Crash Reports for Android 。
        GitHub:https://github.com/ACRA
    

    (文章基于ACRA v4.8.0)
    ACRA目的简单明了,收集App崩溃堆栈信息,生成报告并发送到指定端。

    通俗的崩溃处理流程:
    1,实现Thread.UncaughtExceptionHandler接口,自定义崩溃处理器。
    2,保留系统默认Thread.UncaughtExceptionHandler接口(通过Thread.getDefaultUncaughtExceptionHandler()获得),
       当自定义处理器无法分析崩溃异常时,提交给默认处理器解决。
    3,绑定自定义处理器(通过Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler)方法)
    4,崩溃,自定义处理器捕捉崩溃异常,生成报表。
    5,处理报表(我习惯发送到静态BroadcastReceiver处理报表并重启应用,尝试将报表发送到服务器,若发送失败,则写入本地文件)
    
    ACRA核心类:
    ACRA    ACRA入口类
    ACRAConfiguration    ACRA配置器
    ConfiguraitonBuilder    配置器的构造器
    ErrorReporter    崩溃堆栈捕捉线程(实现Thread.UncaughtExceptionHandler)
    ReportBuilder    错误报表生成器
    SendService    报表提交服务(处于ErrorReporter与ReportSender之间)
    SenderServiceStarter    SendService帮助类
    ReportSender    错误报表发送器
    ReportSenderFactory    ReportSender工厂类
    

    ACRA初始化:

    //初始化三种方式
    ACRA.init(Application app);
    ACRA.init(Application app, ACRAConfiguration config);
    //ACRAConfiguration是ACRA配置器,与注解是相同功能,ACRAConfiguration优先于注解
    //checkReportsOnApplicationStart,这个参数决定了三件事:
      1,是否删除上个版本未发送的错误报告,
      2,是否删除用户未批准发送的错误报告,
      3,是否尝试发送之前发送失败的错误报表。
    ACRA.init(Application app, ACRAConfiguration config, boolean checkReportsOnApplicationStart);
    
    //省略版本适配,优化等代码
    public static void init(Application app, ACRAConfiguration config, boolean checkReportsOnApplicationStart){
        //判断ACRA是否处于运行状态
        final boolean senderServiceProcess = isACRASenderServiceProcess(app);
        //android 系统版本是否>=8
        boolean supportedAndroidVersion = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO);
    
        mApplication = app;
        configProxy = config;
        try {
        ...
            省略ACRA版本适配相关,ACRA版本升级,本地错误报表转移
        ...
    
            //checkCrashResources()方法检查注释中的相关字段是否完整,Toast模式必须设置ToastText字段等..
            config.checkCrashResources();
            //是否加载Acra
            final boolean enableAcra = supportedAndroidVersion && !shouldDisableACRA(prefs);
            //创建ErrorReporter实例
            errorReporterSingleton = new ErrorReporter(mApplication, configProxy, prefs, enableAcra, supportedAndroidVersion, !senderServiceProcess);
            //
            if (checkReportsOnApplicationStart && !senderServiceProcess) {
                //ApplicationStartupProcessor 用于每次ACRA初始化时,查找任何现有的报告并发送。
                final ApplicationStartupProcessor startupProcessor = new ApplicationStartupProcessor(mApplication,  config);
                //如果配置器中设定删除App上个版本未发送的错误报表
                if (config.deleteOldUnsentReportsOnApplicationStart()) {
                    //则删除
                    startupProcessor.deleteUnsentReportsFromOldAppVersion();
                }
                //如果配置器中设定删除用户未批准发送的错误报告
                if (config.deleteUnapprovedReportsOnApplicationStart()) {
                    //则删除
                    startupProcessor.deleteAllUnapprovedReportsBarOne();
                }
                //如果可以启动ACRA
                if (enableAcra) {
                  //尝试发送之前发送失败的错误报表。                
                  startupProcessor.sendApprovedReports();
                }
            }
        } catch (ACRAConfigurationException e) {
            log.w(LOG_TAG, "Error : ", e);
        }
        .......
    }
    

    ErrorReporter,崩溃堆栈捕捉线程

    public class ErrorReporter implements Thread.UncaughtExceptionHandler
    

    ErrorReporter初始化:

    //省略版本适配,优化等代码
    ErrorReporter(Application context, ACRAConfig config, SharedPreferences prefs, boolean enabled, boolean supportedAndroidVersion, boolean listenForUncaughtExceptions) {
        this.context = context;
        this.config = config;
        this.supportedAndroidVersion = supportedAndroidVersion;
        
    ......
        //获取系统默认异常捕捉线程
        defaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
        //将ErrorReporter设置为默认异常捕捉线程
        Thread.setDefaultUncaughtExceptionHandler(this);
    
    ......
    }
    

    ErrorReporter异常处理:

    @Overridepublic void uncaughtException(Thread t, Throwable e) {
        ......
            //出现异常,利用错误报表构造器,生成错误报表
            new ReportBuilder()
                 //ReportBuilder内部持有崩溃数据t实例
                .uncaughtExceptionThread(t)
                //ReportBuilder内部持有崩溃数据e实例
                .exception(e)
                //ReportBuilder内部有app是否结束的标示
                .endApplication()
                //构建
                .build(reportExecutor);
        ......
    }
    
    public void build(ReportExecutor reportExecutor) {
        .....
        //通过错误报表构造器,分析错误堆栈,并写入本地文件
        reportExecutor.execute(ReportBuilder.this);
    }
    
    public void execute(final ReportBuilder reportBuilder) {
        ...分析并写入本地,再根据配置,显示对应的提示...
        //发送错误报表
        startSendingReports(是否是静默发送, 是否直接批准发送);
    }
    
    private void startSendingReports(boolean onlySendSilentReports, boolean approveReportsFirst) {
    ......
            //创建SenderServiceStarter 对象
            final SenderServiceStarter starter = new SenderServiceStarter(context, config);
            //调用startService方法
            starter.startService(onlySendSilentReports, approveReportsFirst);
    ......
        } 
    }
    
    //启动SenderService服务
    public void startService(boolean onlySendSilentReports, boolean approveReportsFirst) {
        final Intent intent = new Intent(context, SenderService.class);
        //存入是否静默发送
        intent.putExtra(SenderService.EXTRA_ONLY_SEND_SILENT_REPORTS, onlySendSilentReports);
        //存入是否直接批准发送
        intent.putExtra(SenderService.EXTRA_APPROVE_REPORTS_FIRST, approveReportsFirst);
        //存入发射器工厂类的Class对象,此对象为ReportSenderFactory实例
        intent.putExtra(SenderService.EXTRA_REPORT_SENDER_FACTORIES, config.reportSenderFactoryClasses());
        //存入ACRA配置器
        intent.putExtra(SenderService.EXTRA_ACRA_CONFIG, config);
        //启动SenderService
        context.startService(intent);
    }
    

    SenderService继承自IntentService

    public class SenderService extends IntentService
    

    ReportSenderFactory接口

    public interface ReportSenderFactory {
         //返回ReportSender 实例
        ReportSender create(Context context, ACRAConfig config);
    }
    

    ReportSender 接口

    public interface ReportSender {
        //处理错误报表
        void send(Context context, CrashReportData errorContent) throws ReportSenderException;
    }
    
    //启动IntentService,调用startService(intent);intent都会传入此方法
    @Overrideprotected void onHandleIntent(final Intent intent) {
        //是否静默发送
        final boolean onlySendSilentReports = intent.getBooleanExtra(EXTRA_ONLY_SEND_SILENT_REPORTS, false);
        //是否直接批准发送
        final boolean approveReportsFirst = intent.getBooleanExtra(EXTRA_APPROVE_REPORTS_FIRST, false);
        //发射器工厂类
        final Class<? extends ReportSenderFactory>[] senderFactoryClasses =            (Class<? extends ReportSenderFactory>[]) intent.getSerializableExtra(EXTRA_REPORT_SENDER_FACTORIES);
        //ACRA配置器
        final ACRAConfig config = (ACRAConfig) intent.getSerializableExtra(EXTRA_ACRA_CONFIG);
        try {
            //配置器ReportSenderFactory可以配置多个,所以ReportSender实例的个数与ReportSenderFactory个数相同,getSenderInstances方法通过ReportSenderFactory.Class创建ReportSenderFactory实例,并创建ReportSender,返回ReportSender列表
            final List<ReportSender> senderInstances = getSenderInstances(config, senderFactoryClasses);
            ......
            // 获取本地所有错误报表
            final File[] reports = locator.getApprovedReports();
            //ReportDistributor 用于向所有ReportSender实例分发报告
            final ReportDistributor reportDistributor = new ReportDistributor(this, config, senderInstances);
            for (final File report : reports) {
    ......
                //向所有ReportSender实例分发报告
                reportDistributor.distribute(report);
    ......
            }
        } catch (Exception e) {
            ......
        }
    }
    
    public void distribute(File reportFile) {
    ......
            sendCrashReport(reportFile格式化后);
    ......
    }
    
    //CrashReportData 为错误信息格式化后的对象
    public void sendCrashReport(CrashReportData errorContent) {
    ......
      //遍历所有ReportSender 实例
      for (ReportSender sender : reportSenders) {
    ......
            //通过ReportSender 实例发送错误报告
            sender.send(context, errorContent);
    ......
      }
    ......
    }
    

    相关文章

      网友评论

        本文标题:崩溃处理,ACRA核心流程简析

        本文链接:https://www.haomeiwen.com/subject/qjdbyttx.html