
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);
......
}
......
}