Merge "StrictMode: batch drop box writes for system apps" into gingerbread

This commit is contained in:
Brad Fitzpatrick
2010-07-15 15:43:03 -07:00
committed by Android (Google) Code Review
2 changed files with 138 additions and 38 deletions

View File

@ -3102,7 +3102,9 @@ public final class ActivityThread {
* For system applications on userdebug/eng builds, log stack
* traces of disk and network access to dropbox for analysis.
*/
if ((data.appInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0 &&
if ((data.appInfo.flags &
(ApplicationInfo.FLAG_SYSTEM |
ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0 &&
!"user".equals(Build.TYPE)) {
StrictMode.setThreadBlockingPolicy(
StrictMode.DISALLOW_DISK_WRITE |

View File

@ -541,6 +541,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
private final HashSet<Integer> mAlreadyLoggedViolatedStacks = new HashSet<Integer>();
private static final int MAX_DUP_SUPPRESSED_STACKS = 5000;
/**
* Strict Mode background batched logging state.
*
* The string buffer is guarded by itself, and its lock is also
* used to determine if another batched write is already
* in-flight.
*/
private final StringBuilder mStrictModeBuffer = new StringBuilder();
/**
* Intent broadcast that we have tried to start, but are
* waiting for its application's process to be created. We only
@ -6115,7 +6124,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
if (logIt) {
addErrorToDropBox("strictmode", r, null, null, null, null, null, crashInfo);
logStrictModeViolationToDropBox(r, crashInfo);
}
}
@ -6141,6 +6150,89 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
// Depending on the policy in effect, there could be a bunch of
// these in quick succession so we try to batch these together to
// minimize disk writes, number of dropbox entries, and maximize
// compression, by having more fewer, larger records.
private void logStrictModeViolationToDropBox(ProcessRecord process,
ApplicationErrorReport.CrashInfo crashInfo) {
if (crashInfo == null) {
return;
}
final boolean isSystemApp = process == null ||
(process.info.flags & (ApplicationInfo.FLAG_SYSTEM |
ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0;
final String dropboxTag = isSystemApp ? "system_app_strictmode" : "data_app_strictmode";
final DropBoxManager dbox = (DropBoxManager)
mContext.getSystemService(Context.DROPBOX_SERVICE);
// Exit early if the dropbox isn't configured to accept this report type.
if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return;
boolean bufferWasEmpty;
final StringBuilder sb = isSystemApp ? mStrictModeBuffer : new StringBuilder(1024);
synchronized (sb) {
bufferWasEmpty = sb.length() == 0;
appendDropBoxProcessHeaders(process, sb);
sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
sb.append("System-App: ").append(isSystemApp).append("\n");
if (crashInfo != null && crashInfo.durationMillis != -1) {
sb.append("Duration-Millis: ").append(crashInfo.durationMillis).append("\n");
}
sb.append("\n");
if (crashInfo != null && crashInfo.stackTrace != null) {
sb.append(crashInfo.stackTrace);
}
sb.append("\n");
}
// Non-system apps are isolated with a different tag & policy.
// They're also not batched. Batching is useful during system
// boot with strict system-wide logging policies and lots of
// things firing, but not common with regular apps, which
// won't ship with StrictMode dropboxing enabled.
if (!isSystemApp) {
new Thread("Error dump: " + dropboxTag) {
@Override
public void run() {
dbox.addText(dropboxTag, sb.toString());
}
}.start();
return;
}
// System app batching:
if (!bufferWasEmpty) {
// An existing dropbox-writing thread is outstanding and
// will handle it.
return;
}
// Worker thread to both batch writes and to avoid blocking the caller on I/O.
// (After this point, we shouldn't access AMS internal data structures.)
new Thread("Error dump: " + dropboxTag) {
@Override
public void run() {
// 5 second sleep to let stacks arrive and be batched together
try {
Thread.sleep(5000); // 5 seconds
} catch (InterruptedException e) {}
String errorReport;
synchronized (mStrictModeBuffer) {
errorReport = mStrictModeBuffer.toString();
if (errorReport.length() == 0) {
return;
}
mStrictModeBuffer.delete(0, mStrictModeBuffer.length());
mStrictModeBuffer.trimToSize();
}
dbox.addText(dropboxTag, errorReport);
}
}.start();
}
/**
* Used by {@link Log} via {@link com.android.internal.os.RuntimeInit} to report serious errors.
* @param app object of the crashing app, null for the system server
@ -6194,40 +6286,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
/**
* 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 activity which triggered the error, null if unknown
* @param parent activity related to the error, null if unknown
* @param subject line related to the error, null if absent
* @param report in long form describing the error, null if absent
* @param logFile to include in the report, null if none
* @param crashInfo giving an application stack trace, null if absent
* Utility function for addErrorToDropBox and handleStrictModeViolation's logging
* to append various headers to the dropbox log text.
*/
public void addErrorToDropBox(String eventType,
ProcessRecord process, ActivityRecord activity, ActivityRecord parent, String subject,
final String report, final File logFile,
final ApplicationErrorReport.CrashInfo crashInfo) {
// NOTE -- this must never acquire the ActivityManagerService lock,
// otherwise the watchdog may be prevented from resetting the system.
String prefix;
if (process == null || process.pid == MY_PID) {
prefix = "system_server_";
} else if ((process.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
prefix = "system_app_";
} else {
prefix = "data_app_";
}
final String dropboxTag = prefix + eventType;
final DropBoxManager dbox = (DropBoxManager)
mContext.getSystemService(Context.DROPBOX_SERVICE);
// Exit early if the dropbox isn't configured to accept this report type.
if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return;
final StringBuilder sb = new StringBuilder(1024);
private static void appendDropBoxProcessHeaders(ProcessRecord process, StringBuilder sb) {
if (process == null || process.pid == MY_PID) {
sb.append("Process: system_server\n");
} else {
@ -6253,6 +6315,45 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
sb.append("\n");
}
}
}
private static String processClass(ProcessRecord process) {
if (process == null || process.pid == MY_PID) {
return "system_server";
} else if ((process.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
return "system_app";
} else {
return "data_app";
}
}
/**
* 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 activity which triggered the error, null if unknown
* @param parent activity related to the error, null if unknown
* @param subject line related to the error, null if absent
* @param report in long form describing the error, null if absent
* @param logFile to include in the report, null if none
* @param crashInfo giving an application stack trace, null if absent
*/
public void addErrorToDropBox(String eventType,
ProcessRecord process, ActivityRecord activity, ActivityRecord parent, String subject,
final String report, final File logFile,
final ApplicationErrorReport.CrashInfo crashInfo) {
// NOTE -- this must never acquire the ActivityManagerService lock,
// otherwise the watchdog may be prevented from resetting the system.
final String dropboxTag = processClass(process) + "_" + eventType;
final DropBoxManager dbox = (DropBoxManager)
mContext.getSystemService(Context.DROPBOX_SERVICE);
// Exit early if the dropbox isn't configured to accept this report type.
if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return;
final StringBuilder sb = new StringBuilder(1024);
appendDropBoxProcessHeaders(process, sb);
if (activity != null) {
sb.append("Activity: ").append(activity.shortComponentName).append("\n");
}
@ -6266,9 +6367,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
sb.append("Subject: ").append(subject).append("\n");
}
sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
if (crashInfo != null && crashInfo.durationMillis != -1) {
sb.append("Duration-Millis: ").append(crashInfo.durationMillis).append("\n");
}
sb.append("\n");
// Do the rest in a worker thread to avoid blocking the caller on I/O