作者:lds(lds2012@gmail.com)
日期:2017-03-24
一. 項(xiàng)目簡(jiǎn)介
ACRA是Google推出的開源Android應(yīng)用Crash reports框架。本文主要針對(duì)其最新的源碼(v4.9.2)進(jìn)行學(xué)習(xí)研究移怯,目的是了解在Android平臺(tái)上處理未捕獲異常,并在崩潰時(shí)收集各種設(shè)備及上下文信息,并生成崩潰報(bào)告肉渴,保存到本地文件柔滔,并使用合適的機(jī)制將所有的崩潰報(bào)告上報(bào)給服務(wù)器等一整套開源解決方案泡徙。
項(xiàng)目主頁及源碼:https://github.com/ACRA/acra
二. 模塊及關(guān)鍵類
模塊劃分及關(guān)鍵類說明
package | class | |
---|---|---|
org.acra | ACRA | 入口 |
ErrorReporter | 異常處理器 | |
org.acra.builder | ReportBuilder | 異常報(bào)告構(gòu)建器 |
ReportExecutor | 異常報(bào)告執(zhí)行器 | |
org.acra.collector | CrashReportDataFactory | 異常報(bào)告收集數(shù)據(jù)工廠 |
org.acra.config | ACRAConfiguration | ACRA配置 |
org.acra.collections | - | 集合類 |
org.acra.dialog | CrashReportDialog | 崩潰Dialog |
org.acra.file | ReportLocator | 報(bào)告文件定位 |
org.acra.http | DefaultHttpRequest | HTTP網(wǎng)絡(luò)請(qǐng)求 |
org.acra.legacy | LegacyFileHandler | 傳統(tǒng)舊文件升級(jí)處理器 |
org.acra.log | ACRALog | 日志接口 |
org.acra.model | Element | 日志報(bào)告字段元素 |
org.acra.prefs | SharedPreferencesFactory | Pref工廠 |
org.acra.security | KeyStoreHelper | https KeyStore幫助類 |
org.acra.sender | ReportSender | 異常報(bào)告發(fā)送器接口 |
org.acra.util | - | 工具類 |
三. ACRA類
首先看如何初始化ACRA:
public static void init(Application app, ACRAConfiguration config, boolean checkReportsOnApplicationStart);
參數(shù):
- application:應(yīng)用實(shí)例该肴,這個(gè)實(shí)例會(huì)被ACRA以靜態(tài)變量hold住葛假,看起來會(huì)有內(nèi)存泄漏問題障陶,但其實(shí)沒問題。
- config:自定義配置
- checkReportsOnApplicationStart:是否在應(yīng)用啟動(dòng)的時(shí)候檢查并上傳報(bào)告桐款。
具體的異常處理都是由 ErrorReportor
來處理的咸这,并以靜態(tài)變量被ACRA hold住,保證其生命周期和application一致魔眨。它其實(shí)是一個(gè) Thread.UncaughtExceptionHandler
, 可以捕獲到未捕捉的異常媳维。
在初始化的時(shí)候,為了兼容舊版本的報(bào)告文件遏暴,提供了一個(gè)將舊版本文件升級(jí)到新版本文件的機(jī)制侄刽。
并且提供配置,允許在啟動(dòng)的時(shí)候刪除舊應(yīng)用版本遺留下來的舊異常報(bào)告文件朋凉。(升級(jí)app后眨补,之前版本遺留下來的文件被視為舊文件。)
也提供選項(xiàng)珍昨,允許在啟動(dòng)的時(shí)候刪除所有不合法的報(bào)告文件木蹬。
在啟動(dòng)的時(shí)候,也會(huì)上傳所有合法的異常報(bào)告文件亲怠。注意使用了獨(dú)立的線程里的Service進(jìn)行發(fā)送操作所计,以實(shí)現(xiàn)和應(yīng)用主進(jìn)程進(jìn)行隔離區(qū)分。
四. 捕捉崩潰(ErrorReporter)
ErrorReporter實(shí)現(xiàn)了Thread.UncaughtExceptionHandler接口团秽,并自己注冊(cè)到應(yīng)用主線程上主胧,它是一個(gè)單例對(duì)象,用于手機(jī)崩潰上下文數(shù)據(jù)习勤,并發(fā)送崩潰報(bào)告踪栋。
當(dāng)崩潰發(fā)生時(shí),它收集崩潰時(shí)的上下文數(shù)據(jù)(例如設(shè)備图毕,系統(tǒng)夷都,崩潰stack trace等信息),并將其寫入應(yīng)用私有目錄(/data/data/packageName) 下的一個(gè)崩潰報(bào)告文件中予颤。
這個(gè)崩潰報(bào)告文件會(huì)被發(fā)送的時(shí)機(jī)由:
- 如果崩潰配置為silent模式或toast模式损肛,崩潰報(bào)告文件會(huì)立即被發(fā)送
- 每次程序啟動(dòng)的時(shí)候,上一次沒有被發(fā)送則被發(fā)送
- 如果崩潰配置為notification荣瑟,則會(huì)彈出對(duì)話框治拿,用戶點(diǎn)擊發(fā)送才會(huì)被發(fā)送。
首先會(huì)收集收集的 Configuration 數(shù)據(jù)笆焰,這個(gè)數(shù)據(jù)收集起來消耗比較大劫谅,因此只有當(dāng)準(zhǔn)備report的時(shí)候才進(jìn)行收集。
所有的崩潰報(bào)告都是由各種不同的收集器來收集起來的,然后通過 CrashReport DataFactory
報(bào)告工廠來生成報(bào)告捏检。
在設(shè)置新的 Thread uncaught Exception Handler 之類荞驴,先保存舊的handler,因?yàn)閔andler只能設(shè)置一個(gè)贯城,保存舊的熊楼,今后可以去調(diào)用舊的handler,讓它也有可能來處理異常能犯。
4.1 當(dāng)崩潰發(fā)生時(shí)的處理工作
當(dāng)崩潰發(fā)生的時(shí)候鲫骗,被 ErrorReporter
的捕獲到,會(huì)使用 ReportBuilder
來構(gòu)建崩潰報(bào)告踩晶。其包括了崩潰的異常执泰,線程,自定義數(shù)據(jù)等信息渡蜻。
具體的崩潰處理术吝,是交給 ReportExecutor
來處理的。
4.2 當(dāng)崩潰發(fā)生后的清理工作
在崩潰發(fā)生以后茸苇,ACRA還會(huì)去幫助application正確的關(guān)閉上一個(gè)activity排苍,清理并關(guān)閉進(jìn)程。
清理工作包括:
- 關(guān)閉上一個(gè)activity(調(diào)用其finish方法)
- 關(guān)閉所有services
- 殺掉進(jìn)程并退出應(yīng)用
首先需要記錄上一個(gè)activity学密。原理是在4.0版本以后調(diào)用 application 的方法來注冊(cè) activity 的生命周期監(jiān)聽函數(shù)纪岁,并使用weakReference來記錄上一次啟動(dòng)的activity(最后一個(gè)onCreate的activity)
public LastActivityManager(Application app) {
application.registerActivityLifecycleCallbacks(() -> {
void onActivityCreated(Activity act, Bundle bundle) {
lastActivityCreated = new WeakReference<Activity>(act);
}
});
}
然后需要找到當(dāng)前進(jìn)程里的所有service,并調(diào)用stopService來關(guān)閉则果。
最后kill掉線程,并退出漩氨。
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(10);
參見:org.acra.builder.LastActivityManager
參見:org.acra.util.ProcessFinisher
五. 異常報(bào)告處理器(ReportExecutor)
ReportExecutor負(fù)責(zé)收集和處理異常報(bào)告西壮。
5.1 生成崩潰報(bào)告
當(dāng)崩潰發(fā)生時(shí),崩潰的異常等信息交給 ReportExecutor叫惊,然后轉(zhuǎn)交給 CrashReportDataFactory
來生成具體的崩潰報(bào)告款青。
5.2 保存崩潰報(bào)告到文件
之后將報(bào)告保存到本地文件中。
注意:ACRA寫報(bào)告文件是用的同步操作霍狰,在當(dāng)前線程進(jìn)行阻塞IO操作抡草,而不是在開啟一個(gè)工作線程來寫文件。TODO:為什么蔗坯?
具體寫文件的邏輯是有 CrashReportPersister
來實(shí)現(xiàn)康震。具體存到哪個(gè)目錄是由 ReportLocator
來決定的。而具體存成什么文件名宾濒,是根據(jù)崩潰的時(shí)間戳來決定的:
/data/data/packageName/files/{UnapprovedFolder}/{Timestamp}-{IS_SILENT}.stacktrace
例如:
/data/data/test.lds.com.androidtest/app_ACRA-unapproved/2017-03-25T03:34:45.633+00:00-IS_SILENT.stacktrace
ACRA會(huì)將報(bào)告存在不同的兩個(gè)目錄下:
- app_ACRA-unapproved
- app_ACRA-approved
崩潰報(bào)告首先都會(huì)存到 unapproved 目錄下腿短,在該目錄下的報(bào)告不會(huì)發(fā)送出去,而允許發(fā)送以后則會(huì)將報(bào)告移動(dòng)到 approved 目錄下,在該目錄下的崩潰報(bào)告才會(huì)被發(fā)送出去橘忱。
5.3 崩潰報(bào)告文件格式
ACRA的崩潰報(bào)告以JSON格式保存在本地中赴魁。
報(bào)告是鍵值對(duì)結(jié)構(gòu),包含各種字段的信息钝诚,具體的字段可參考:
https://github.com/ACRA/acra/wiki/ReportContent
注意:需要上報(bào)哪些字段颖御,不需要上報(bào)哪些字段,這都是可以手動(dòng)配置的凝颇,避免上報(bào)的數(shù)據(jù)過多潘拱。
5.4 崩潰發(fā)送模式
- 如果模式為silent或toast,則立即將報(bào)告發(fā)送出去祈噪。
- 如果模式為notification泽铛,則在通知欄顯示一個(gè)notification,來通知用戶該應(yīng)用崩潰了辑鲤,點(diǎn)擊這個(gè)通知會(huì)彈出一個(gè)對(duì)話框盔腔,用戶可選擇是否發(fā)送崩潰報(bào)告,如果用戶選擇發(fā)送月褥,則立即將報(bào)告發(fā)送出去弛随。
- 如果模式為dialog,則直接顯示dialog給用戶選擇是否發(fā)送宁赤。
六. 崩潰報(bào)告數(shù)據(jù)工廠(CrashReportDataFactory)
ACRA支持各種數(shù)據(jù)的收集舀透,每個(gè)收集器都收集不同類型的數(shù)據(jù),并且它支持配置需要發(fā)送什么類型的數(shù)據(jù)决左,而不發(fā)送什么數(shù)據(jù)愕够。
CrashReportDataFactory負(fù)責(zé)將崩潰時(shí)的數(shù)據(jù),以及根據(jù)配置來收集不同的上下文數(shù)據(jù)佛猛,將其封裝成一個(gè)崩潰報(bào)告對(duì)象(CrashReportData)惑芭。
崩潰報(bào)告其實(shí)是一個(gè)關(guān)鍵對(duì),包含各種不同字段的數(shù)據(jù)继找,并可以在寫到文件的時(shí)候輸入json格式數(shù)據(jù)遂跟。
七. 崩潰報(bào)告發(fā)送器(SenderServiceStarter)
當(dāng)崩潰報(bào)告生成以后,并允許發(fā)送時(shí)婴渡,會(huì)交由 SenderServiceStarter
來負(fù)責(zé)啟動(dòng) SenderServie
服務(wù)來在厚愛發(fā)送報(bào)告幻锁。
八. 后臺(tái)發(fā)送崩潰報(bào)告服務(wù)(SenderService)
SenderService
負(fù)責(zé)具體的將崩潰報(bào)告發(fā)送出去的工作。
注意該Service是在另一個(gè)進(jìn)程中(名為acra的進(jìn)程)來和應(yīng)用的主進(jìn)程進(jìn)行隔離边臼。
其繼承于 IntentService
哄尔,非常適合于短時(shí)間的后臺(tái)操作,并在工作線程執(zhí)行柠并。每次執(zhí)行完畢后則會(huì)關(guān)閉自己究飞。
首先它會(huì)將所有 unapproved 目錄下的報(bào)告都移動(dòng)到 approved 目錄置谦,然后將該目錄下的所有報(bào)告進(jìn)行批量分發(fā)。因?yàn)榭赡軙?huì)注冊(cè)多種報(bào)告發(fā)送方法(如郵件亿傅、自定義服務(wù)器腳本等)媒峡,所以具體的報(bào)告分發(fā)工作都交由 ReportDistributor
來處理。
每一次Service啟動(dòng)的時(shí)候葵擎,都只會(huì)最多發(fā)送 MAX_SEND_REPORTS
即5封報(bào)告來避免網(wǎng)絡(luò)負(fù)載過大谅阿。
九. 崩潰報(bào)告分發(fā)器(ReportDistributor)
ReportDistributor
負(fù)責(zé)將某一個(gè)崩潰報(bào)告分發(fā)給所有注冊(cè)的報(bào)告發(fā)送器。具體支持哪些發(fā)送器是由application上的注解來決定的酬滤。
一共有三種發(fā)送器(對(duì)應(yīng)注解ReportsCrashes):
- 沒有發(fā)送器 NullSender
- 郵件發(fā)送器 EmailIntentSender (對(duì)應(yīng)注解 mailTo )
- 自定義服務(wù)器發(fā)送器 HttpSender(對(duì)應(yīng)注解 fromUri )
分發(fā)的時(shí)候會(huì)將崩潰報(bào)告從文件讀入到內(nèi)存签餐,即將文件里的JSON反映射為 CrashReportData 對(duì)象。然后再將其分發(fā)出去盯串。
崩潰報(bào)告分發(fā)以后則會(huì)立即刪除崩潰文件氯檐。
注意:如果在從文件解析JSON的過程中出現(xiàn)異常,即無法解析JSON文件体捏,則會(huì)直接刪除該報(bào)告冠摄,因?yàn)檫@個(gè)報(bào)告很可能是不合法的格式。而如果是分發(fā)過程中出現(xiàn)異常几缭,則不會(huì)刪除崩潰文件河泳。
十. 崩潰報(bào)告發(fā)送器
ACRA支持多種發(fā)送崩潰報(bào)告的方法。發(fā)送器支持在錯(cuò)誤情況下重試的機(jī)制 RetryPolicy
年栓。
10.1 發(fā)送給自定義服務(wù)器(fromUri)
可以將崩潰報(bào)告發(fā)送給自定義服務(wù)器上的某個(gè)腳本拆挥,腳本的url在注解中的 fromUri 中配置。
支持在config中配置某抓,是否需要使用 BasicAuth 來進(jìn)行用戶認(rèn)證纸兔,可配置 username/password 。
還可以在config中配置http的超時(shí)時(shí)間否副,headers等信息汉矿。
具體的HTTP網(wǎng)絡(luò)請(qǐng)求是由 DefaultHttpRequest
類來實(shí)現(xiàn)的。它的內(nèi)部實(shí)現(xiàn)是使用 HttpURLConnection
來實(shí)現(xiàn)HTTP請(qǐng)求的副编。并實(shí)現(xiàn)了https,BasicAuth的支持流强。
崩潰報(bào)告的內(nèi)容會(huì)直接以輸出流的形式傳給服務(wù)器痹届。
10.2 發(fā)送給指定郵箱(mailTo)
可以將報(bào)告以郵件的形式發(fā)送給指定的郵箱地址,但是需要注意的是這里并沒有實(shí)現(xiàn)郵件發(fā)送功能打月,而僅僅是使用Intent來喚起設(shè)備上直接發(fā)送郵件的郵件客戶端來進(jìn)行發(fā)送队腐。即對(duì)于用戶而言,發(fā)送的時(shí)候程序會(huì)跳到郵件客戶端編寫新郵件的頁面奏篙,并且收件人和發(fā)送的內(nèi)容都可以填寫好了柴淘,點(diǎn)擊發(fā)送即可迫淹。
崩潰報(bào)告會(huì)在郵件的正文(純文本)的形式發(fā)送,每一條數(shù)據(jù)一行为严,以“=”進(jìn)行key和value的分隔符, 例如:
APP_VERSION_CODE=1
USER_CRASH_DATE=2017-03-25T03:34:45.633+00:00
PRODUCT=sdk_google_phone_x86
十一. Collector信息收集器
ACRA可以收集各種各樣的崩潰上下文數(shù)據(jù)敛熬,則從架構(gòu)上它將所有信息進(jìn)行分類,交給不同的收集器去收集第股,也支持配置去過濾需要的收集器來收集不同的信息应民。
11.1 應(yīng)用日志收集器(LogCatCollector)
收集崩潰時(shí)最近300行的Logcat日志輸出內(nèi)容∠ξ牵可支持收集不同緩存區(qū)的日志诲锹。
緩存區(qū):
- main,查看主要日志緩沖區(qū)(默認(rèn)值)
- events涉馅,查看包含事件相關(guān)消息的緩沖區(qū)归园。
- radio, 查看包含無線裝置/電話相關(guān)消息的緩沖區(qū)稚矿。
收集這些信息需要使用執(zhí)行終端命令 logcat
來實(shí)現(xiàn)庸诱,并支持根據(jù)當(dāng)前的pid進(jìn)行過濾。
List<String> commandLine = new ArrayList<>();
commandLine.add("logcat");
// ...
final Process process =
new ProcessBuilder().command(commandLine).redirectErrorStream(true).start();
// process.getInputStream()
收集到的logcat日志會(huì)以 \n
作為分隔符盐捷,拼接成一個(gè)字符串偶翅。
收集logcat信息需要權(quán)限:android.permission.READ_LOGS, 并且系統(tǒng)版本在Android 4.1及以上碉渡。
logocat命令官方文檔:https://developer.android.com/studio/command-line/logcat.html
11.2 系統(tǒng)日志收集器(DropBoxCollector)
Android內(nèi)有一個(gè)名為DropBoxManager的Service聚谁,用于持久化的記錄系統(tǒng)日志或程序崩潰日志。
DropBoxManager 是 Android 在 Froyo(API level 8) 引入的用來持續(xù)化存儲(chǔ)系統(tǒng)數(shù)據(jù)的機(jī)制, 主要用于記錄 Android 運(yùn)行過程中, 內(nèi)核, 系統(tǒng)進(jìn)程, 用戶進(jìn)程等出現(xiàn)嚴(yán)重問題時(shí)的 log, 可以認(rèn)為這是一個(gè)可持續(xù)存儲(chǔ)的系統(tǒng)級(jí)別的logcat.
DropBox可以記錄到如下的日志:
- crash: 崩潰時(shí)
-
native_crash: 當(dāng)調(diào)用
NativeCrashReporter.run()
時(shí)滞诺。 -
WTF:調(diào)用
Log.wtf()
或Log.wtfQuiet()
時(shí) - ANR:應(yīng)用程序未響應(yīng)時(shí)
- watchdog: 如果WatchDog 檢測(cè)到系統(tǒng)進(jìn)程(system_server)出現(xiàn)問題時(shí)形导。
- lowmem: 內(nèi)存不足時(shí)
- 等等
收集這些信息需要獲取 DropBoxManager 的 Service 對(duì)象即可:
final DropBoxManager dropbox =
(DropBoxManager) context.getSystemService(Context.DROPBOX_SERVICE);
// ...
DropBoxManager.Entry entry = dropbox.getNextEntry(tag, time);
當(dāng)系統(tǒng)出現(xiàn)各種情況時(shí),都會(huì)寫入各種日志习霹,日志類型清單如下(不完全):
SYSTEM_TAGS | NOTE |
---|---|
system_app_anr | 系統(tǒng)app無響應(yīng) |
system_app_wtf | 系統(tǒng)app發(fā)生嚴(yán)重錯(cuò)誤 |
system_app_crash | 系統(tǒng)app崩潰 |
system_app_strictmode | 系統(tǒng)app嚴(yán)格模式 |
system_server_anr | system進(jìn)程無響應(yīng) |
system_server_wtf | system進(jìn)程發(fā)生嚴(yán)重錯(cuò)誤 |
system_server_crash | system進(jìn)程崩潰 |
data_app_anr | 普通應(yīng)用無響應(yīng) |
data_app_wtf | 普通應(yīng)用發(fā)生嚴(yán)重錯(cuò)誤 |
data_app_creash | 普通應(yīng)用崩潰 |
data_app_strictmode | 普通應(yīng)用嚴(yán)格模式 |
BATTERY_DISCHARGE_INFO | 系統(tǒng)充電日志( BatteryService ) |
SYSTEM_RECOVERY_LOG | 系統(tǒng)恢復(fù)而重啟( /cache/recovery/log文件存在時(shí)) |
SYSTEM_BOOT | 系統(tǒng)開機(jī)日志 |
SYSTEM_LAST_KMSG | 內(nèi)核錯(cuò)誤( /proc/last_kmsg文件存在時(shí)) |
APANIC_CONSOLE | 內(nèi)核錯(cuò)誤( /data/dontpanic/apanic_console文件存在時(shí)) |
APANIC_THREADS | 內(nèi)核錯(cuò)誤( /data/dontpanic/apanic_threads文件存在時(shí)) |
SYSTEM_RESTART | 系統(tǒng)重啟日志 |
SYSTEM_TOMBSTONE | Native進(jìn)程崩潰日志 |
event_data | |
netstats_error | 網(wǎng)絡(luò)狀態(tài)異常日志( NetworkStatsService ) |
所有dropbox的文件都以 TAG@timestrap.txt 為名稱保存在系統(tǒng)目錄:
/data/system/dropbox
每次有新文件寫入的時(shí)候朵耕,都會(huì)有系統(tǒng)廣播:
DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED
例如:data_app_crash@1490172449967.txt
文件就記錄了一個(gè)普通app崩潰的日志信息:
Process: com.example.dumptestbyjava
Flags: 0xa8be46
Package: com.example.dumptestbyjava v1 (1.1)
Build: Android/sdk_google_phone_x86/generic_x86:5.1.1/LMY48X/3728910:userdebug/test-keys
java.lang.ArrayIndexOutOfBoundsException: length=3; index=10
at com.example.dumptestbyjava.MainActivity$3.onClick(MainActivity.java:167)
at android.view.View.performClick(View.java:4780)
at android.view.View$PerformClick.run(View.java:19866)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
收集logcat信息需要權(quán)限:android.permission.READ_LOGS, 并且系統(tǒng)版本在Android 4.1及以上淋叶。
dropBox介紹參考:http://blog.csdn.net/ljchlx/article/details/8559963
DropBoxManagerService啟動(dòng)說明:http://gityuan.com/2016/06/12/DropBoxManagerService/DropBox介紹:http://www.reibang.com/p/f9174a8d0a10
11.3 崩潰日志收集器(StacktraceCollector)
收集崩潰時(shí)引發(fā)的異常exception的stack trace阎曹。
這個(gè)比較簡(jiǎn)單,因?yàn)閑xception對(duì)象里包含了stack trace煞檩,直接將其轉(zhuǎn)換為字符串即可处嫌。
// Throwable
public void void printStackTrace(PrintWriter err);
11.4 時(shí)間收集器(TimeCollector)
收集應(yīng)用啟動(dòng)的時(shí)間,和崩潰發(fā)生的時(shí)間斟湃。
應(yīng)用啟動(dòng)的時(shí)間就是調(diào)用 init
方法的時(shí)候熏迹。
崩潰的時(shí)間就是崩潰當(dāng)前的時(shí)間戳。
時(shí)間格式:
yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ
11.5 鍵值對(duì)收集器(SimpleValuesCollector)
收集一些簡(jiǎn)單的鍵值對(duì)凝赛,如:
- is_silent: 配置中的選項(xiàng)
-
report_id: 每個(gè)崩潰報(bào)告會(huì)生成一個(gè)報(bào)告的唯一識(shí)別碼UUID
UUID.randomUUID().toString()
- installation_id: 每次安裝的時(shí)候會(huì)生成一個(gè)機(jī)器的唯一識(shí)別碼UUID(安裝的時(shí)候會(huì)將其寫入到文件)
-
package_name: 應(yīng)用的包名
context.getPackageName())
-
phone_model: 手機(jī)型號(hào)
Build.MODEL
-
android_version: android版本號(hào)
Build.VERSION.RELEASE
, 例如5.1.1
-
brand: 手機(jī)品牌
Build.BRAND
-
product: 手機(jī)產(chǎn)品名
Build.PRODUCT
-
file_path: 應(yīng)用私有目錄路徑:
/data/data/packageName/files
- user_ip: 用戶IP , 從networkInterface中獲取的當(dāng)前所有ip
11.6 系統(tǒng)配置收集器(ConfigurationCollector)
收集的信息比較多注暗,包括屏幕尺寸坛缕,觸摸屏類型,系統(tǒng)語言捆昏,鍵盤赚楚,導(dǎo)航,UI模式等信息屡立。
這些信息收集起來其實(shí)比較簡(jiǎn)單直晨,只需要調(diào)用context的方法即可。
getContext().getResources().getConfiguration();
收集信息實(shí)例如下:
{
"compatScreenHeightDp": 511,
"compatScreenWidthDp": 319,
"compatSmallestScreenWidthDp": 320,
"densityDpi": 420,
"fontScale": 1,
"hardKeyboardHidden": "HARDKEYBOARDHIDDEN_YES",
"keyboard": "KEYBOARD_NOKEYS",
"keyboardHidden": "KEYBOARDHIDDEN_NO",
"locale": "en_US",
"mcc": 310,
"mnc": 260,
"navigation": "NAVIGATION_NONAV",
"navigationHidden": "NAVIGATIONHIDDEN_YES",
"orientation": "ORIENTATION_PORTRAIT",
"screenHeightDp": 658,
"screenLayout": "SCREENLAYOUT_SIZE_NORMAL+SCREENLAYOUT_LONG_NO+SCREENLAYOUT_LAYOUTDIR_LTR",
"screenWidthDp": 411,
"seq": 6,
"smallestScreenWidthDp": 411,
"touchscreen": "TOUCHSCREEN_FINGER",
"uiMode": "UI_MODE_TYPE_NORMAL+UI_MODE_NIGHT_NO",
"userSetLocale": false
},
具體參數(shù)含義可參考官方文檔: https://developer.android.com/reference/android/content/res/Configuration.html
11.7 內(nèi)存信息收集器(MemoryInfoCollector)
收集當(dāng)前應(yīng)用最大內(nèi)存(total)膨俐,可用內(nèi)存(available)勇皇,以及dumpsys里的內(nèi)存信息。
內(nèi)存信息使用的就是終端命令焚刺,來獲取跟內(nèi)存有關(guān)的信息敛摘。
dumpsys meninfo
注意dumpsys在很多機(jī)器上使不行的,需要android.permission.DUMP權(quán)限乳愉,但該權(quán)限只有系統(tǒng)應(yīng)用才允許使用兄淫。
Total PSS by process:
52818 kB: com.google.android.gms (pid 4071)
50785 kB: system (pid 3455)
40850 kB: com.google.android.gms.persistent (pid 3672)
31394 kB: com.google.android.googlequicksearchbox (pid 3720 / activities)
31273 kB: com.android.systemui (pid 3545)
19930 kB: com.google.android.googlequicksearchbox:search (pid 3849)
17980 kB: com.google.android.gms.unstable (pid 4354)
15836 kB: com.android.phone (pid 3703)
14464 kB: zygote (pid 3173)
12383 kB: com.google.android.gms.ui (pid 4423)
9932 kB: com.android.inputmethod.latin (pid 3618)
7867 kB: android.process.acore (pid 3746)
7264 kB: com.google.process.gapps (pid 3797)
6428 kB: mediaserver (pid 3175)
5776 kB: test.lds.com.androidtest:acra (pid 7266)
5254 kB: com.google.android.googlequicksearchbox:interactor (pid 3598)
4926 kB: com.android.providers.calendar (pid 4179)
4131 kB: com.android.keychain (pid 4917)
3638 kB: com.android.defcontainer (pid 4884)
3166 kB: com.svox.pico (pid 4943)
2562 kB: logd (pid 1157)
1906 kB: surfaceflinger (pid 1162)
1583 kB: drmserver (pid 1171)
995 kB: vold (pid 1161)
876 kB: netd (pid 3174)
763 kB: keystore (pid 1174)
742 kB: debuggerd (pid 1169)
702 kB: rild (pid 1170)
556 kB: adbd (pid 1167)
456 kB: healthd (pid 1158)
453 kB: sh (pid 8276)
437 kB: lmkd (pid 1159)
437 kB: sh (pid 1166)
423 kB: sdcard (pid 1856)
408 kB: /init (pid 1)
406 kB: dumpsys (pid 8411)
358 kB: logcat (pid 5268)
320 kB: ueventd (pid 829)
299 kB: installd (pid 1173)
292 kB: servicemanager (pid 1160)
11.8 反射信息收集器(ReflectionCollector)
通過反射獲取到一些常量信息,一般和環(huán)境有關(guān)蔓姚。
- Build 的常量信息:包括BRAND捕虽,DEVICE等。
- BuildConfigs 的常量信息:包括debug坡脐,application_id, flavor, version_code, version_name等
- Environment 的常量信息:包括 getExternalStorageDirectory 等環(huán)境變量(這個(gè)是通過調(diào)用其一系列g(shù)et方法的獲取的)
11.9 屏幕信息收集器(DisplayManagerCollector)
收集屏幕相關(guān)的數(shù)據(jù)泄私,如size,rotation备闲,width晌端,height,Metrics恬砂,RealMetrics咧纠,refreshRate等。
使用 DisplayManager 來獲取 Display 對(duì)象(可能有多個(gè)泻骤,但一般只有一個(gè))
11.10 自定義數(shù)據(jù)收集器(CustomDataCollector)
收集自定義數(shù)據(jù)漆羔,由用戶主動(dòng)插入的自定義數(shù)據(jù)。
11.11 Pref信息收集器(SharedPreferencesCollector)
收集 SharedPreferences 信息狱掂。
有兩種情況:
- Application作為context獲得的 default SharedPreferences 對(duì)象里的數(shù)據(jù)演痒。
- 在配置中指定 name 的 SharedPreferences 對(duì)象里的所有鍵值對(duì)。
11.12 設(shè)備特性收集器(DeviceFeaturesCollector)
收集設(shè)備支持的特性符欠,如是否有GPS嫡霞,有藍(lán)牙瓶埋,有加速器希柿,openGL es的版本號(hào)等信息诊沪。
收集方法比較簡(jiǎn)單,使用以下代碼即可:
final PackageManager pm = context.getPackageManager();
final FeatureInfo[] features = pm.getSystemAvailableFeatures();
// 獲取 OpenGL Es 版本號(hào)
if (feature.name == null) {
feature.getGlEsVersion();
}
11.13 手機(jī)設(shè)置收集器(SettingsCollector)
收集手機(jī)設(shè)置相關(guān)信息:
- SETTINGS_GLOBAL 全局設(shè)置曾撤,如WiFi是否開啟端姚,鈴聲,藍(lán)牙是否開啟挤悉,GPS是否開啟等手機(jī)設(shè)置渐裸。
- SETTINGS_SYSTEM 系統(tǒng)設(shè)置,音量大小装悲,是否開啟震動(dòng)等設(shè)置昏鹃。
- SETTINGS_SECURE 隱私設(shè)置,
這些信息也是通過反射來獲取的
// SETTINGS_GLOBAL
Global.class.getFields();
// SETTINGS_SYSTEM
System.class.getFields();
// SETTINGS_SECURE
Secure.class.getFields();
11.14 包信息收集器(PackageManagerCollector)
收集應(yīng)用版本信息诀诊,如versionCode和versionName洞渤。
11.15 設(shè)備唯一標(biāo)識(shí)收集器(DeviceIdCollector)
獲取設(shè)備唯一識(shí)別碼,如IMEI號(hào)信息
final TelephonyManager tm =
(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
tm.getDeviceId();
需要權(quán)限:android.permission.READ_PHONE_STATE
更多設(shè)備唯一識(shí)別碼獲取參見:http://www.cnblogs.com/lvcha/p/3721091.html
11.16 自定義日志收集器(LogFileCollector)
收集自定義log文件属瓣,可以在配置中指定自定義個(gè)log文件路徑载迄,崩潰報(bào)告則會(huì)將其log文件的內(nèi)容以字符串的形式作為報(bào)告的信息進(jìn)行收集。
11.17 媒體格式收集器(MediaCodecCollector)
收集設(shè)備支持的媒體格式抡蛙,如視頻格式护昧,音頻格式等。
收集這些信息是使用反射 android.media.MediaCodecInfo
類兩個(gè)內(nèi)部類:
- MediaCodecInfo$CodecCapabilities
- MediaCodecInfo$CodecProfileLevel
11.18 崩潰線程信息收集器(ThreadCollector)
收集崩潰線程的信息粗截,如 Thread 的 id, name, priority, groupName
這里 Thread 對(duì)象是由 UncaughtExceptionHandler
的 uncaughtException
方法一路傳進(jìn)來的惋耙,指向引發(fā)崩潰的線程。
十二. 結(jié)語
ACRA作為一個(gè)被廣泛使用的Android Crash Report系統(tǒng)慈格,又是Google官方推出怠晴,因此該框架有幾點(diǎn)優(yōu)勢(shì):
- 經(jīng)過大量真實(shí)應(yīng)用長(zhǎng)時(shí)間的使用,穩(wěn)定性比較高浴捆。
- 因?yàn)镚oogle對(duì)Android的了解蒜田,對(duì)于大量信息的收集比較全面,包括使用反射來收集的信息选泻。
- 框架在架構(gòu)上設(shè)計(jì)得比較好冲粤,值得學(xué)習(xí)。