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