崩潰處理,ACRA核心流程簡析

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崩潰堆棧信息,生成報(bào)告并發(fā)送到指定端。

通俗的崩潰處理流程:
1,實(shí)現(xiàn)Thread.UncaughtExceptionHandler接口,自定義崩潰處理器。
2,保留系統(tǒng)默認(rèn)Thread.UncaughtExceptionHandler接口(通過Thread.getDefaultUncaughtExceptionHandler()獲得),
   當(dāng)自定義處理器無法分析崩潰異常時(shí),提交給默認(rèn)處理器解決。
3,綁定自定義處理器(通過Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler)方法)
4,崩潰,自定義處理器捕捉崩潰異常,生成報(bào)表。
5,處理報(bào)表(我習(xí)慣發(fā)送到靜態(tài)BroadcastReceiver處理報(bào)表并重啟應(yīng)用,嘗試將報(bào)表發(fā)送到服務(wù)器,若發(fā)送失敗,則寫入本地文件)
ACRA核心類:
ACRA    ACRA入口類
ACRAConfiguration    ACRA配置器
ConfiguraitonBuilder    配置器的構(gòu)造器
ErrorReporter    崩潰堆棧捕捉線程(實(shí)現(xiàn)Thread.UncaughtExceptionHandler)
ReportBuilder    錯(cuò)誤報(bào)表生成器
SendService    報(bào)表提交服務(wù)(處于ErrorReporter與ReportSender之間)
SenderServiceStarter    SendService幫助類
ReportSender    錯(cuò)誤報(bào)表發(fā)送器
ReportSenderFactory    ReportSender工廠類

ACRA初始化:

//初始化三種方式
ACRA.init(Application app);
ACRA.init(Application app, ACRAConfiguration config);
//ACRAConfiguration是ACRA配置器,與注解是相同功能,ACRAConfiguration優(yōu)先于注解
//checkReportsOnApplicationStart,這個(gè)參數(shù)決定了三件事:
  1,是否刪除上個(gè)版本未發(fā)送的錯(cuò)誤報(bào)告,
  2,是否刪除用戶未批準(zhǔn)發(fā)送的錯(cuò)誤報(bào)告,
  3,是否嘗試發(fā)送之前發(fā)送失敗的錯(cuò)誤報(bào)表。
ACRA.init(Application app, ACRAConfiguration config, boolean checkReportsOnApplicationStart);
//省略版本適配,優(yōu)化等代碼
public static void init(Application app, ACRAConfiguration config, boolean checkReportsOnApplicationStart){
    //判斷ACRA是否處于運(yùn)行狀態(tài)
    final boolean senderServiceProcess = isACRASenderServiceProcess(app);
    //android 系統(tǒng)版本是否>=8
    boolean supportedAndroidVersion = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO);

    mApplication = app;
    configProxy = config;
    try {
    ...
        省略ACRA版本適配相關(guān),ACRA版本升級(jí),本地錯(cuò)誤報(bào)表轉(zhuǎn)移
    ...

        //checkCrashResources()方法檢查注釋中的相關(guān)字段是否完整,Toast模式必須設(shè)置ToastText字段等..
        config.checkCrashResources();
        //是否加載Acra
        final boolean enableAcra = supportedAndroidVersion && !shouldDisableACRA(prefs);
        //創(chuàng)建ErrorReporter實(shí)例
        errorReporterSingleton = new ErrorReporter(mApplication, configProxy, prefs, enableAcra, supportedAndroidVersion, !senderServiceProcess);
        //
        if (checkReportsOnApplicationStart && !senderServiceProcess) {
            //ApplicationStartupProcessor 用于每次ACRA初始化時(shí),查找任何現(xiàn)有的報(bào)告并發(fā)送。
            final ApplicationStartupProcessor startupProcessor = new ApplicationStartupProcessor(mApplication,  config);
            //如果配置器中設(shè)定刪除App上個(gè)版本未發(fā)送的錯(cuò)誤報(bào)表
            if (config.deleteOldUnsentReportsOnApplicationStart()) {
                //則刪除
                startupProcessor.deleteUnsentReportsFromOldAppVersion();
            }
            //如果配置器中設(shè)定刪除用戶未批準(zhǔn)發(fā)送的錯(cuò)誤報(bào)告
            if (config.deleteUnapprovedReportsOnApplicationStart()) {
                //則刪除
                startupProcessor.deleteAllUnapprovedReportsBarOne();
            }
            //如果可以啟動(dòng)ACRA
            if (enableAcra) {
              //嘗試發(fā)送之前發(fā)送失敗的錯(cuò)誤報(bào)表。                
              startupProcessor.sendApprovedReports();
            }
        }
    } catch (ACRAConfigurationException e) {
        log.w(LOG_TAG, "Error : ", e);
    }
    .......
}

ErrorReporter,崩潰堆棧捕捉線程

public class ErrorReporter implements Thread.UncaughtExceptionHandler

ErrorReporter初始化:

//省略版本適配,優(yōu)化等代碼
ErrorReporter(Application context, ACRAConfig config, SharedPreferences prefs, boolean enabled, boolean supportedAndroidVersion, boolean listenForUncaughtExceptions) {
    this.context = context;
    this.config = config;
    this.supportedAndroidVersion = supportedAndroidVersion;
    
......
    //獲取系統(tǒng)默認(rèn)異常捕捉線程
    defaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
    //將ErrorReporter設(shè)置為默認(rèn)異常捕捉線程
    Thread.setDefaultUncaughtExceptionHandler(this);

......
}

ErrorReporter異常處理:

@Overridepublic void uncaughtException(Thread t, Throwable e) {
    ......
        //出現(xiàn)異常,利用錯(cuò)誤報(bào)表構(gòu)造器,生成錯(cuò)誤報(bào)表
        new ReportBuilder()
             //ReportBuilder內(nèi)部持有崩潰數(shù)據(jù)t實(shí)例
            .uncaughtExceptionThread(t)
            //ReportBuilder內(nèi)部持有崩潰數(shù)據(jù)e實(shí)例
            .exception(e)
            //ReportBuilder內(nèi)部有app是否結(jié)束的標(biāo)示
            .endApplication()
            //構(gòu)建
            .build(reportExecutor);
    ......
}
public void build(ReportExecutor reportExecutor) {
    .....
    //通過錯(cuò)誤報(bào)表構(gòu)造器,分析錯(cuò)誤堆棧,并寫入本地文件
    reportExecutor.execute(ReportBuilder.this);
}
public void execute(final ReportBuilder reportBuilder) {
    ...分析并寫入本地,再根據(jù)配置,顯示對(duì)應(yīng)的提示...
    //發(fā)送錯(cuò)誤報(bào)表
    startSendingReports(是否是靜默發(fā)送, 是否直接批準(zhǔn)發(fā)送);
}
private void startSendingReports(boolean onlySendSilentReports, boolean approveReportsFirst) {
......
        //創(chuàng)建SenderServiceStarter 對(duì)象
        final SenderServiceStarter starter = new SenderServiceStarter(context, config);
        //調(diào)用startService方法
        starter.startService(onlySendSilentReports, approveReportsFirst);
......
    } 
}
//啟動(dòng)SenderService服務(wù)
public void startService(boolean onlySendSilentReports, boolean approveReportsFirst) {
    final Intent intent = new Intent(context, SenderService.class);
    //存入是否靜默發(fā)送
    intent.putExtra(SenderService.EXTRA_ONLY_SEND_SILENT_REPORTS, onlySendSilentReports);
    //存入是否直接批準(zhǔn)發(fā)送
    intent.putExtra(SenderService.EXTRA_APPROVE_REPORTS_FIRST, approveReportsFirst);
    //存入發(fā)射器工廠類的Class對(duì)象,此對(duì)象為ReportSenderFactory實(shí)例
    intent.putExtra(SenderService.EXTRA_REPORT_SENDER_FACTORIES, config.reportSenderFactoryClasses());
    //存入ACRA配置器
    intent.putExtra(SenderService.EXTRA_ACRA_CONFIG, config);
    //啟動(dòng)SenderService
    context.startService(intent);
}

SenderService繼承自IntentService

public class SenderService extends IntentService

ReportSenderFactory接口

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

ReportSender 接口

public interface ReportSender {
    //處理錯(cuò)誤報(bào)表
    void send(Context context, CrashReportData errorContent) throws ReportSenderException;
}
//啟動(dòng)IntentService,調(diào)用startService(intent);intent都會(huì)傳入此方法
@Overrideprotected void onHandleIntent(final Intent intent) {
    //是否靜默發(fā)送
    final boolean onlySendSilentReports = intent.getBooleanExtra(EXTRA_ONLY_SEND_SILENT_REPORTS, false);
    //是否直接批準(zhǔn)發(fā)送
    final boolean approveReportsFirst = intent.getBooleanExtra(EXTRA_APPROVE_REPORTS_FIRST, false);
    //發(fā)射器工廠類
    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可以配置多個(gè),所以ReportSender實(shí)例的個(gè)數(shù)與ReportSenderFactory個(gè)數(shù)相同,getSenderInstances方法通過ReportSenderFactory.Class創(chuàng)建ReportSenderFactory實(shí)例,并創(chuàng)建ReportSender,返回ReportSender列表
        final List<ReportSender> senderInstances = getSenderInstances(config, senderFactoryClasses);
        ......
        // 獲取本地所有錯(cuò)誤報(bào)表
        final File[] reports = locator.getApprovedReports();
        //ReportDistributor 用于向所有ReportSender實(shí)例分發(fā)報(bào)告
        final ReportDistributor reportDistributor = new ReportDistributor(this, config, senderInstances);
        for (final File report : reports) {
......
            //向所有ReportSender實(shí)例分發(fā)報(bào)告
            reportDistributor.distribute(report);
......
        }
    } catch (Exception e) {
        ......
    }
}
public void distribute(File reportFile) {
......
        sendCrashReport(reportFile格式化后);
......
}
//CrashReportData 為錯(cuò)誤信息格式化后的對(duì)象
public void sendCrashReport(CrashReportData errorContent) {
......
  //遍歷所有ReportSender 實(shí)例
  for (ReportSender sender : reportSenders) {
......
        //通過ReportSender 實(shí)例發(fā)送錯(cuò)誤報(bào)告
        sender.send(context, errorContent);
......
  }
......
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容