簡(jiǎn)介
系統(tǒng)服務(wù)dropbox以文件形式記錄了系統(tǒng)各種異常信息旷赖,例如app crash、native crash、anr、kernel panic等等
adb查詢
adb shell dumpsys dropbox
app接口
源碼
10.0
1.DropBoxManager dropbox = (DropBoxManager) getSystemService(Context.DROPBOX_SERVICE)
例如,dropbox.addText 可實(shí)現(xiàn)把需要記錄的數(shù)據(jù)丟給dropbox進(jìn)行存儲(chǔ)
2.監(jiān)聽廣播android.intent.action.DROPBOX_ENTRY_ADDED射亏,可知系統(tǒng)發(fā)生了異常
注意權(quán)限:android.permission.READ_LOGS -- 平臺(tái)簽名或priv-app
dropbox啟動(dòng)
1.SystemServer:run。SystemServer啟動(dòng)服務(wù)
private void startOtherServices() {
···
mSystemServiceManager.startService(DropBoxManagerService.class);
···
}
2.DropBoxManagerService繼承SystemService,啟動(dòng)順序:構(gòu)造方法 -->onStart
a)構(gòu)造方法
public DropBoxManagerService(final Context context, File path) {
super(context);
mDropBoxDir = path;//dropbox路徑/data/system/dropbox
mContentResolver = getContext().getContentResolver();
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == MSG_SEND_BROADCAST) {
getContext().sendBroadcastAsUser((Intent)msg.obj, UserHandle.SYSTEM,
android.Manifest.permission.READ_LOGS);
}
}
};
}
b)onStart啟動(dòng)
public void onStart() {
// 監(jiān)聽低內(nèi)存返弹,保證dropbox不占用更多空間
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW);
getContext().registerReceiver(mReceiver, filter);
mContentResolver.registerContentObserver(
Settings.Global.CONTENT_URI, true,
new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
mReceiver.onReceive(getContext(), (Intent) null);
}
});
//注冊(cè)dropbox服務(wù)
publishBinderService(Context.DROPBOX_SERVICE, mStub);
}
3.接口運(yùn)用,發(fā)送廣播DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED
dropbox.add
public void add(DropBoxManager.Entry entry) {
···
try {
···
final Intent dropboxIntent = new Intent(DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED);
dropboxIntent.putExtra(DropBoxManager.EXTRA_TAG, tag);
dropboxIntent.putExtra(DropBoxManager.EXTRA_TIME, time);
if (!mBooted) {
dropboxIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
}
···
mHandler.sendMessage(mHandler.obtainMessage(MSG_SEND_BROADCAST, dropboxIntent));
} catch (IOException e) {
Slog.e(TAG, "Can't write: " + tag, e);
} finally {
IoUtils.closeQuietly(output);
IoUtils.closeQuietly(input);
entry.close();
if (temp != null) temp.delete();
}
}
dropbox日志路徑:/data/system/dropbox
C:\Users\99418>adb shell ls -al /data/system/dropbox
total 432
drwx------ 2 system system 4096 2021-12-23 06:02 .
drwxrwxr-x 16 system system 4096 2021-12-23 06:01 ..
-rw------- 1 system system 335 2022-01-25 14:40 SYSTEM_BOOT@1640210494810.txt
-rw------- 1 system system 334 2022-01-25 15:05 SYSTEM_BOOT@1640210494823.txt
-rw------- 1 system system 334 2021-12-23 06:01 SYSTEM_BOOT@1640210496077.txt
-rw------- 1 system system 19264 2022-01-25 14:40 SYSTEM_RECOVERY_KMSG@1640210494811.txt.gz
-rw------- 1 system system 19191 2022-01-25 15:05 SYSTEM_RECOVERY_KMSG@1640210494824.txt.gz
-rw------- 1 system system 5661 2022-01-25 14:40 SYSTEM_RECOVERY_LOG@1640210494809.txt.gz
-rw------- 1 system system 5076 2022-01-25 15:05 SYSTEM_RECOVERY_LOG@1640210494822.txt.gz
-rw------- 1 system system 30 2022-01-25 14:40 storage_trim@1640210494803.txt
-rw------- 1 system system 4192 2022-01-25 14:40 system_app_strictmode@1640210494804.txt.gz
記錄的系統(tǒng)錯(cuò)誤
1.系統(tǒng)正常啟動(dòng)后的自檢工作
1)SYSTEM_BOOT
開機(jī)一次爪飘,記錄一次
2)SYSTEM_RESTART
如果system_server在設(shè)備運(yùn)行過(guò)程中異常义起,則會(huì)有記錄
3)SYSTEM_LAST_KMSG
kernel異常。
pstore是persistent storage的縮寫师崎,內(nèi)核發(fā)生異常通過(guò)此把異常日志記錄下來(lái)默终,方便定位問(wèn)題。
ramoops指的是采用ram保存oops信息(kernel 異常信息)的一個(gè)功能,利用pstore技術(shù)實(shí)現(xiàn)齐蔽。
kernel異常信息保存地:
panic
/proc/last_kmsg
oops
/sys/fs/pstore/console-ramoops
/sys/fs/pstore/console-ramoops-0
4)SYSTEM_TOMBSTONE
TOMBSTONE 是 Android 用來(lái)記錄 native 進(jìn)程崩潰的 core dump 日志, 系統(tǒng)服務(wù)在啟動(dòng)完成后會(huì)增加一個(gè) Observer 來(lái)偵測(cè) tombstone 日志文件的變化, 每當(dāng)生成新的 tombstone 文件, 就會(huì)增加一條 SYSTEM_TOMBSTONE 記錄到 DropBoxManager 中.
5)SYSTEM_RECOVERY_LOG/SYSTEM_RECOVERY_KMSG
SYSTEM_RECOVERY_KMSG:recovery kerenl日志
SYSTEM_RECOVERY_LOG:recovery 升級(jí)或恢復(fù)出廠設(shè)置等等日志
6)SYSTEM_FSCK
文件系統(tǒng)完整性校驗(yàn)日志
7)SYSTEM_AUDIT
kernel 異常信息的查漏補(bǔ)缺日志
BootReceiver.java
private void logBootEvents(Context ctx) throws IOException {
final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE);
final String headers = getBootHeadersToLogAndUpdate();
final String bootReason = SystemProperties.get("ro.boot.bootreason", null);
String recovery = RecoverySystem.handleAftermath(ctx);
if (recovery != null && db != null) {
db.addText("SYSTEM_RECOVERY_LOG", headers + recovery);
}
String lastKmsgFooter = "";
if (bootReason != null) {
lastKmsgFooter = new StringBuilder(512)
.append("\n")
.append("Boot info:\n")
.append("Last boot reason: ").append(bootReason).append("\n")
.toString();
}
HashMap<String, Long> timestamps = readTimestamps();
if (SystemProperties.getLong("ro.runtime.firstboot", 0) == 0) {
if (StorageManager.inCryptKeeperBounce()) {
// Encrypted, first boot to get PIN/pattern/password so data is tmpfs
// Don't set ro.runtime.firstboot so that we will do this again
// when data is properly mounted
} else {
String now = Long.toString(System.currentTimeMillis());
SystemProperties.set("ro.runtime.firstboot", now);
}
if (db != null) db.addText("SYSTEM_BOOT", headers);
// Negative sizes mean to take the *tail* of the file (see FileUtils.readTextFile())
// kernel panic日志两疚,例如異常重啟
addFileWithFootersToDropBox(db, timestamps, headers, lastKmsgFooter,
"/proc/last_kmsg", -LOG_SIZE, "SYSTEM_LAST_KMSG");
addFileWithFootersToDropBox(db, timestamps, headers, lastKmsgFooter,
"/sys/fs/pstore/console-ramoops", -LOG_SIZE, "SYSTEM_LAST_KMSG");
addFileWithFootersToDropBox(db, timestamps, headers, lastKmsgFooter,
"/sys/fs/pstore/console-ramoops-0", -LOG_SIZE, "SYSTEM_LAST_KMSG");
//recovery日志。例如OTA升級(jí)或恢復(fù)出廠設(shè)置的時(shí)候
addFileToDropBox(db, timestamps, headers, "/cache/recovery/log", -LOG_SIZE,
"SYSTEM_RECOVERY_LOG");
addFileToDropBox(db, timestamps, headers, "/cache/recovery/last_kmsg",
-LOG_SIZE, "SYSTEM_RECOVERY_KMSG");
//kernel日志的查漏補(bǔ)缺備份
addAuditErrorsToDropBox(db, timestamps, headers, -LOG_SIZE, "SYSTEM_AUDIT");
} else {
if (db != null) db.addText("SYSTEM_RESTART", headers);
}
// log always available fs_stat last so that logcat collecting tools can wait until
// fs_stat to get all file system metrics.
logFsShutdownTime();
logFsMountTime();
//fsck文件系統(tǒng)校驗(yàn)日志收集
//fsck(file system consistency check)是Unix和類Unix系統(tǒng)上用于檢查文件系統(tǒng)完整性的工具
addFsckErrorsToDropBoxAndLogFsStat(db, timestamps, headers, -LOG_SIZE, "SYSTEM_FSCK");
logSystemServerShutdownTimeMetrics();
// Scan existing tombstones (in case any new ones appeared)
//native進(jìn)程崩潰日志收集
File[] tombstoneFiles = TOMBSTONE_DIR.listFiles();
for (int i = 0; tombstoneFiles != null && i < tombstoneFiles.length; i++) {
if (tombstoneFiles[i].isFile()) {
addFileToDropBox(db, timestamps, headers, tombstoneFiles[i].getPath(),
LOG_SIZE, "SYSTEM_TOMBSTONE");
}
}
writeTimestamps(timestamps);
// Start watching for new tombstone files; will record them as they occur.
// This gets registered with the singleton file observer thread.
// /data/tombstones目錄監(jiān)聽收集
sTombstoneObserver = new FileObserver(TOMBSTONE_DIR.getPath(), FileObserver.CREATE) {
@Override
public void onEvent(int event, String path) {
HashMap<String, Long> timestamps = readTimestamps();
try {
File file = new File(TOMBSTONE_DIR, path);
if (file.isFile() && file.getName().startsWith("tombstone_")) {
addFileToDropBox(db, timestamps, headers, file.getPath(), LOG_SIZE,
TAG_TOMBSTONE);
}
} catch (IOException e) {
Slog.e(TAG, "Can't log tombstone", e);
}
writeTimestamps(timestamps);
}
};
sTombstoneObserver.startWatching();
}
2.java/native crash肴熏。-- crash/native_crash
java/native層異常的區(qū)分在于eventType:crash/native_crash
ActivityManagerService
void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
ApplicationErrorReport.CrashInfo crashInfo) {
//event事件的日志記錄:EventLogTags.AM_CRASH --> am_crash
EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
UserHandle.getUserId(Binder.getCallingUid()), processName,
r == null ? -1 : r.info.flags,
crashInfo.exceptionClassName,
crashInfo.exceptionMessage,
crashInfo.throwFileName,
crashInfo.throwLineNumber);
···
//加入到dropbox
addErrorToDropBox(
eventType, r, processName, null, null, null, null, null, null, crashInfo);
//其他業(yè)務(wù)處理
mAppErrors.crashApplication(r, crashInfo);
}
java層:handleApplicationCrashInner("crash", r, processName, crashInfo);
native層: mAm.handleApplicationCrashInner("native_crash", mApp, mApp.processName, ci);
3.anr 異常鬼雀。-- anr
這里涉及廣播、Service蛙吏、Provider等組件的anr以及觸摸按鍵事件的anr
ProcessRecord
void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo,
String parentShortComponentName, WindowProcessController parentProcess,
boolean aboveSystem, String annotation) {
···
//event事件的日志記錄:EventLogTags.AM_ANR --> am_anr
EventLog.writeEvent(EventLogTags.AM_ANR, userId, pid, processName, info.flags,
annotation);
···
//加入到dropbox
mService.addErrorToDropBox("anr", this, processName, activityShortComponentName,
parentShortComponentName, parentPr, annotation, cpuInfo, tracesFile, null);
···
}
4.wtf(What a Terrible Failure)源哩。--- wtf
android.util.Log.wtf(String, String),應(yīng)用可調(diào)用布局異常點(diǎn)
ActivityManagerService
ProcessRecord handleApplicationWtfInner(int callingUid, int callingPid, IBinder app, String tag,
final ApplicationErrorReport.CrashInfo crashInfo) {
final ProcessRecord r = findAppProcess(app, "WTF");
final String processName = app == null ? "system_server"
: (r == null ? "unknown" : r.processName);
//event事件的日志記錄:EventLogTags.AM_WTF --> am_wtf
EventLog.writeEvent(EventLogTags.AM_WTF, UserHandle.getUserId(callingUid), callingPid,
processName, r == null ? -1 : r.info.flags, tag, crashInfo.exceptionMessage);
···
//加入到dropbox
addErrorToDropBox("wtf", r, processName, null, null, null, tag, null, null, crashInfo);
return r;
}
注意:
當(dāng)系統(tǒng)設(shè)置Settings.Global.WTF_IS_FATAL為1時(shí)鸦做,發(fā)送wtf可kill應(yīng)用
5.strict mode励烦。---**_strictmode
嚴(yán)格模式,主要為性能監(jiān)測(cè)使用
StrictMode (嚴(yán)格模式), 顧名思義, 就是在比正常模式檢測(cè)得更嚴(yán)格, 通常用來(lái)監(jiān)測(cè)不應(yīng)當(dāng)在主線程執(zhí)行的網(wǎng)絡(luò), 文件等操作. 任何 StrictMode 違例都會(huì)被 ActivityManagerService 在 DropBoxManager 中記錄為一次 strict_mode 違例.
ActivityManagerService
public void handleApplicationStrictModeViolation(
IBinder app,
int penaltyMask,
StrictMode.ViolationInfo info) {
···
//需要滿足觸發(fā)dropbox的條件
if ((penaltyMask & StrictMode.PENALTY_DROPBOX) != 0) {
Integer stackFingerprint = info.hashCode();
boolean logIt = true;
···
if (logIt) {//執(zhí)行dropbox業(yè)務(wù)
logStrictModeViolationToDropBox(r, info);
}
}
···
}
private void logStrictModeViolationToDropBox(
ProcessRecord process,
StrictMode.ViolationInfo info) {
if (info == null) {
return;
}
//收集信息泼诱,tag:***_strictmode
···省略···
//加入到dropbox
IoThread.getHandler().post(() -> {
dbox.addText(dropboxTag, res);
});
}
6.lowmem坛掠。低內(nèi)存報(bào)告
ActivityManagerService
final void doLowMemReportIfNeededLocked(ProcessRecord dyingProc) {
// If there are no longer any background processes running,
// and the app that died was not running instrumentation,
// then tell everyone we are now low on memory.
if (!mProcessList.haveBackgroundProcessLocked()) {
···
//event事件的日志記錄:EventLogTags.AM_LOW_MEMORY --> am_low_memory
EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mProcessList.getLruSizeLocked());
···
if (doReport) {//如果報(bào)告,最后調(diào)入reportMemUsage
Message msg = mHandler.obtainMessage(REPORT_MEM_USAGE_MSG, memInfos);
mHandler.sendMessage(msg);
}
···
}
}
void reportMemUsage(ArrayList<ProcessMemInfo> memInfos) {
···
addErrorToDropBox("lowmem", null, "system_server", null,
null, null, tag.toString(), dropBuilder.toString(), null, null);
···
}
7.watchdog
如果 WatchDog 監(jiān)測(cè)到系統(tǒng)進(jìn)程(system_server)出現(xiàn)問(wèn)題, 會(huì)增加一條 watchdog 記錄到 DropBoxManager 中, 并終止系統(tǒng)進(jìn)程的執(zhí)行.
WatchDog
public void run() {
···
while (true) {
···
//event事件的日志記錄:EventLogTags.WATCHDOG --> watchdog
EventLog.writeEvent(EventLogTags.WATCHDOG, name.isEmpty() ? subject : name);
···
/// M: WDT debug enhancement
/// need to wait the AEE dumps all info, then kill system server @{
// Try to add the error to the dropbox, but assuming that the ActivityManager
// itself may be deadlocked. (which has happened, causing this statement to
// deadlock and the watchdog as a whole to be ineffective)
Thread dropboxThread = new Thread("watchdogWriteToDropbox") {
public void run() {
//加入到dropbox
if (mActivity != null) {
mActivity.addErrorToDropBox(
"watchdog", null, "system_server", null, null, null,
name.isEmpty() ? subject : name, cpuInfo, stack, null);
}
StatsLog.write(StatsLog.SYSTEM_SERVER_WATCHDOG_OCCURRED, subject);
}
};
dropboxThread.start();
try {
dropboxThread.join(2000); // wait up to 2 seconds for it to return.
} catch (InterruptedException ignored) {}
···
}
}
8.其他
1)netstats_error/netstats_dump
NetworkStatsService 負(fù)責(zé)收集并持久化存儲(chǔ)網(wǎng)絡(luò)狀態(tài)的統(tǒng)計(jì)數(shù)據(jù), 當(dāng)遇到明顯的網(wǎng)絡(luò)狀態(tài)錯(cuò)誤時(shí), 它會(huì)增加一條 netstats_error 記錄到 DropBoxManager.
NetworkStatsService
private static final String TAG_NETSTATS_ERROR = "netstats_error";
private class DropBoxNonMonotonicObserver implements NonMonotonicObserver<String> {
@Override
public void foundNonMonotonic(NetworkStats left, int leftIndex, NetworkStats right,
int rightIndex, String cookie) {
Log.w(TAG, "Found non-monotonic values; saving to dropbox");
// record error for debugging
final StringBuilder builder = new StringBuilder();
builder.append("found non-monotonic " + cookie + " values at left[" + leftIndex
+ "] - right[" + rightIndex + "]\n");
builder.append("left=").append(left).append('\n');
builder.append("right=").append(right).append('\n');
mContext.getSystemService(DropBoxManager.class).addText(TAG_NETSTATS_ERROR,
builder.toString());
}
@Override
public void foundNonMonotonic(
NetworkStats stats, int statsIndex, String cookie) {
Log.w(TAG, "Found non-monotonic values; saving to dropbox");
final StringBuilder builder = new StringBuilder();
builder.append("Found non-monotonic " + cookie + " values at [" + statsIndex + "]\n");
builder.append("stats=").append(stats).append('\n');
mContext.getSystemService(DropBoxManager.class).addText(TAG_NETSTATS_ERROR,
builder.toString());
}
}
NetworkStatsRecorder
private static final String TAG_NETSTATS_DUMP = "netstats_dump";
private void recoverFromWtf() {
if (DUMP_BEFORE_DELETE) {
···
mDropBox.addData(TAG_NETSTATS_DUMP, os.toByteArray(), 0);
}
···
}
2)BATTERY_DISCHARGE_INFO
BatteryService 負(fù)責(zé)檢測(cè)充電狀態(tài), 并更新手機(jī)電池信息. 當(dāng)遇到明顯的 discharge 事件, 它會(huì)增加一條 BATTERY_DISCHARGE_INFO 記錄到 DropBoxManager.
// TODO: Current code doesn't work since "--unplugged" flag in BSS was purposefully removed.
private void logBatteryStatsLocked() {
···
DropBoxManager db = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
···
try {
···
// add dump file to drop box
db.addFile("BATTERY_DISCHARGE_INFO", dumpFile, DropBoxManager.IS_TEXT);
}
···
}
3)storage_benchmark/storage_trim
StorageManagerService 負(fù)責(zé)存儲(chǔ)設(shè)備管理治筒,例如sdcard或usb mass storage
fstrim提升磁盤性能屉栓,緩解Android卡頓
private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
private static final String TAG_STORAGE_TRIM = "storage_trim";
public void benchmark(String volId, IVoldTaskListener listener) {
···
mVold.benchmark(volId, new IVoldTaskListener.Stub() {
···
final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
dropBox.addText(TAG_STORAGE_BENCHMARK, scrubPath(path)
+ " " + ident + " " + create + " " + run + " " + destroy);
···
});
}
public void fstrim(int flags, IVoldTaskListener listener) {
···
mVold.fstrim(flags, new IVoldTaskListener.Stub() {
@Override
public void onStatus(int status, PersistableBundle extras) {
···
final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path) + " " + bytes + " " + time);
···
}
···
});
···
}
4)network_watchlist_report
NetworkWatchlistService
WatchlistLoggingHandler
private static final String DROPBOX_TAG = "network_watchlist_report";
private void tryAggregateRecords(long lastRecordTime) {
try {
···
if (mDropBoxManager != null && mDropBoxManager.isTagEnabled(DROPBOX_TAG)) {
···
if (encodedResult != null) {
addEncodedReportToDropBox(encodedResult);
}
} else {
···
}
···
} finally {
···
}
}
private void addEncodedReportToDropBox(byte[] encodedReport) {
mDropBoxManager.addData(DROPBOX_TAG, encodedReport, 0);
}
5)incident
frameworks/base/cmds/incidentd
Broadcaster.cpp
Status status = dropbox->addFile(String16("incident"), readFd, 0);
6)keymaster
system/security/keystore
operation_proto_handler.cpp
android::sp<android::os::DropBoxManager> dropbox(new android::os::DropBoxManager);
size_t size = opConfigEvents.ByteSize();
auto data = std::make_unique<uint8_t[]>(size);
opConfigEvents.SerializeWithCachedSizesToArray(data.get());
dropbox->addData(android::String16("keymaster"), data.get(), size, 0);
key_proto_handler.cpp
android::sp<android::os::DropBoxManager> dropbox(new android::os::DropBoxManager());
keyConfig.set_was_creation_successful(wasCreationSuccessful);
size_t size = keyConfig.ByteSize();
auto data = std::make_unique<uint8_t[]>(size);
keyConfig.SerializeWithCachedSizesToArray(data.get());
dropbox->addData(android::String16("keymaster"), data.get(), size, 0);
參考學(xué)習(xí)
http://xiaocong.github.io/blog/2012/11/21/to-introduce-android-dropboxmanager-service/
http://huaqianlee.github.io/2020/11/13/Android/pstore/
http://tjtech.me/analyze-pstore-ramoops-in-android-kernel.html
https://blog.csdn.net/zangdongming/article/details/37729315
https://skytoby.github.io/2019/fstrim/