Merge "StrictMode: batch drop box writes for system apps" into gingerbread
This commit is contained in:
committed by
Android (Google) Code Review
commit
0c36c96f2a
@ -3102,7 +3102,9 @@ public final class ActivityThread {
|
|||||||
* For system applications on userdebug/eng builds, log stack
|
* For system applications on userdebug/eng builds, log stack
|
||||||
* traces of disk and network access to dropbox for analysis.
|
* 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)) {
|
!"user".equals(Build.TYPE)) {
|
||||||
StrictMode.setThreadBlockingPolicy(
|
StrictMode.setThreadBlockingPolicy(
|
||||||
StrictMode.DISALLOW_DISK_WRITE |
|
StrictMode.DISALLOW_DISK_WRITE |
|
||||||
|
@ -541,6 +541,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
|
|||||||
private final HashSet<Integer> mAlreadyLoggedViolatedStacks = new HashSet<Integer>();
|
private final HashSet<Integer> mAlreadyLoggedViolatedStacks = new HashSet<Integer>();
|
||||||
private static final int MAX_DUP_SUPPRESSED_STACKS = 5000;
|
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
|
* Intent broadcast that we have tried to start, but are
|
||||||
* waiting for its application's process to be created. We only
|
* waiting for its application's process to be created. We only
|
||||||
@ -6115,7 +6124,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (logIt) {
|
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.
|
* 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
|
* @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.
|
* Utility function for addErrorToDropBox and handleStrictModeViolation's logging
|
||||||
* @param eventType to include in the drop box tag ("crash", "wtf", etc.)
|
* to append various headers to the dropbox log text.
|
||||||
* @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,
|
private static void appendDropBoxProcessHeaders(ProcessRecord process, StringBuilder sb) {
|
||||||
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);
|
|
||||||
if (process == null || process.pid == MY_PID) {
|
if (process == null || process.pid == MY_PID) {
|
||||||
sb.append("Process: system_server\n");
|
sb.append("Process: system_server\n");
|
||||||
} else {
|
} else {
|
||||||
@ -6253,6 +6315,45 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
|
|||||||
sb.append("\n");
|
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) {
|
if (activity != null) {
|
||||||
sb.append("Activity: ").append(activity.shortComponentName).append("\n");
|
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("Subject: ").append(subject).append("\n");
|
||||||
}
|
}
|
||||||
sb.append("Build: ").append(Build.FINGERPRINT).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");
|
sb.append("\n");
|
||||||
|
|
||||||
// Do the rest in a worker thread to avoid blocking the caller on I/O
|
// Do the rest in a worker thread to avoid blocking the caller on I/O
|
||||||
|
Reference in New Issue
Block a user