Introducing the Android DropBoxManager Service

What is DropBoxManager?
quote
Enqueues chunks of data (from various sources – application crashes, kernel log records, etc.). The queue is size bounded and will drop old data if the enqueued data exceeds the maximum size. You can think of this as a persistent, system-wide, blob-oriented “logcat”.

DropBoxManager is a mechanism introduced by Android in Froyo (API level) to continuously store system data. It is mainly used to record logs when serious problems occur in the kernel, system process, user process, etc. during the Android running process. Continuously stored system-level logcat.

We can obtain this service by calling getSystemService(String) with the parameter DROPBOX_SERVICE, and query all system error records stored in DropBoxManager. What

system errors can Android record by default?

The documentation on which system errors are logged to the DropBoxManager can be found on the website of the DropBoxManager, but we can look at the source code to find the relevant information. From the source code we can find various tags (similar to logcat's tags) logged to the DropBoxManager.

crash (application force close, Force Close)

When the Java layer encounters an exception that is not caught, the ActivityManagerService will record a crash to the DropBoxManager, and a Force Close dialog box will pop up to prompt the user.
public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
    ProcessRecord r = findAppProcess(app, "Crash");
    final String processName = app == null ? "system_server"
            : (r == null ? "unknown" : r.processName);

    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);

    addErrorToDropBox("crash", r, processName, null, null, null, null, null, crashInfo);

    crashApplication(r, crashInfo);
}

anr (Application Not Responding, ANR)

When the application's main thread (UI thread) fails to respond for a long time, ActivityManagerService will record anr to DropBoxManager and pop up the Application Not Responding dialog box to prompt the user.
final void appNotResponding(ProcessRecord app, ActivityRecord activity,
        ActivityRecord parent, boolean aboveSystem, final String annotation) {
    //......
    addErrorToDropBox("anr", app, app.processName, activity, parent, annotation,
            cpuInfo, tracesFile, null);
    //......
}

wtf (What a Terrible Failure)

The 'android.util.Log' class provides a static wtf function that the application can use in the code to actively report a situation that should not happen. Depending on system settings, this function will be added through ActivityManagerService A wtf is logged to the DropBoxManager, and/or terminates the current application process.
public boolean handleApplicationWtf(IBinder app, String tag,
        ApplicationErrorReport.CrashInfo crashInfo) {
    ProcessRecord r = findAppProcess(app, "WTF");
    final String processName = app == null ? "system_server"
            : (r == null ? "unknown" : r.processName);

    EventLog.writeEvent(EventLogTags.AM_WTF,
            UserHandle.getUserId (Binder.getCallingUid ()), Binder.getCallingPid (),
            processName,
            r == null ? -1 : r.info.flags,
            tag, crashInfo.exceptionMessage);

    addErrorToDropBox("wtf", r, processName, null, null, tag, null, null, crashInfo);

    if (r != null && r.pid != Process.myPid() &&
            Settings.Global.getInt(mContext.getContentResolver(),
                    Settings.Global.WTF_IS_FATAL, 0) != 0) {
        crashApplication(r, crashInfo);
        return true;
    } else {
        return false;
    }
}

strict_mode (StrictMode Violation)

StrictMode (strict mode), as the name suggests, is more strict than normal mode detection, usually used to monitor network, file and other operations that should not be performed on the main thread. Any StrictMode violations will be recorded by ActivityManagerService in DropBoxManager for a strict_mode violation.
public void handleApplicationStrictModeViolation(
        IBinder app,
        int violationMask,
        StrictMode.ViolationInfo info) {
    ProcessRecord r = findAppProcess(app, "StrictMode");
    if (r == null) {
        return;
    }

    if ((violationMask & StrictMode.PENALTY_DROPBOX) != 0) {
        Integer stackFingerprint = info.hashCode();
        boolean logIt = true;
        synchronized (mAlreadyLoggedViolatedStacks) {
            if (mAlreadyLoggedViolatedStacks.contains(stackFingerprint)) {
                logIt = false;
                // TODO: sub-sample into EventLog for these, with
                // the info.durationMillis?  Then we'd get
                // the relative pain numbers, without logging all
                // the stack traces repeatedly.  We'd want to do
                // likewise in the client code, which also does
                // dup suppression, before the Binder call.
            } else {
                if (mAlreadyLoggedViolatedStacks.size() >= MAX_DUP_SUPPRESSED_STACKS) {
                    mAlreadyLoggedViolatedStacks.clear();
                }
                mAlreadyLoggedViolatedStacks.add(stackFingerprint);
            }
        }
        if (logIt) {
            logStrictModeViolationToDropBox(r, info);
        }
    }
    //......
}

lowmem (low memory)

When the memory is insufficient, Android will terminate the background application to release the memory, but if no background application can be released, the ActivityManagerService will record a lowmem in the DropBoxManager.
    public void handleMessage(Message msg) {
        switch (msg.what) {
        //...
        case REPORT_MEM_USAGE: {
            //......
            Thread thread = new Thread() {
                @Override public void run() {
                    StringBuilder dropBuilder = new StringBuilder(1024);
                    StringBuilder logBuilder = new StringBuilder(1024);
                    //......
                    addErrorToDropBox("lowmem", null, "system_server", null,
                            null, tag.toString(), dropBuilder.toString(), null, null);
                    //......
                }
            };
            thread.start();
            break;
        }
        //......
    }

watchdog

If WatchDog detects a problem with the system process (system_server), it will add a watchdog record to the DropBoxManager and terminate the execution of the system process.
/** This class calls its monitor every minute. Killing this process if they don't return **/
public class Watchdog extends Thread {
    //......
    @Override
    public void run() {
        boolean waitedHalf = false;
        while (true) {
            //......

            // If we got here, that means that the system is most likely hung.
            // First collect stack traces from all threads of the system process.
            // Then kill this process so that the system will restart.

            //......

            // 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() {
                        mActivity.addErrorToDropBox(
                                "watchdog", null, "system_server", null, null,
                                name, null, stack, null);
                    }
                };
            dropboxThread.start();
            try {
                dropboxThread.join(2000);  // wait up to 2 seconds for it to return.
            } catch (InterruptedException ignored) {}

            //......
        }
    }

    //......
}

netstats_error
NetworkStatsService is responsible for collecting and persistently storing network status statistics. When encountering obvious network status errors, it will add a netstats_error record to DropBoxManager.

BATTERY_DISCHARGE_INFO
BatteryService is responsible for detecting charging status and updating mobile phone battery information. The discharge event, it will add a BATTERY_DISCHARGE_INFO record to DropBoxManager.

Detection after the
system service (System Serve) is started, a series of self-checks will be carried out, including:
booting
each boot will add a SYSTEM_BOOT Record.
System Server restart
If the system service (System Server) is not started for the first time after booting, a SYSTEM_RESTART record will be added. Under normal circumstances, the system service (System Server) will only be started once in a boot, and the second time it is started. Means bug.
Kernel Panic
When Kernel Panic occurs, Kernel will record some log information to the file system, because Kernel has been hung up, of course there is no other chance to log error information at this time. The only way to detect Kernel Panic is to check these after the phone is turned on. Whether the log file exists, if it exists, it means that the last time the phone was down because of Kernel Panic, and records these logs to DropBoxManager. DropBoxManager records the TAG name and the corresponding file name:
SYSTEM_LAST_KMSG, if /proc/last_kmsg exists.
APANIC_CONSOLE, if /data/dontpanic/apanic_console exists.
APANIC_THREADS, if /data/dontpanic/apanic_threads exists.

System Recovery
detects if the device reboots due to system recovery by checking if the file /cache/recovery/log exists, and Add a SYSTEM_RECOVERY_LOG record to DropBoxManager.

private void logBootEvents(Context ctx) throws IOException {
    final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE);
    final SharedPreferences prefs = ctx.getSharedPreferences("log_files", Context.MODE_PRIVATE);
    final String headers = new StringBuilder(512)
        .append("Build: ").append(Build.FINGERPRINT).append("\n")
        .append("Hardware: ").append(Build.BOARD).append("\n")
        .append("Revision: ")
        .append(SystemProperties.get("ro.revision", "")).append("\n")
        .append("Bootloader: ").append(Build.BOOTLOADER).append("\n")
        .append("Radio: ").append(Build.RADIO).append("\n")
        .append("Kernel: ")
        .append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n"))
        .append("\n").toString();

    String recovery = RecoverySystem.handleAftermath();
    if (recovery != null && db != null) {
        db.addText("SYSTEM_RECOVERY_LOG", headers + recovery);
    }

    if (SystemProperties.getLong("ro.runtime.firstboot", 0) == 0) {
        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())
        addFileToDropBox(db, prefs, headers, "/proc/last_kmsg",
                -LOG_SIZE, "SYSTEM_LAST_KMSG");
        addFileToDropBox(db, prefs, headers, "/cache/recovery/log",
                -LOG_SIZE, "SYSTEM_RECOVERY_LOG");
        addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_console",
                -LOG_SIZE, "APANIC_CONSOLE");
        addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_threads",
                -LOG_SIZE, "APANIC_THREADS");
    } else {
        if (db != null) db.addText("SYSTEM_RESTART", headers);
    }

    // Scan existing tombstones (in case any new ones appeared)
    File[] tombstoneFiles = TOMBSTONE_DIR.listFiles();
    for (int i = 0; tombstoneFiles != null && i < tombstoneFiles.length; i++) {
        addFileToDropBox(db, prefs, headers, tombstoneFiles[i].getPath(),
                LOG_SIZE, "SYSTEM_TOMBSTONE");
    }

    // Start watching for new tombstone files; will record them as they occur.
    // This gets registered with the singleton file observer thread.
    sTombstoneObserver = new FileObserver(TOMBSTONE_DIR.getPath(), FileObserver.CLOSE_WRITE) {
        @Override
        public void onEvent(int event, String path) {
            try {
                String filename = new File(TOMBSTONE_DIR, path).getPath();
                addFileToDropBox(db, prefs, headers, filename, LOG_SIZE, "SYSTEM_TOMBSTONE");
            } catch (IOException e) {
                Slog.e(TAG, "Can't log tombstone", e);
            }
        }
    };

    sTombstoneObserver.startWatching();
}

SYSTEM_TOMBSTONE (Crash of the Native process)
Tombstone is a core dump log used by Android to record the crash of the native process. After the system service is started, an Observer will be added to detect changes in the tombstone log file. Whenever a new tombstone file is generated, it will Add a SYSTEM_TOMBSTONE record to DropBoxManager.
How does DropBoxManager store record data?
DropBoxManager uses file storage, all records are stored in the /data/system/dropbox directory, a record is a file, when the size of the text file exceeds the file system DropBoxManager will also automatically compress the file after the minimum block size, usually the filename starts with the TAG parameter of the call to DropBoxManager.

quote
$ adb shell ls -l /data/system/dropbox
-rw------- system   system        258 2012-11-21 11:36 [email protected]
-rw------- system   system         39 2012-11-21 11:40 [email protected]
-rw------- system   system         39 2012-11-21 12:10 [email protected]
-rw------- system   system         34 2012-11-21 18:10 [email protected]
-rw------- system   system         34 2012-11-21 18:40 [email protected]
-rw------- system   system         34 2012-11-22 10:10 [email protected]
-rw------- system   system       1528 2012-11-21 22:54 [email protected]
-rw------- system   system       1877 2012-11-21 11:36 [email protected]
-rw------- system   system       3724 2012-11-21 11:36 [email protected]

How to use DropBoxManager?
Use DropBoxManager to record the error log information that needs to be persistently stored.
DropBoxManager provides another error logging mechanism other than logcat. The program can automatically record relevant information to DropBoxManager when an error occurs. Compared with logcat, DropBoxManager is more suitable for automatic error detection of programs, avoiding errors and omissions caused by human factors. And DropBoxManager is a public service of the Android system. Compared with many private implementations, the probability of compatibility problems will be greatly reduced
.
Combined with the device's BugReport to automatically report errors to the server. Whenever a new record is generated, DropBoxManager will broadcast a DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED Intent, and the device's BugReport service needs to listen to this Intent, and then trigger automatic error reporting.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326686767&siteId=291194637