diff options
author | Dan Egnor <egnor@google.com> | 2010-03-12 08:52:28 -0800 |
---|---|---|
committer | Dan Egnor <egnor@google.com> | 2010-03-12 13:01:45 -0800 |
commit | a455d194863d6c09f0388b03271880d7f21e77d6 (patch) | |
tree | 4963132ece1e05c65e965e4892e5c19cfd32174d /services | |
parent | e25bf5dc6357c4cc441846c389b86add3f8489cc (diff) | |
download | frameworks_base-a455d194863d6c09f0388b03271880d7f21e77d6.zip frameworks_base-a455d194863d6c09f0388b03271880d7f21e77d6.tar.gz frameworks_base-a455d194863d6c09f0388b03271880d7f21e77d6.tar.bz2 |
Record some logcat output with crashes, ANRs, etc..
Shelling out to logcat from the system server makes me queasy,
so this is turned off by default -- it must be enabled individually
for each error type (system_app_anr, etc) via a secure settings
value (which I plan to poke into from gservices for internal use).
Even when enabled, it happens in a side thread, unless the system
server is about to die anyway (system server restart).
Change-Id: Id6d88bcd78d3625f0364a5fe9c771046601a5a14
Diffstat (limited to 'services')
-rw-r--r-- | services/java/com/android/server/am/ActivityManagerService.java | 160 |
1 files changed, 103 insertions, 57 deletions
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 8866bbd..a501ceb 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -111,6 +111,7 @@ import java.io.File; import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStreamReader; import java.io.PrintWriter; import java.lang.IllegalStateException; import java.lang.ref.WeakReference; @@ -8960,77 +8961,122 @@ public final class ActivityManagerService extends ActivityManagerNative implemen * @param crashInfo giving an application stack trace, null if absent */ public void addErrorToDropBox(String eventType, - ProcessRecord process, HistoryRecord activity, HistoryRecord parent, - String subject, String report, File logFile, - ApplicationErrorReport.CrashInfo crashInfo) { + ProcessRecord process, HistoryRecord activity, HistoryRecord 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 dropboxTag; + String prefix; if (process == null || process.pid == MY_PID) { - dropboxTag = "system_server_" + eventType; + prefix = "system_server_"; } else if ((process.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { - dropboxTag = "system_app_" + eventType; + prefix = "system_app_"; } else { - dropboxTag = "data_app_" + eventType; + prefix = "data_app_"; } - DropBoxManager dbox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE); - if (dbox != null && dbox.isTagEnabled(dropboxTag)) { - StringBuilder sb = new StringBuilder(1024); - if (process == null || process.pid == MY_PID) { - sb.append("Process: system_server\n"); - } else { - sb.append("Process: ").append(process.processName).append("\n"); - } - if (process != null) { - int flags = process.info.flags; - IPackageManager pm = ActivityThread.getPackageManager(); - sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n"); - for (String pkg : process.pkgList) { - sb.append("Package: ").append(pkg); - try { - PackageInfo pi = pm.getPackageInfo(pkg, 0); - if (pi != null) { - sb.append(" v").append(pi.versionCode); - if (pi.versionName != null) { - sb.append(" (").append(pi.versionName).append(")"); - } + 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) { + sb.append("Process: system_server\n"); + } else { + sb.append("Process: ").append(process.processName).append("\n"); + } + if (process != null) { + int flags = process.info.flags; + IPackageManager pm = ActivityThread.getPackageManager(); + sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n"); + for (String pkg : process.pkgList) { + sb.append("Package: ").append(pkg); + try { + PackageInfo pi = pm.getPackageInfo(pkg, 0); + if (pi != null) { + sb.append(" v").append(pi.versionCode); + if (pi.versionName != null) { + sb.append(" (").append(pi.versionName).append(")"); } - } catch (RemoteException e) { - Slog.e(TAG, "Error getting package info: " + pkg, e); } - sb.append("\n"); + } catch (RemoteException e) { + Slog.e(TAG, "Error getting package info: " + pkg, e); } + sb.append("\n"); } - if (activity != null) { - sb.append("Activity: ").append(activity.shortComponentName).append("\n"); - } - if (parent != null && parent.app != null && parent.app.pid != process.pid) { - sb.append("Parent-Process: ").append(parent.app.processName).append("\n"); - } - if (parent != null && parent != activity) { - sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n"); - } - if (subject != null) { - sb.append("Subject: ").append(subject).append("\n"); - } - sb.append("Build: ").append(Build.FINGERPRINT).append("\n"); - sb.append("\n"); - if (report != null) { - sb.append(report); - } - if (logFile != null) { - try { - sb.append(FileUtils.readTextFile(logFile, 128 * 1024, "\n\n[[TRUNCATED]]")); - } catch (IOException e) { - Slog.e(TAG, "Error reading " + logFile, e); + } + if (activity != null) { + sb.append("Activity: ").append(activity.shortComponentName).append("\n"); + } + if (parent != null && parent.app != null && parent.app.pid != process.pid) { + sb.append("Parent-Process: ").append(parent.app.processName).append("\n"); + } + if (parent != null && parent != activity) { + sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n"); + } + if (subject != null) { + sb.append("Subject: ").append(subject).append("\n"); + } + sb.append("Build: ").append(Build.FINGERPRINT).append("\n"); + sb.append("\n"); + + // Do the rest in a worker thread to avoid blocking the caller on I/O + // (After this point, we shouldn't access AMS internal data structures.) + Thread worker = new Thread("Error dump: " + dropboxTag) { + @Override + public void run() { + if (report != null) { + sb.append(report); } + if (logFile != null) { + try { + sb.append(FileUtils.readTextFile(logFile, 128 * 1024, "\n\n[[TRUNCATED]]")); + } catch (IOException e) { + Slog.e(TAG, "Error reading " + logFile, e); + } + } + if (crashInfo != null && crashInfo.stackTrace != null) { + sb.append(crashInfo.stackTrace); + } + + String setting = Settings.Secure.ERROR_LOGCAT_PREFIX + dropboxTag; + int lines = Settings.Secure.getInt(mContext.getContentResolver(), setting, 0); + if (lines > 0) { + sb.append("\n"); + + // Merge several logcat streams, and take the last N lines + InputStreamReader input = null; + try { + java.lang.Process logcat = new ProcessBuilder("/system/bin/logcat", + "-v", "time", "-b", "events", "-b", "system", "-b", "main", + "-t", String.valueOf(lines)).redirectErrorStream(true).start(); + + try { logcat.getOutputStream().close(); } catch (IOException e) {} + try { logcat.getErrorStream().close(); } catch (IOException e) {} + input = new InputStreamReader(logcat.getInputStream()); + + int num; + char[] buf = new char[8192]; + while ((num = input.read(buf)) > 0) sb.append(buf, 0, num); + } catch (IOException e) { + Slog.e(TAG, "Error running logcat", e); + } finally { + if (input != null) try { input.close(); } catch (IOException e) {} + } + } + + dbox.addText(dropboxTag, sb.toString()); } - if (crashInfo != null && crashInfo.stackTrace != null) { - sb.append(crashInfo.stackTrace); - } - dbox.addText(dropboxTag, sb.toString()); + }; + + if (process == null || process.pid == MY_PID) { + worker.run(); // We may be about to die -- need to run this synchronously + } else { + worker.start(); } } |