- 浏览: 2195498 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (1240)
- mac/IOS (287)
- flutter (1)
- J2EE (115)
- android基础知识 (582)
- android中级知识 (55)
- android组件(Widget)开发 (18)
- android 错误 (21)
- javascript (18)
- linux (70)
- 树莓派 (18)
- gwt/gxt (1)
- 工具(IDE)/包(jar) (18)
- web前端 (17)
- java 算法 (8)
- 其它 (5)
- chrome (7)
- 数据库 (8)
- 经济/金融 (0)
- english (2)
- HTML5 (7)
- 网络安全 (14)
- 设计欣赏/设计窗 (8)
- 汇编/C (8)
- 工具类 (4)
- 游戏 (5)
- 开发频道 (5)
- Android OpenGL (1)
- 科学 (4)
- 运维 (0)
- 好东西 (6)
- 美食 (1)
最新评论
-
liangzai_cool:
请教一下,文中,shell、C、Python三种方式控制led ...
树莓派 - MAX7219 -
jiazimo:
...
Kafka源码分析-序列5 -Producer -RecordAccumulator队列分析 -
hp321:
Windows该命令是不是需要安装什么软件才可以?我试过不行( ...
ImageIO读jpg的时候出现javax.imageio.IIOException: Unsupported Image Type -
hp321:
Chenzh_758 写道其实直接用一下代码就可以解决了:JP ...
ImageIO读jpg的时候出现javax.imageio.IIOException: Unsupported Image Type -
huanghonhpeng:
大哥你真强什么都会,研究研究。。。。小弟在这里学到了很多知识。 ...
android 浏览器
概述
Acra是老牌的bug自动采集系统。接入sdk后,可以实现程序崩溃自动发送崩溃日志。
发送自定义的错误日志等功能。具体详细介绍可以参见acra官网地址。
整体来看,Acra就是通过sdk收集进程的崩溃日志,然后以http或mail(默认的两类Sender)的方式将数据发送出去。服务器则是一套基于json的restful的接口。
服务端方面不是本次分析重点,暂不进行分析。
本系列文章将基于Acra 4.9.0 RC2源码进行分析。
Backend
服务端方面我们需要先搭建一个server,才能更好的看到我们的崩溃信息,
更直观的看到acra给我们提供了哪些针对崩溃的采集内容。
官方提供了acralyzer以及一些针对acra的第三方开源实现。
关于世面上常用的server端的,该文章做了明确分析,针对不同backend的比较。
官方backend acralyzer的搭建非常简单,具体可以参见该文章的server配置部分。
项目搭建完成后可以使用通过如下的url对server端进行访问。
查看app崩溃的表结构
http://ip:port/_utils/
查看崩溃日志
http://ip:port/acralyzer/_design/acralyzer/index.html#/dashboard/
关于server端的介绍结束。不是重点。
Client
项目构建
最新版本项目基于Gradle构建,了解Acra历史的肯定知道该项目是存在了很久了.
Android世界中项目最早是基于ant构建,后来是maven,现在是Gradle。
在没有Gradle的编译环境之前,基本上大部分是基于maven构建。
查看最新版本的代码可以看到仍然包含了之前maven的配置文件。
并且使用Gradle编译编译中使用到的version name等配置参数也都是从pom.xml中读取的。
具体可以参看build.gradle中关于版本号的相关配置。
需要注意的是,从github clone下来的项目是无法直接使用Gradle进行编译的。
熟悉Gradle android 编译流程的人应该从build.gradle文件中可以找出错误的原因。
具体的编译文件需要修改的地方为,在build.gradle中开头位置添加编译android项目使用到的plugin。
如下所示:
添加之后,就可以执行gradle build命令打出需要使用的aar包。
项目配置及使用
首先需要注意一点,Acra使用独立进程:acra,进行采集数据的发送,保证当app崩溃时,采集仍然能发送出去。
由于使用独立的进程,所以会导致application被实例化多次,这样就需要注意app自身的某些业务逻辑,不要在application类中执行多次,从而导致app产生bug。
对Acra的相关配置一般在application中进行初始化。
初始化配置
在application中进行初始化配置。
使用注解初始化
动态初始化配置
一般使用acra我们的目的是采集崩溃,所以需要在manifest中申请网络权限,以保证crash的正常发送。
目标服务器配置
acra中发送crash数据是通过Sender实现的,Sender是通过ReportSenderFactory实例化出来的。
而ReportSenderFactory是可以在初始化时进行配置的。
acra默认提供了email及http 两种sender。
如果自定义Sender则需要两个步骤,
针对Sender的配置有两种形式,一种为注解,一种为通过代码进行设置。
Acra中默认提供两个Sender
HttpSender
提供了Post及Put两种提交crash到服务器的方式。
提交的类型可以为JSON或Form表单两种方式。
EmailIntentSender
组拼crash Report 通过intent调用系统提供的发送email的app。
流程分析及重点类分析
初始化设置流程
Acra的初始化函数为init,所以使用入口函数ACRA.init()对acra进行初始化。
一般入口函数在application初始化时进行调用。
ACRA.init()
使用ReportsCrashes来初始化Acra。
ACRA提供多个init方法,经过内部调用,最终都会调用参数最多的init方法完成初始化相关逻辑。
下面对重要的init方法进行说明
ConfigurationBuilder
主要用来封装构造ACRAConfiguration的相关属性。
提供了两种方式来设置相关属性的值。
获取属性值之后,通过调用build()方法,创建ACRAConfiguration对象。
ACRAConfiguration
用来保存ACRA涉及到的所有配置。
SharedPreferencesFactory
用来获取ACRA所使用的SharedPreferences的文件。
通过这层封装可以对sp进行一些自定义的设置,比如sp的名字。
ErrorReporter
ACRA最核心的类,该类用来捕获crash相关的信息,以及发送crash信息。
Android平台如果想要捕获java层代码的crash需要设置application Thread的UncaughtExceptionHandler。
ACRA会将ErrorReporter设置为Application Thread的UncaughtExceptionHandler。
从而实现对异常的捕获。
参见代码可以知道,acra通过设置默认ExceptionHandler来捕获异常。
并把自己设置为处理对象。
LastActivityManager
是用来记录最后展示的Activity的,通过application.registerActivityLifecycleCallbacks来实现记录功能的。ACRA可以在崩溃的时候弹出Dialog,所以需要记住最后的Activity。
ReportExecutor
主要业务逻辑关注execute()方法.
该类主要负责调用CrashReportDataFactory采集数据,
调用CrashReportPersister对崩溃数据进行持久化,
调用SenderServiceStarter运行Service发送的报告。
ApplicationStartupProcessor
封装一些App启动时可能执行的任务
ReportLocator
关于ACRA对日志文件位置的处理主要是ReportLocator来设置的。
acra内部使用文件对崩溃日志进行保存,该类用来获取文件夹的名字。
内部有两个文件夹acra-unapproved(未处理),acra-approved(处理过)分别用来保存未处理及处理过的崩溃文件。
采集内容
崩溃采集,必然需要采集崩溃及手机的相关信息。
ACRA中涉及到崩溃相关信息的主要有如下一些类。
ReportBuilder,ReportPrimer,CrashReportDataFactory,CrashReportData,
LogCatCollector,DropBoxCollector,ReportUtils,UUID,
Installation,ConfigurationCollector,DumpSysCollector,ReflectionCollector,
DisplayManagerCollector,DeviceFeaturesCollector,settingsCollector,
LogFileCollector,MediaCodecListCollector,ThreadCollector.
ACRA获取全部数据,涉及到的类比较多。下面逐个分析。
ReportBuilder
对throwable,message,自定义信息,以及exception的简单封装。
主要方法为build(),通过build方法调用ReportExecutor.execute()方法,
在ReportExcutor中进行真正的crash采集以及调用发送Service
ReportPrimer
用来设置崩溃时候,用户需要保存的一些用户自定义的信息。
比如崩溃时候在此类中设置一些用户账号等相关信息。
该类中设置的相关内容会一起发送到服务端,从而更好的定位一些崩溃信息。
CrashReportDataFactory,CrashReportData
CrashReportDataFactory类用来实例化CrashReportData。
其中最重要的方法为createCrashData()方法,使用该方法来组拼CrashReportData。
CrashReportData继承EnumMap,其中保存的数据的key为各种上传时候的key,
对应的值为崩溃的相关信息。后面的流程中该类中的值会通过CrashReportPersister类写入file文件。
LogCatCollector
用来获取logcat日志中的相关信息,执行Logcat命令,读取命令输出信息。
其实相信大部分人不太清楚logcat的相关命令。
针对以上的三条命令做如下解释
DropBoxCollector
通过DropBoxManager读取系统系统的日志信息
DropBoxManager,很多人应该也没接触过。
android系统实际上是有三种日志打印的。log EventLog DropBox,关于三种log的介绍参见此处。
三种log的介绍
关于DropBoxManager的相关内容可以参见此处。dropboxManager介绍
ReportUtils
封装的各种工具类,用来获取系统相关的信息
UUID
java.util包中提供的类,用来生成唯一字符串的类。
Installation
用来生成唯一身份串的类。
ConfigurationCollector
通过反射系统的Configuration类,获取系统相关参数。
DumpSysCollector
通过执行dumpsys meminfo xxxpid 来分析内存
关于dumpsys的介绍参见此:dumsys相关介绍
ReflectionCollector
相当于Util类,主要通过反射获取传过来的类的一些信息。
DisplayManagerCollector
主要用来获取手机显示相关的数据
DeviceFeaturesCollector
通过PackageManager获取系统相关特性。比如glEsVersion等
SettingsCollector
使用反射获取android.provider.Settings.x中的相关内容。
LogFileCollector
获取用户自己保存的相关的log文件,使用该接口可以让acra结合logback-android这类类库相结合。
很多做android的同学都没有做过java web开发,并且android的Log接口也还算好用,再加上客户端编程和服务端编程系统的不同,所以可能理解不了logback-android这样库的意义。
实际上logback-android这类库主要就是可以指定log输出的位置,以及log的打印级别。
关于java开发中log的重要性可以参见此文章,java log的意义
MediaCodecListCollector
主要用来获取系统支持哪些音视频类型等媒体相关的。
ThreadCollector
获取崩溃线程的相关信息。
ACRA中用到的其他一些获取异常的方法
结语
本部分内容主要包括
后面的部分会继续分析如何将生成的file发送到服务端。
Acra是老牌的bug自动采集系统。接入sdk后,可以实现程序崩溃自动发送崩溃日志。
发送自定义的错误日志等功能。具体详细介绍可以参见acra官网地址。
整体来看,Acra就是通过sdk收集进程的崩溃日志,然后以http或mail(默认的两类Sender)的方式将数据发送出去。服务器则是一套基于json的restful的接口。
服务端方面不是本次分析重点,暂不进行分析。
本系列文章将基于Acra 4.9.0 RC2源码进行分析。
Backend
服务端方面我们需要先搭建一个server,才能更好的看到我们的崩溃信息,
更直观的看到acra给我们提供了哪些针对崩溃的采集内容。
官方提供了acralyzer以及一些针对acra的第三方开源实现。
关于世面上常用的server端的,该文章做了明确分析,针对不同backend的比较。
官方backend acralyzer的搭建非常简单,具体可以参见该文章的server配置部分。
项目搭建完成后可以使用通过如下的url对server端进行访问。
查看app崩溃的表结构
http://ip:port/_utils/
查看崩溃日志
http://ip:port/acralyzer/_design/acralyzer/index.html#/dashboard/
关于server端的介绍结束。不是重点。
Client
项目构建
最新版本项目基于Gradle构建,了解Acra历史的肯定知道该项目是存在了很久了.
Android世界中项目最早是基于ant构建,后来是maven,现在是Gradle。
在没有Gradle的编译环境之前,基本上大部分是基于maven构建。
查看最新版本的代码可以看到仍然包含了之前maven的配置文件。
并且使用Gradle编译编译中使用到的version name等配置参数也都是从pom.xml中读取的。
具体可以参看build.gradle中关于版本号的相关配置。
需要注意的是,从github clone下来的项目是无法直接使用Gradle进行编译的。
熟悉Gradle android 编译流程的人应该从build.gradle文件中可以找出错误的原因。
具体的编译文件需要修改的地方为,在build.gradle中开头位置添加编译android项目使用到的plugin。
如下所示:
//此部分添加到build.gradle开头 buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.1.0' } } allprojects { repositories { jcenter() } } task clean(type: Delete) { delete rootProject.buildDir } //此部分添加到build.gradle开头
添加之后,就可以执行gradle build命令打出需要使用的aar包。
项目配置及使用
首先需要注意一点,Acra使用独立进程:acra,进行采集数据的发送,保证当app崩溃时,采集仍然能发送出去。
由于使用独立的进程,所以会导致application被实例化多次,这样就需要注意app自身的某些业务逻辑,不要在application类中执行多次,从而导致app产生bug。
对Acra的相关配置一般在application中进行初始化。
初始化配置
在application中进行初始化配置。
使用注解初始化
import org.acra.*; import org.acra.annotation.*; @ReportsCrashes( formUri = "http://www.backendofyourchoice.com/reportpath" ) public class MyApplication extends Application { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); // 调用init方法,对acra进行初始化. ACRA.init(this); } }
动态初始化配置
import org.acra.ACRA; import org.acra.configuration.*; public class MyApplication extends Application { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); //使用ConfigurationBuilder构建ACRAConfirueation final ACRAConfiguration config = new ConfigurationBuilder(this) .setFoo(foo) .setBar(bar) .build(); // 传参的方式初始化acra ACRA.init(this, config); } }
一般使用acra我们的目的是采集崩溃,所以需要在manifest中申请网络权限,以保证crash的正常发送。
<uses-permission android:name="android.permission.INTERNET"/>
目标服务器配置
acra中发送crash数据是通过Sender实现的,Sender是通过ReportSenderFactory实例化出来的。
而ReportSenderFactory是可以在初始化时进行配置的。
acra默认提供了email及http 两种sender。
如果自定义Sender则需要两个步骤,
- 实现ReportSender接口,用来执行发送报告操作。
- 实现ReportSenderFactory接口,用来创建自定义sender。
public class YourOwnSender implements ReportSender { @Override public void send(Context context, CrashReportData report) throws ReportSenderException { // 遍历 CrashReportData 并做发送操作 } } public class YourOwnSenderfactory implements ReportSenderFactory { // 由于在SenderService中通过Class.newInstance()来实例化对象 // 所以需要保证实例化的类的构造函数有一个默认无参的构造函数 // 自定义的ReportSenderFactory必须包含一个不含参数的构造函数 public ReportSender create(Context context, ACRAConfiguration config) { ... return new YourOwnSender(someConfigPerhaps); } }
针对Sender的配置有两种形式,一种为注解,一种为通过代码进行设置。
//注解的方式设置Sender @ReportCrashes{ reportSenderFactoryClasses = { your.funky.ReportSenderFactory.class, other.funky.ReportSenderFactory.class } } public class YourApplication extends Application { ... } //代码的方式设置Sender @ReportCrashes{ ... } public class YourApplication extends Application { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); final Class<? extends ReportSenderFactory>[] myReportSenderFactoryClasses = ... // 初始化一个ConfigurationBuilder,并设置ReportSenderFactoryClasses. final ACRAConfiguration config = new ConfigurationBuilder(this) .setReportSenderFactoryClasses(myReportSenderFactoryClasses) .build(); ACRA.init(this, config); } }
Acra中默认提供两个Sender
HttpSender
提供了Post及Put两种提交crash到服务器的方式。
提交的类型可以为JSON或Form表单两种方式。
建议使用Put方式进行提交。 Put可以理解成已经知道了某个资源的位置.代表直接更新或创建该资源。 POST为不知道某个资源的位置,由server端来决定对该资源进行何种方式的存储。 所以在此场景下使用Put操作更合适,因为每一条bug实际上就应该对应与数据库中的一条, 只是该条记录还没有上传到服务器。 关于post与put的差别,具体可以查看该文档when should use PUT and when should use POST
EmailIntentSender
组拼crash Report 通过intent调用系统提供的发送email的app。
流程分析及重点类分析
初始化设置流程
Acra的初始化函数为init,所以使用入口函数ACRA.init()对acra进行初始化。
一般入口函数在application初始化时进行调用。
ACRA.init()
使用ReportsCrashes来初始化Acra。
ACRA提供多个init方法,经过内部调用,最终都会调用参数最多的init方法完成初始化相关逻辑。
下面对重要的init方法进行说明
class ACRA { //使用Application的注解进行初始化 public static void init(Application app){ //获取application上的注解 final ReportsCrashes reportsCrashes = app.getClass().getAnnotation(ReportsCrashes.class); //ConfigurationBuilder中通过注解获取application上配置的注解信息 init(app, new ConfigurationBuilder(app).build()); } //参数 checkReportsOnApplicationStart 表示 //是否立即执行ErrorReporter.checkReportsOnApplicationStart()方法 public static void init(Application app, ACRAConfiguration config, boolean checkReportsOnApplicationStart){ //根据process的名字判断执行当前方法执行时所在的进程是否是发送crash的进程 final boolean senderServiceProcess = isACRASenderServiceProcess(app); //ACRA只支持2.3以上的系统版本,所以预先做判断 final boolean supportedAndroidVersion = Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO; //保存config configProxy = config; //获取ACRA保存配置的SharedPreferences final SharedPreferences prefs = new SharedPreferencesFactory(mApplication, configProxy).create(); if (!prefs.getBoolean(PREF__LEGACY_ALREADY_CONVERTED_TO_4_8_0, false)) { //处理之前的版本的日志文件 } errorReporterSingleton = new ErrorReporter(mApplication, configProxy, prefs, enableAcra, supportedAndroidVersion, !senderServiceProcess); //当在非Sender进程,并设置app启动时发送report的情况下进行检测。 //当在Sender进程中,不需要进行检测,因为Sender进程中的逻辑自己会进行判断处理 if (checkReportsOnApplicationStart && !senderServiceProcess) { //执行发送的相关业务逻辑 final ApplicationStartupProcessor startupProcessor = new ApplicationStartupProcessor(mApplication, config); if (config.deleteOldUnsentReportsOnApplicationStart()) { startupProcessor.deleteUnsentReportsFromOldAppVersion(); } if (config.deleteUnapprovedReportsOnApplicationStart()) { startupProcessor.deleteAllUnapprovedReportsBarOne(); } if (enableAcra) { startupProcessor.sendApprovedReports(); } } } }
ConfigurationBuilder
主要用来封装构造ACRAConfiguration的相关属性。
提供了两种方式来设置相关属性的值。
- 构造函数通过注解的方式,获取Application中定义注解的值,进行设置。
- 通过set方法,设置每个不同的配置项。
获取属性值之后,通过调用build()方法,创建ACRAConfiguration对象。
//通过app的注解所配置的值对builder对象本身进行初始化 public ConfigurationBuilder(@NonNull Application app) { //..... } //构建ACRAConfiguration对象 public ACRAConfiguration build() { return new ACRAConfiguration(this); } .... //对外提供的设置相关属性的方法 public ConfigurationBuilder setHttpHeaders(@NonNull Map<String, String> headers) { this.httpHeaders.clear(); this.httpHeaders.putAll(headers); return this; }
ACRAConfiguration
用来保存ACRA涉及到的所有配置。
SharedPreferencesFactory
用来获取ACRA所使用的SharedPreferences的文件。
通过这层封装可以对sp进行一些自定义的设置,比如sp的名字。
public class SharedPreferencesFactory { //获取默认sharedPreferences的流程为 //1.如果通过builder或ReportsCrashes配置所构建的类生成的config文件, // 包含sp相关配置,则使用该配置项。 //2.如果不满足1的条件,则通过android api PreferenceManager返回默认的sp文件 public SharedPreferences create() { if (context == null) { //.. } else if (!"".equals(config.sharedPreferencesName())) { return context.getSharedPreferences( config.sharedPreferencesName(), config.sharedPreferencesMode() ); } else { return PreferenceManager.getDefaultSharedPreferences(context); } } }
ErrorReporter
ACRA最核心的类,该类用来捕获crash相关的信息,以及发送crash信息。
Android平台如果想要捕获java层代码的crash需要设置application Thread的UncaughtExceptionHandler。
ACRA会将ErrorReporter设置为Application Thread的UncaughtExceptionHandler。
从而实现对异常的捕获。
这里有一点需要注意的,Thread中的defaultUncaughtHandler为一个对象, 所以多次设置该属性,则会使用最后一个作为异常捕获的类。 比如现在市面上比较火的umeng等相关包含崩溃采集功能sdk。 使用的时候,需要注意查看文档或反编译其源码,查看sdk是怎么实现该部分功能的。 否则容易造成先设置的异常捕获类,无法被执行。
public class ErrorReporter implements Thread.UncaughtExceptionHandler { ErrorReporter( @NonNull Application context, @NonNull ACRAConfiguration config, @NonNull SharedPreferences prefs,boolean enabled, boolean supportedAndroidVersion, boolean listenForUncaughtExceptions) { ... //通过ConfigurationCollector获取系统的相关环境信息 if (config.getReportFields().contains(ReportField.INITIAL_CONFIGURATION)) { initialConfiguration = ConfigurationCollector.collectConfiguration(this.context); } else { initialConfiguration = null; } //获取系统时间,崩溃发生时上传 final Calendar appStartDate = new GregorianCalendar(); crashReportDataFactory = new CrashReportDataFactory( this.context, config, prefs, appStartDate, initialConfiguration); final Thread.UncaughtExceptionHandler defaultExceptionHandler; //listenForUncaughtExceptions为Acra初始化流程中传过来的。 //如果当前运行的进程是Sender进程则不监听崩溃。 //如果当前运行的进程是app主进程则对崩溃进行监听 if (listenForUncaughtExceptions) { defaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler(this); } else { defaultExceptionHandler = null; } //记录最后的activity final LastActivityManager lastActivityManager = new LastActivityManager(this.context); //用来保存针对崩溃的一些用户自定义的信息 final ReportPrimer reportPrimer = getReportPrimer(config); reportExecutor = new ReportExecutor( context, config, crashReportDataFactory, lastActivityManager, defaultExceptionHandler, reportPrimer); reportExecutor.setEnabled(enabled); } //崩溃采集需要实现UncaughtExceptionHandler为接口。 @Override public void uncaughtException(@Nullable Thread t, @NonNull Throwable e) { //未开启crash采集时,使用之前默认的ExceptionHandler处理 if (!reportExecutor.isEnabled()) { reportExecutor.handReportToDefaultExceptionHandler(t, e); return; } try { ACRA.log.e(LOG_TAG, "ACRA caught a " + e.getClass().getSimpleName() + " for " + context.getPackageName(), e); if (ACRA.DEV_LOGGING) ACRA.log.d(LOG_TAG, "Building report"); performDeprecatedReportPriming(); // 生成并发送report new ReportBuilder() .uncaughtExceptionThread(t) .exception(e) .endApplication() .build(reportExecutor); } catch (Throwable fatality) { // ACRA failed. Prevent any recursive call to ACRA.uncaughtException(), let the native reporter do its job. ACRA.log.e(LOG_TAG, "ACRA failed to capture the error - handing off to native error reporter" , fatality); reportExecutor.handReportToDefaultExceptionHandler(t, e); } } }
参见代码可以知道,acra通过设置默认ExceptionHandler来捕获异常。
并把自己设置为处理对象。
LastActivityManager
是用来记录最后展示的Activity的,通过application.registerActivityLifecycleCallbacks来实现记录功能的。ACRA可以在崩溃的时候弹出Dialog,所以需要记住最后的Activity。
ReportExecutor
主要业务逻辑关注execute()方法.
该类主要负责调用CrashReportDataFactory采集数据,
调用CrashReportPersister对崩溃数据进行持久化,
调用SenderServiceStarter运行Service发送的报告。
ApplicationStartupProcessor
封装一些App启动时可能执行的任务
class ApplicationStartupProcessor{ void deleteUnsentReportsFromOldAppVersion(){ //app版本更新后,一般会修掉老的崩溃等问题, //所以当老版本更新到新版本后,可以将老版本记录的日志全部删除掉 } void deleteAllUnapprovedReportsBarOne(){ //unapproved的文件夹内的文件,只保留最新创建的日志文件,其他的全部删除掉。 } void sendApprovedReports(){ //调用SenderServiceStarter开启Service进行崩溃日志的发送。 } }
ReportLocator
关于ACRA对日志文件位置的处理主要是ReportLocator来设置的。
acra内部使用文件对崩溃日志进行保存,该类用来获取文件夹的名字。
内部有两个文件夹acra-unapproved(未处理),acra-approved(处理过)分别用来保存未处理及处理过的崩溃文件。
采集内容
崩溃采集,必然需要采集崩溃及手机的相关信息。
ACRA中涉及到崩溃相关信息的主要有如下一些类。
ReportBuilder,ReportPrimer,CrashReportDataFactory,CrashReportData,
LogCatCollector,DropBoxCollector,ReportUtils,UUID,
Installation,ConfigurationCollector,DumpSysCollector,ReflectionCollector,
DisplayManagerCollector,DeviceFeaturesCollector,settingsCollector,
LogFileCollector,MediaCodecListCollector,ThreadCollector.
ACRA获取全部数据,涉及到的类比较多。下面逐个分析。
ReportBuilder
对throwable,message,自定义信息,以及exception的简单封装。
主要方法为build(),通过build方法调用ReportExecutor.execute()方法,
在ReportExcutor中进行真正的crash采集以及调用发送Service
ReportPrimer
用来设置崩溃时候,用户需要保存的一些用户自定义的信息。
比如崩溃时候在此类中设置一些用户账号等相关信息。
该类中设置的相关内容会一起发送到服务端,从而更好的定位一些崩溃信息。
CrashReportDataFactory,CrashReportData
CrashReportDataFactory类用来实例化CrashReportData。
其中最重要的方法为createCrashData()方法,使用该方法来组拼CrashReportData。
CrashReportData继承EnumMap,其中保存的数据的key为各种上传时候的key,
对应的值为崩溃的相关信息。后面的流程中该类中的值会通过CrashReportPersister类写入file文件。
LogCatCollector
用来获取logcat日志中的相关信息,执行Logcat命令,读取命令输出信息。
class LogCatCollector{ public String collectLogCat(){ //根据所传参数不同组拼不同的logcat命令 //主要组拼出的命令为 //1.logcat -t 100 -v time //2.logcat -t 100 -v time -b radio //1.logcat -t 100 -v time -b events } }
logcat -b events 05-18 19:45:46.158 31191 31191 I auditd : type=1400 audit(0.0:505001): avc: denied { search } for comm="PerfFgMonitor" name="1711" dev="proc" ino=18618 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:r:radio:s0 tclass=dir permissive=0 logcat -b radio 05-18 19:44:39.343 1711 1785 D RILJ : [9679]< RIL_REQUEST_GET_CELL_INFO_LIST [CellInfoWcdma:{mRegistered=YES mTimeStampType=oem_ril mTimeStamp=1283159923921792ns CellIdentityWcdma:{ mMcc=460 mMnc=1 mLac=53529 mCid=101852154 mPsc=438} CellSignalStrengthWcdma: ss=8 ber=99}] [SUB0] 05-18 19:44:39.345 1711 1975 D GsmSST : [GsmSST] SST.getAllCellInfo(): X size=1 list=[CellInfoWcdma:{mRegistered=YES mTimeStampType=oem_ril mTimeStamp=1283159923921792ns CellIdentityWcdma:{ mMcc=460 mMnc=1 mLac=53529 mCid=101852154 mPsc=438} CellSignalStrengthWcdma: ss=8 ber=99}] 05-18 19:44:39.346 1711 1975 D GsmSST : [GsmSST] getCellLocation(): X ret WCDMA info=[53529,101852154,438] 05-18 19:44:43.068 1711 1927 D SubscriptionController: [getPhoneId]- no sims, returning default phoneId=2147483647
其实相信大部分人不太清楚logcat的相关命令。
针对以上的三条命令做如下解释
logcat -t 100 -v time -t 限制打印100行内容 -v time 设置日志输出格式。打印日志的为:打印日期->触发时间->优先级(E,W,V)->tag->出问题进程的pid 关于日志输出格式的介绍参见此处日志输出格式。 logcat -b [options] 切换打印log的内容级别 radio radio/telephony相关log events events-related相关log main 默认的log
DropBoxCollector
通过DropBoxManager读取系统系统的日志信息
DropBoxManager,很多人应该也没接触过。
android系统实际上是有三种日志打印的。log EventLog DropBox,关于三种log的介绍参见此处。
三种log的介绍
关于DropBoxManager的相关内容可以参见此处。dropboxManager介绍
class DropBoxCollector{ public String read(){ //通过DropBoxService获取系统的DropBoxManager //读取所有预先定义的不同tag对应的日志内容 } }
ReportUtils
封装的各种工具类,用来获取系统相关的信息
public getAvailableInternalMemorySize(){ //通过StatFs类获取可用内存block数量及每个block的size //block_size * free_block_count = 可用内存数 } public getTotalInternalMemorySize(){ //通过StatFs类获取所有内存block数量及每个block的size //block_size * total_block_count = 总内存数 } public getDeviceId(){ //通过TelephonyManager获取deviceId //GSM手机对应与IMEI //CDMA手机对应与ESN或MEID } public getApplicationFilePath(){ //通过context.getFilesDir()获取当前app的绝对路径 //'/data/user/0/yftx.net.oschina.git.gradlesample/files' } public getLocalIpAddress(){ //通过NetworkInterface 获取当前设备的ip } public getTimeString(){ //通过Calendar类获取当前时间 }
UUID
java.util包中提供的类,用来生成唯一字符串的类。
Installation
用来生成唯一身份串的类。
class Installation{ void id(){ //获取的id用来标记用户的身份。 //具体算法可以参见android blog中的解释。 //http://android-developers.blogspot.com/2011/03/identifying-app-installations.html } }
ConfigurationCollector
通过反射系统的Configuration类,获取系统相关参数。
class ConfigurationCollector{ void collectConfiguration(Context context){ //通过 context.getResources().getConfiguration()获取configration对象, //并用反射获取该类中的相关信息 } }
DumpSysCollector
通过执行dumpsys meminfo xxxpid 来分析内存
关于dumpsys的介绍参见此:dumsys相关介绍
class DumpSysCollector{ void collectMemInfo(){ //执行dumsys 相关命令 } }
ReflectionCollector
相当于Util类,主要通过反射获取传过来的类的一些信息。
class ReflectionCollector{ void collectConstants(){ //通过反射获取系统的相关信息 //acra中主要获取Build,Build.Version中的相关数据 } }
DisplayManagerCollector
主要用来获取手机显示相关的数据
class DisplayManagerCollector{ void collectDisplays(){ //通过Display类获取屏幕宽,高,方向等显示相关的参数 } }
DeviceFeaturesCollector
通过PackageManager获取系统相关特性。比如glEsVersion等
class DeviceFeaturesCollector{ void getFeatures(){ //通过PackageManager获取系统相关特性。比如glEsVersion等 } }
SettingsCollector
使用反射获取android.provider.Settings.x中的相关内容。
class SettingsCollector{ void collectSystemSettings(){ //获取系统Settings类中的相关信息 } void collectSecureSettings(){ //获取Settings.Secure中的相关信息 } void collectGlobalSettings(){ //获取Settings.Global中的相关信息 } }
LogFileCollector
获取用户自己保存的相关的log文件,使用该接口可以让acra结合logback-android这类类库相结合。
很多做android的同学都没有做过java web开发,并且android的Log接口也还算好用,再加上客户端编程和服务端编程系统的不同,所以可能理解不了logback-android这样库的意义。
实际上logback-android这类库主要就是可以指定log输出的位置,以及log的打印级别。
关于java开发中log的重要性可以参见此文章,java log的意义
MediaCodecListCollector
主要用来获取系统支持哪些音视频类型等媒体相关的。
ThreadCollector
获取崩溃线程的相关信息。
class ThreadCollector{ void collect(Thread t){ //获取线程t的相关信息,id,name,priority,groupName } }
ACRA中用到的其他一些获取异常的方法
getStackTracehash(Throwable th){ //通过组拼Error的className及MethodName生成的字符串 //获取该字符串的hash值 //服务端可以根据该值做崩溃分类 }
结语
本部分内容主要包括
- ACRA如何配置(服务端,客户端的配置)
- 崩溃信息相关内容如何采集,涉及到的关键类。
后面的部分会继续分析如何将生成的file发送到服务端。
发表评论
-
带你深入理解 FLUTTER 中的字体“冷”知识
2020-08-10 23:40 626本篇将带你深入理解 Flutter 开发过程中关于字体和文 ... -
Flutter -自定义日历组件
2020-03-01 17:56 1099颜色文件和屏幕适配的文件 可以自己给定 import ... -
Dart高级(一)——泛型与Json To Bean
2020-02-23 19:13 989从 Flutter 发布到现在, 越来越多人开始尝试使用 Da ... -
flutter loading、Progress进度条
2020-02-21 17:03 1166Flutter Progress 1 条形无固定值进度条 ... -
Flutter使用Https加载图片
2020-02-21 01:39 1003Flutter使用Https加载图片 使用http加载图片出 ... -
flutter shared_preferences 异步变同步
2020-02-21 00:55 838前言 引用 在开发原生iOS或Native应用时,一般有判断上 ... -
Flutter TextField边框颜色
2020-02-19 21:31 924监听要销毁 myController.dispose(); T ... -
flutter Future的正确用法
2020-02-18 21:55 799在flutter中经常会用到异步任务,dart中异步任务异步处 ... -
记一次Flutter简单粗暴处理HTTPS证书检验方法
2020-02-18 14:13 948最近在做Flutter项目到了遇到一个无解的事情,当使用Ima ... -
flutter 获取屏幕宽度高度 通知栏高度等屏幕信息
2019-07-27 08:39 1326##MediaQuery MediaQuery.of(con ... -
关于flutter RefreshIndicator扩展listview下拉刷新的问题
2019-07-10 19:40 1110当条目过少时listview某些嵌套情况下可能不会滚动(条目 ... -
flutter listview 改变状态的时候一直无限添加
2019-07-10 16:01 773setstate的时候会一直无限的调用listview.bui ... -
Flutter Android端启动白屏问题的解决
2019-07-09 00:51 1505问题描述 Flutter 应用在 Android 端上启动时 ... -
Flutter中SnackBar使用
2019-07-08 23:43 765底部弹出,然后在指定时间后消失。 注意: build(Bui ... -
Flutter 之点击空白区域收起键盘
2019-07-08 18:43 1780点击空白处取消TextField焦点这个需求是非常简单的,在学 ... -
Flutter 弹窗 Dialog ,AlertDialog,IOS风格
2019-07-08 18:04 1369import 'package:flutter/mate ... -
flutter ---TextField 之 输入类型、长度限制
2019-07-08 14:30 2313TextField想要实现输入类型、长度限制需要先引入impo ... -
【flutter 溢出BUG】键盘上显示bottom overflowed by 104 PIXELS
2019-07-08 11:13 1542一开始直接使用Scaffold布局,body:new Colu ... -
解决Flutter项目卡在Initializing gradle...界面的问题
2019-07-07 12:53 864Flutter最近很火,我抽出了一点时间对Flutter进行了 ... -
关于android O 上 NotificationChannel 的一些注意事项
2019-07-04 11:47 931最近在适配android O,遇到个问题,应用中原本有设置界面 ...
相关推荐
通常,开发者需要配合使用日志分析工具(如Sentry、Loggly等)来解析Go-acra-go发送的崩溃报告,便于进行错误排查和修复。 8. **测试与调试**: 在开发过程中,可以利用模拟器或真机进行测试,触发异常以检查Go-...
ACRA不仅简化了崩溃报告的获取过程,还提供了详细的报告分析,使得问题排查更加高效。 ACRA的工作流程大致如下:当应用发生未捕获的异常导致崩溃时,ACRA会自动捕获这个异常信息,包括异常类型、堆栈轨迹、设备信息...
首先,让我们详细了解一下`acra`框架。`acra`不仅提供了崩溃日志的自动收集,还支持自定义报告字段、非致命异常处理以及多种发送报告的方式(如HTTP、HTTPS、FTP等)。在Android项目中,你可以通过Gradle或Maven依赖...
配置完成后,当应用发生崩溃时,ACRA会自动生成一个包含详细错误信息的报告,并尝试通过电子邮件发送。报告通常包含以下内容: 1. **崩溃时的堆栈跟踪**:这是最重要的部分,它显示了导致应用崩溃的具体代码行和...
《Android应用崩溃报告工具Acra深度解析》 在Android应用开发过程中,确保应用的稳定性和可靠性至关重要。而当应用出现异常或崩溃时,能够及时、准确地获取到错误信息是定位问题的关键。这就是Acra(Android Crash ...
- **处理报告**:配置服务器端接收和解析ACRA发送的报告,进行错误分析和修复。 4. **ACRA报告内容**: - **堆栈跟踪**:包含导致应用崩溃的异常堆栈信息。 - **设备信息**:如设备型号、Android版本、屏幕...
《ACRA 源码分析与理解》 ACRA(Android Crash Report Analyzer)是Google推出的一款用于Android应用崩溃报告分析的工具。它可以帮助开发者收集、分析以及报告应用程序在运行时出现的异常信息,从而帮助我们定位和...
通常,ACRA可能指的是Android Crash Report Analyzer,这是一个用于分析Android应用崩溃报告的工具。但是,由于提供的信息有限,无法确定这是否是相关的情境。而PDF文件可能是报告、文档或教程,但具体内容未知。 ...
《安卓Android源码解析——acra-master.zip》 在安卓应用开发领域,深入理解源码是提升技术能力的重要途径。本篇文章将聚焦于"acra-master.zip"这一压缩包,探讨其中包含的Android源码,主要关注其在错误报告、崩溃...
KAM500系统是由AcRa公司开发的一款专为航空测试领域设计的先进系统。该系统集成了多种功能和技术,旨在提供高性能、高可靠性的测试解决方案。下面将详细介绍KAM500系统的各个组成部分及其在航空测试中的应用。 ####...
通过集成ACRA,开发者可以获取详细的崩溃日志,包括设备信息、堆栈跟踪以及用户环境等,从而更好地诊断和修复问题。ACRA后端则负责接收和管理这些崩溃报告,提供了一个集中化的错误处理中心。 在构建ACRA后端时,...
在Android开发中,自动收集和提交应用崩溃报告是一项重要的任务,它可以帮助...通过阅读和理解这个源码,开发者不仅可以学习如何集成acra,还可以深入理解Android异常处理机制以及如何有效地收集和分析应用的崩溃数据。
ACRA是Google提供的一款用于收集、报告和分析Android应用崩溃信息的工具,对于理解和实现Android应用的异常处理非常有帮助。 ACRA的核心功能包括: 1. **全局异常捕获**:ACRA可以全局地捕获应用中的未处理异常,...
7. **第三方日志库**:有些开发者选择使用如` Timber `或`ACRA `这样的第三方日志库,它们提供了更高级的功能,如日志分类、异步日志记录、崩溃报告和日志上传服务器等。 8. **调试技巧**:除了Logcat,还可以结合...
本篇文章将详细讲解如何在Android系统中实现异常捕获,并结合写文件和发送邮件功能,将捕获到的错误信息进行记录和报告。 首先,我们需要了解Android中的异常处理机制。在Java语言中,异常处理通常通过try-catch-...
它们按照严重程度递增,通常在开发阶段使用较详细的`DEBUG`和`VERBOSE`,而在发布版本中则限制为`INFO`或更高。学会合理选择日志级别,既能帮助调试,又不会泄露过多敏感信息。 2. **使用Logcat工具** `Logcat`是...
6. **审计与日志记录**: AcraNetwork可能还提供详细的审计日志,帮助监控和分析系统的安全事件。 在压缩包中,"使用说明.txt"文件应该是对如何部署和配置AcraNetwork的详细指南。按照这份说明,你可以了解如何设置...
以下将围绕该源码进行详细的解析与讨论。 首先,易读阅读器的源码展示了如何在Android平台上构建一个用户友好的界面。Android SDK提供了丰富的UI组件,如TextView、EditText和RecyclerView等,这些在阅读器中都得到...
本文将详细讲解如何在Android系统中进行异常日志的捕获、记录以及分析,以便优化和调试应用程序。 首先,Android系统提供了一个内置的日志系统,称为Log类,位于`android.util`包下。Log类提供了多种方法,如`Log.v...
5. **ACRA公司技术手册**:爱尔兰ACRA公司的数据采集系统技术手册可能提供了实践经验和技术细节,对于设计新型数据采集插件有重要参考价值。 6. **误差分析与校准**:在设计过程中,如何减少测量误差和进行系统校准...