Android DropBoxManagerService初探
背景
随着Android的发展,市场上也出现各种形态的搭载Android系统的设备。然而对于开发者而言,永远预想不到用户能搞一些什么骚操作,将你的程序搞出问题,那么我们只能依赖问题监控去定位分析了。
如果你需要同时监控整个Android设备rom的稳定性(系统异常 + 各种应用的异常),那么市场上常见的异常监控的SDK就无法满足我们的需求了。那么对于这样的问题我们该怎么办呢?
Android系统中是否实现
在Android系统设计时候Google的工程师也考虑到了这个问题,从而在framework和native层种下了一个跟踪器 — DropBox。DropBox是Android 在Froyo(API level 8) 引入的用来持续化存储系统数据的机制,主要用于记录Android运行过程中,内核,系统进程,用户进程等出现严重问题时的log。DropBoxManagerService是一个独立的服务。
DropBoxManagerService分析
DropboxManagerService Initialize Flow and Usage Overview
onBootPhase启动的流程
DropboxManagerService 服务处理请求
Crash Flow
DropBox日志文件会记录在/data/system/dropbox目录中。DropBox涵盖了绝大多数的异常和非法操作的相关信息。当一个Crash发生后,大概流程:
DropBox File 生成流程
DropBoxManagerService (DBMS)是一个系统服务。它的启动就在system_server启动的时候。在SystemService的startOtherService中启动。
mSystemServiceManager.startService(DropBoxManagerService.class);
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);
}
/* Native crash reporting uses this inner version because it needs to be somewhat
* decoupled from the AM-managed cleanup lifecycle
*/
void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
ApplicationErrorReport.CrashInfo crashInfo) {
...
...
addErrorToDropBox(
eventType, r, processName, null, null, null, null, null, null, crashInfo,
new Float(loadingProgress), incrementalMetrics, null);
mAppErrors.crashApplication(r, crashInfo);
}
/**
* Write a description of an error (crash, WTF, ANR) to the drop box.
* @param eventType to include in the drop box tag ("crash", "wtf", etc.)
* @param process which caused the error, null means the system server
* @param activityShortComponentName which triggered the error, null if unknown
* @param parentShortComponentName activity related to the error, null if unknown
* @param parentProcess parent process
* @param subject line related to the error, null if absent
* @param report in long form describing the error, null if absent
* @param dataFile text file to include in the report, null if none
* @param crashInfo giving an application stack trace, null if absent
* @param loadingProgress the loading progress of an installed package, range in [0, 1].
* @param incrementalMetrics metrics for apps installed on Incremental.
* @param errorId a unique id to append to the dropbox headers.
*/
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,
@Nullable Float loadingProgress, @Nullable IncrementalMetrics incrementalMetrics,
@Nullable UUID errorId) {
// NOTE -- this must never acquire the ActivityManagerService lock,
// otherwise the watchdog may be prevented from resetting the system.
// Bail early if not published yet
if (ServiceManager.getService(Context.DROPBOX_SERVICE) == null) return;
final DropBoxManager dbox = mContext.getSystemService(DropBoxManager.class);
...
...
dbox.addText(dropboxTag, sb.toString());
...
...
}
DropBoxManager.java
/**
* Stores human-readable text. The data may be discarded eventually (or even
* immediately) if space is limited, or ignored entirely if the tag has been
* blocked (see {@link #isTagEnabled}).
*
* @param tag describing the type of entry being stored
* @param data value to store
*/
public void addText(@NonNull String tag, @NonNull String data) {
addData(tag, data.getBytes(StandardCharsets.UTF_8), IS_TEXT);
}
/**
* Stores binary data, which may be ignored or discarded as with {@link #addText}.
*
* @param tag describing the type of entry being stored
* @param data value to store
* @param flags describing the data
*/
public void addData(@NonNull String tag, @Nullable byte[] data, @Flags int flags) {
...
// IDropBoxManagerService mService
mService.addData(tag, data, flags);
...
}
DropBoxManagerService.java
public void addData(String tag, byte[] data, int flags) {
addEntry(tag, new ByteArrayInputStream(data), data.length, flags);
}
public void addEntry(String tag, EntrySource entry, int flags) {
...
// Call sendBroadcast after returning from this call to avoid deadlock. In particular
// the caller may be holding the WindowManagerService lock but sendBroadcast requires a
// lock in ActivityManagerService. ActivityManagerService has been caught holding that
// very lock while waiting for the WindowManagerService lock.
if (mLowPriorityTags != null && mLowPriorityTags.contains(tag)) {
// Rate limit low priority Dropbox entries
mHandler.maybeDeferBroadcast(tag, time);
} else {
mHandler.sendBroadcast(tag, time);
}
...
}
这个流程system_service启动的时候,启动DBMS。当有Crash/anr/wtf等等问题产生时,调用AMS的addErrorToDropBox方式,生成一个对应的Entry对象,
Crash Type
dropbox文件名格式为dropboxTag@xxx.txt,xxx代表时间戳,例如 system_server_crash@1465650845355.txt ,则记录该文件时间戳为1465650845355. 文件后缀除了.txt,还有压缩格式.txt.gz. 对于dropboxTag是由processClass + eventType组合而成.
- processClass分为:system_server, system_app, data_app;
- eventType分为:crash, anr, wtf, native_cras, lowmem, watchdog
| dropboxTag | 含义 |
|---|---|
| system_server_anr | system进程无响应 |
| system_server_watchdog | system进程发生watchdog |
| system_server_crash | system进程崩溃 |
| system_server_native_crash | system进程native出现崩溃 |
| system_server_wtf | system进程发生严重错误 |
| system_server_lowmem | system进程内存不足 |
| system_app_crash | 系统app崩溃 |
| system_app_anr | 系统app无响应 |
| data_app_crash | 普通app崩溃 |
| data_app_anr | 普通app无响应 |
DropBoxFile 内容
SYSTEM_TOMBSTONE
system_app_anr
data_app_crash