Android日志能力之持久化转储及回传的闭环方案(上)
背景
在现如今Android市场的半壁江山下各ODM厂商OEM厂商谁要是没点获取问题日志的能力那可能会被这快速的更新迭代大浪淘沙掉,尤其是一款新上市的产品初期,必定是有各种各样的售后问题反馈,俗话说-用户即上帝,在上帝反馈前和反馈后及时获取对于开发者有用的全面的信息必定是推动产品软件快速更新迭代和赢得上帝信任好评的关键。
今天我们就来聊聊一种持久化日志转储及回传的闭环设计方案。
Android系统中常用的日志信
众所周知,logcat作为Android中不可或缺的开发者调试利器,让我们能直观的看到我们的程序究竟发生了什么,在哪里跑飞,又是如何崩溃的,甚至于哪个函数的哪一行系统都已经提示出来了。但是对于开发者来说,不可能追到用户家里去拿着电脑调试用户的手机/平板,那就必须要获取出现问题的日志信息,然而就算在出现Crash/ANR后去获取logcat,必然已经不是案发现场了(就算是案发现场也可能不是第一现场了),因此将案发现场进行保存必然是有利于我们分析破案的。
上帝反馈前
在Android系统的设计时Google的开发者必然也有同样的苦恼 —— 如何准确的获取用户程序出现问题的信息。因此机智的他们在framework和native层埋下了一个追踪器 —— DropBox。只要是在framework层处理的异常信息(ANR、CRASH)均会将关键的信息收集到DropBox中,并记录在/data/system/dropbox
目录下。
DropBox涵盖了绝大多数的异常和非法操作的关键信息,以系统处理Crash的流程为例,在ActivityManagerService
中处理application crash时通过如下流程将关键的信息生成一条增加到DropBoxManager中:
ActivityManagerService.java
/**
* Used by {@link com.android.internal.os.RuntimeInit} to report when an application crashes.
* The application process will exit immediately after this call returns.
* @param app object of the crashing app, null for the system server
* @param crashInfo describing the exception
*/
public void handleApplicationCrash(IBinder app,
ApplicationErrorReport.ParcelableCrashInfo crashInfo) {
ProcessRecord r = findAppProcess(app, "Crash");
final String processName = app == null ? "system_server"
: (r == null ? "unknown" : r.processName);
handleApplicationCrashInner("crash", r, processName, crashInfo);
}
void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
ApplicationErrorReport.CrashInfo crashInfo) {
......
mAmsExt.onNotifyAppCrash(Binder.getCallingPid(), Binder.getCallingUid(),
(r != null && r.info != null) ? r.info.packageName : "");
addErrorToDropBox(
eventType, r, processName, null, null, null, null, null, null, crashInfo);
......
}
/**
* Write a description of an error (crash, WTF, ANR) to the drop box.
*/
public void addErrorToDropBox(String eventType,
ProcessRecord process, String processName, String activityShortComponentName,
String parentShortComponentName, ProcessRecord parentProcess,
String subject, final String report, final File dataFile,
final ApplicationErrorReport.CrashInfo crashInfo) {
......
}
调用ActivityManagerService
的addErrorToDropBox
方法后会生成一条对应的Entry,DropBoxManagerService会对此Entry进行处理,将其记录在/data/system/dropbox
目录下,并发送一条广播 —— DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED
,并将时间戳与DropBoxTag作为Extra内容:
DropBoxManagerService.java
private class DropBoxManagerBroadcastHandler extends Handler {
......
private Intent createIntent(String tag, long time) {
final Intent dropboxIntent = new Intent(DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED);
dropboxIntent.putExtra(DropBoxManager.EXTRA_TAG, tag);
dropboxIntent.putExtra(DropBoxManager.EXTRA_TIME, time);
return dropboxIntent;
}
/**
* Schedule a dropbox broadcast to be sent asynchronously.
*/