diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/java/android/app/ActivityManager.java | 21 | ||||
-rw-r--r-- | core/java/android/app/ActivityManagerNative.java | 25 | ||||
-rw-r--r-- | core/java/android/app/ApplicationErrorReport.java | 27 | ||||
-rw-r--r-- | core/java/android/app/IActivityController.aidl | 5 | ||||
-rw-r--r-- | core/java/android/app/IActivityManager.java | 8 | ||||
-rw-r--r-- | core/java/android/os/ICheckinService.aidl | 15 | ||||
-rw-r--r-- | core/java/android/provider/Checkin.java | 56 | ||||
-rw-r--r-- | core/java/android/server/data/BuildData.java | 89 | ||||
-rw-r--r-- | core/java/android/server/data/CrashData.java | 145 | ||||
-rw-r--r-- | core/java/android/server/data/StackTraceElementData.java | 80 | ||||
-rw-r--r-- | core/java/android/server/data/ThrowableData.java | 138 | ||||
-rwxr-xr-x | core/java/android/server/data/package.html | 5 | ||||
-rw-r--r-- | core/java/android/util/Log.java | 4 | ||||
-rw-r--r-- | core/java/com/android/internal/os/RuntimeInit.java | 123 | ||||
-rw-r--r-- | core/res/res/values/strings.xml | 2 |
15 files changed, 57 insertions, 686 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index d709deb..676d6d5 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -621,9 +621,15 @@ public class ActivityManager { public String longMsg; /** - * Raw data about the crash (typically a stack trace). + * The stack trace where the error originated. May be null. + * @pending */ - public byte[] crashData; + public String stackTrace; + + /** + * to be deprecated: This value will always be null. + */ + public byte[] crashData = null; public ProcessErrorStateInfo() { } @@ -640,8 +646,7 @@ public class ActivityManager { dest.writeString(tag); dest.writeString(shortMsg); dest.writeString(longMsg); - dest.writeInt(crashData == null ? -1 : crashData.length); - dest.writeByteArray(crashData); + dest.writeString(stackTrace); } public void readFromParcel(Parcel source) { @@ -652,13 +657,7 @@ public class ActivityManager { tag = source.readString(); shortMsg = source.readString(); longMsg = source.readString(); - int cdLen = source.readInt(); - if (cdLen == -1) { - crashData = null; - } else { - crashData = new byte[cdLen]; - source.readByteArray(crashData); - } + stackTrace = source.readString(); } public static final Creator<ProcessErrorStateInfo> CREATOR = diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 3b8aee9..a0498aa 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -982,18 +982,13 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM case HANDLE_APPLICATION_ERROR_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder app = data.readStrongBinder(); - int fl = data.readInt(); String tag = data.readString(); - String shortMsg = data.readString(); - String longMsg = data.readString(); - byte[] crashData = data.createByteArray(); - int res = handleApplicationError(app, fl, tag, shortMsg, longMsg, - crashData); + ApplicationErrorReport.CrashInfo ci = new ApplicationErrorReport.CrashInfo(data); + handleApplicationError(app, tag, ci); reply.writeNoException(); - reply.writeInt(res); return true; } - + case SIGNAL_PERSISTENT_PROCESSES_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); int sig = data.readInt(); @@ -2342,27 +2337,21 @@ class ActivityManagerProxy implements IActivityManager /* this base class version is never called */ return true; } - public int handleApplicationError(IBinder app, int flags, - String tag, String shortMsg, String longMsg, - byte[] crashData) throws RemoteException + public void handleApplicationError(IBinder app, String tag, + ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(app); - data.writeInt(flags); data.writeString(tag); - data.writeString(shortMsg); - data.writeString(longMsg); - data.writeByteArray(crashData); + crashInfo.writeToParcel(data, 0); mRemote.transact(HANDLE_APPLICATION_ERROR_TRANSACTION, data, reply, 0); reply.readException(); - int res = reply.readInt(); reply.recycle(); data.recycle(); - return res; } - + public void signalPersistentProcesses(int sig) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java index aeae5f9..e89b3ad0 100644 --- a/core/java/android/app/ApplicationErrorReport.java +++ b/core/java/android/app/ApplicationErrorReport.java @@ -19,6 +19,8 @@ package android.app; import android.os.Parcel; import android.os.Parcelable; import android.util.Printer; +import java.io.PrintWriter; +import java.io.StringWriter; /** * Describes an application error. @@ -187,6 +189,31 @@ public class ApplicationErrorReport implements Parcelable { } /** + * Create an instance of CrashInfo initialized from an exception. + */ + public CrashInfo(Throwable tr) { + StringWriter sw = new StringWriter(); + tr.printStackTrace(new PrintWriter(sw)); + stackTrace = sw.toString(); + + // Populate fields with the "root cause" exception + while (tr.getCause() != null) { + tr = tr.getCause(); + String msg = tr.getMessage(); + if (msg != null && msg.length() > 0) { + exceptionMessage = msg; + } + } + + exceptionClassName = tr.getClass().getName(); + StackTraceElement trace = tr.getStackTrace()[0]; + throwFileName = trace.getFileName(); + throwClassName = trace.getClassName(); + throwMethodName = trace.getMethodName(); + throwLineNumber = trace.getLineNumber(); + } + + /** * Create an instance of CrashInfo initialized from a Parcel. */ public CrashInfo(Parcel in) { diff --git a/core/java/android/app/IActivityController.aidl b/core/java/android/app/IActivityController.aidl index 8f6b252..804dd61 100644 --- a/core/java/android/app/IActivityController.aidl +++ b/core/java/android/app/IActivityController.aidl @@ -43,8 +43,9 @@ interface IActivityController * normal error recovery (app crash dialog) to occur, false to kill * it immediately. */ - boolean appCrashed(String processName, int pid, String shortMsg, - String longMsg, in byte[] crashData); + boolean appCrashed(String processName, int pid, + String tag, String shortMsg, String longMsg, + long timeMillis, String stackTrace); /** * An application process is not responding. Return 0 to show the "app diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 9f505ac..c890c4c 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -242,11 +242,9 @@ public interface IActivityManager extends IInterface { // Special low-level communication with activity manager. public void startRunning(String pkg, String cls, String action, String data) throws RemoteException; - // Returns 1 if the user wants to debug. - public int handleApplicationError(IBinder app, - int flags, /* 1 == can debug */ - String tag, String shortMsg, String longMsg, - byte[] crashData) throws RemoteException; + + public void handleApplicationError(IBinder app, String tag, + ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException; /* * This will deliver the specified signal to all the persistent processes. Currently only diff --git a/core/java/android/os/ICheckinService.aidl b/core/java/android/os/ICheckinService.aidl index e56b55d..619079a 100644 --- a/core/java/android/os/ICheckinService.aidl +++ b/core/java/android/os/ICheckinService.aidl @@ -26,21 +26,6 @@ import android.os.IParentalControlCallback; * {@hide} */ interface ICheckinService { - /** Synchronously attempt a checkin with the server, return true - * on success. - * @throws IllegalStateException whenever an error occurs. The - * cause of the exception will be the real exception: - * IOException for network errors, JSONException for invalid - * server responses, etc. - */ - boolean checkin(); - - /** Direct submission of crash data; returns after writing the crash. */ - void reportCrashSync(in byte[] crashData); - - /** Asynchronous "fire and forget" version of crash reporting. */ - oneway void reportCrashAsync(in byte[] crashData); - /** Reboot into the recovery system and wipe all user data. */ void masterClear(); diff --git a/core/java/android/provider/Checkin.java b/core/java/android/provider/Checkin.java index 84753ee..75936a1 100644 --- a/core/java/android/provider/Checkin.java +++ b/core/java/android/provider/Checkin.java @@ -23,7 +23,6 @@ import android.content.ContentValues; import android.database.SQLException; import android.net.Uri; import android.os.SystemClock; -import android.server.data.CrashData; import android.util.Log; import java.io.ByteArrayOutputStream; @@ -267,59 +266,4 @@ public final class Checkin { /** {@link SystemClock#elapsedRealtime} of the last time a crash report failed. */ static private volatile long sLastCrashFailureRealtime = -MIN_CRASH_FAILURE_RETRY; - - /** - * Helper function to report a crash. - * - * @param resolver from {@link android.content.Context#getContentResolver} - * @param crash data from {@link android.server.data.CrashData} - * @return URI of the crash report that was added - */ - static public Uri reportCrash(ContentResolver resolver, byte[] crash) { - try { - // If we are in a situation where crash reports fail (such as a full disk), - // it's important that we don't get into a loop trying to report failures. - // So discard all crash reports for a few seconds after reporting fails. - long realtime = SystemClock.elapsedRealtime(); - if (realtime - sLastCrashFailureRealtime < MIN_CRASH_FAILURE_RETRY) { - Log.e(TAG, "Crash logging skipped, too soon after logging failure"); - return null; - } - - // HACK: we don't support BLOB values, so base64 encode it. - byte[] encoded = Base64.encodeBase64(crash); - ContentValues values = new ContentValues(); - values.put(Crashes.DATA, new String(encoded)); - Uri uri = resolver.insert(Crashes.CONTENT_URI, values); - if (uri == null) { - Log.e(TAG, "Error reporting crash"); - sLastCrashFailureRealtime = SystemClock.elapsedRealtime(); - } - return uri; - } catch (Throwable t) { - // To avoid an infinite crash-reporting loop, swallow all errors and exceptions. - Log.e(TAG, "Error reporting crash: " + t); - sLastCrashFailureRealtime = SystemClock.elapsedRealtime(); - return null; - } - } - - /** - * Report a crash in CrashData format. - * - * @param resolver from {@link android.content.Context#getContentResolver} - * @param crash data to report - * @return URI of the crash report that was added - */ - static public Uri reportCrash(ContentResolver resolver, CrashData crash) { - try { - ByteArrayOutputStream data = new ByteArrayOutputStream(); - crash.write(new DataOutputStream(data)); - return reportCrash(resolver, data.toByteArray()); - } catch (Throwable t) { - // Swallow all errors and exceptions when writing crash report - Log.e(TAG, "Error writing crash: " + t); - return null; - } - } } diff --git a/core/java/android/server/data/BuildData.java b/core/java/android/server/data/BuildData.java deleted file mode 100644 index 53ffa3f..0000000 --- a/core/java/android/server/data/BuildData.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.server.data; - -import android.os.Build; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -import static com.android.internal.util.Objects.nonNull; - -/** - * Build data transfer object. Keep in sync. with the server side version. - */ -public class BuildData { - - /** The version of the data returned by write() and understood by the constructor. */ - private static final int VERSION = 0; - - private final String fingerprint; - private final String incrementalVersion; - private final long time; // in *seconds* since the epoch (not msec!) - - public BuildData() { - this.fingerprint = "android:" + Build.FINGERPRINT; - this.incrementalVersion = Build.VERSION.INCREMENTAL; - this.time = Build.TIME / 1000; // msec -> sec - } - - public BuildData(String fingerprint, String incrementalVersion, long time) { - this.fingerprint = nonNull(fingerprint); - this.incrementalVersion = incrementalVersion; - this.time = time; - } - - /*package*/ BuildData(DataInput in) throws IOException { - int dataVersion = in.readInt(); - if (dataVersion != VERSION) { - throw new IOException("Expected " + VERSION + ". Got: " + dataVersion); - } - - this.fingerprint = in.readUTF(); - this.incrementalVersion = Long.toString(in.readLong()); - this.time = in.readLong(); - } - - /*package*/ void write(DataOutput out) throws IOException { - out.writeInt(VERSION); - out.writeUTF(fingerprint); - - // TODO: change the format/version to expect a string for this field. - // Version 0, still used by the server side, expects a long. - long changelist; - try { - changelist = Long.parseLong(incrementalVersion); - } catch (NumberFormatException ex) { - changelist = -1; - } - out.writeLong(changelist); - out.writeLong(time); - } - - public String getFingerprint() { - return fingerprint; - } - - public String getIncrementalVersion() { - return incrementalVersion; - } - - public long getTime() { - return time; - } -} diff --git a/core/java/android/server/data/CrashData.java b/core/java/android/server/data/CrashData.java deleted file mode 100644 index d652bb3..0000000 --- a/core/java/android/server/data/CrashData.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.server.data; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -import static com.android.internal.util.Objects.nonNull; - -/** - * Crash data transfer object. Keep in sync. with the server side version. - */ -public class CrashData { - - final String id; - final String activity; - final long time; - final BuildData buildData; - final ThrowableData throwableData; - final byte[] state; - - public CrashData(String id, String activity, BuildData buildData, - ThrowableData throwableData) { - this.id = nonNull(id); - this.activity = nonNull(activity); - this.buildData = nonNull(buildData); - this.throwableData = nonNull(throwableData); - this.time = System.currentTimeMillis(); - this.state = null; - } - - public CrashData(String id, String activity, BuildData buildData, - ThrowableData throwableData, byte[] state) { - this.id = nonNull(id); - this.activity = nonNull(activity); - this.buildData = nonNull(buildData); - this.throwableData = nonNull(throwableData); - this.time = System.currentTimeMillis(); - this.state = state; - } - - public CrashData(DataInput in) throws IOException { - int dataVersion = in.readInt(); - if (dataVersion != 0 && dataVersion != 1) { - throw new IOException("Expected 0 or 1. Got: " + dataVersion); - } - - this.id = in.readUTF(); - this.activity = in.readUTF(); - this.time = in.readLong(); - this.buildData = new BuildData(in); - this.throwableData = new ThrowableData(in); - if (dataVersion == 1) { - int len = in.readInt(); - if (len == 0) { - this.state = null; - } else { - this.state = new byte[len]; - in.readFully(this.state, 0, len); - } - } else { - this.state = null; - } - } - - public CrashData(String tag, Throwable throwable) { - id = ""; - activity = tag; - buildData = new BuildData(); - throwableData = new ThrowableData(throwable); - time = System.currentTimeMillis(); - state = null; - } - - public void write(DataOutput out) throws IOException { - // version - if (this.state == null) { - out.writeInt(0); - } else { - out.writeInt(1); - } - - out.writeUTF(this.id); - out.writeUTF(this.activity); - out.writeLong(this.time); - buildData.write(out); - throwableData.write(out); - if (this.state != null) { - out.writeInt(this.state.length); - out.write(this.state, 0, this.state.length); - } - } - - public BuildData getBuildData() { - return buildData; - } - - public ThrowableData getThrowableData() { - return throwableData; - } - - public String getId() { - return id; - } - - public String getActivity() { - return activity; - } - - public long getTime() { - return time; - } - - public byte[] getState() { - return state; - } - - /** - * Return a brief description of this CrashData record. The details of the - * representation are subject to change. - * - * @return Returns a String representing the contents of the object. - */ - @Override - public String toString() { - return "[CrashData: id=" + id + " activity=" + activity + " time=" + time + - " buildData=" + buildData.toString() + - " throwableData=" + throwableData.toString() + "]"; - } -} diff --git a/core/java/android/server/data/StackTraceElementData.java b/core/java/android/server/data/StackTraceElementData.java deleted file mode 100644 index 07185a0..0000000 --- a/core/java/android/server/data/StackTraceElementData.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.server.data; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Stack trace element data transfer object. Keep in sync. with the server side - * version. - */ -public class StackTraceElementData { - - final String className; - final String fileName; - final String methodName; - final int lineNumber; - - public StackTraceElementData(StackTraceElement element) { - this.className = element.getClassName(); - - String fileName = element.getFileName(); - this.fileName = fileName == null ? "[unknown source]" : fileName; - - this.methodName = element.getMethodName(); - this.lineNumber = element.getLineNumber(); - } - - public StackTraceElementData(DataInput in) throws IOException { - int dataVersion = in.readInt(); - if (dataVersion != 0) { - throw new IOException("Expected 0. Got: " + dataVersion); - } - - this.className = in.readUTF(); - this.fileName = in.readUTF(); - this.methodName = in.readUTF(); - this.lineNumber = in.readInt(); - } - - void write(DataOutput out) throws IOException { - out.writeInt(0); // version - - out.writeUTF(className); - out.writeUTF(fileName); - out.writeUTF(methodName); - out.writeInt(lineNumber); - } - - public String getClassName() { - return className; - } - - public String getFileName() { - return fileName; - } - - public String getMethodName() { - return methodName; - } - - public int getLineNumber() { - return lineNumber; - } -} diff --git a/core/java/android/server/data/ThrowableData.java b/core/java/android/server/data/ThrowableData.java deleted file mode 100644 index e500aca..0000000 --- a/core/java/android/server/data/ThrowableData.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.server.data; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * Throwable data transfer object. Keep in sync. with the server side version. - */ -public class ThrowableData { - - final String message; - final String type; - final StackTraceElementData[] stackTrace; - final ThrowableData cause; - - public ThrowableData(Throwable throwable) { - this.type = throwable.getClass().getName(); - String message = throwable.getMessage(); - this.message = message == null ? "" : message; - - StackTraceElement[] elements = throwable.getStackTrace(); - this.stackTrace = new StackTraceElementData[elements.length]; - for (int i = 0; i < elements.length; i++) { - this.stackTrace[i] = new StackTraceElementData(elements[i]); - } - - Throwable cause = throwable.getCause(); - this.cause = cause == null ? null : new ThrowableData(cause); - } - - public ThrowableData(DataInput in) throws IOException { - int dataVersion = in.readInt(); - if (dataVersion != 0) { - throw new IOException("Expected 0. Got: " + dataVersion); - } - - this.message = in.readUTF(); - this.type = in.readUTF(); - - int count = in.readInt(); - this.stackTrace = new StackTraceElementData[count]; - for (int i = 0; i < count; i++) { - this.stackTrace[i] = new StackTraceElementData(in); - } - - this.cause = in.readBoolean() ? new ThrowableData(in) : null; - } - - public void write(DataOutput out) throws IOException { - out.writeInt(0); // version - - out.writeUTF(message); - out.writeUTF(type); - - out.writeInt(stackTrace.length); - for (StackTraceElementData elementData : stackTrace) { - elementData.write(out); - } - - out.writeBoolean(cause != null); - if (cause != null) { - cause.write(out); - } - } - - public String getMessage() { - return message; - } - - public String getType() { - return type; - } - - public StackTraceElementData[] getStackTrace() { - return stackTrace; - } - - public ThrowableData getCause() { - return cause; - } - - - public String toString() { - return toString(null); - } - - public String toString(String prefix) { - StringBuilder builder = new StringBuilder(); - append(prefix, builder, this); - return builder.toString(); - } - - private static void append(String prefix, StringBuilder builder, - ThrowableData throwableData) { - if (prefix != null) builder.append(prefix); - builder.append(throwableData.getType()) - .append(": ") - .append(throwableData.getMessage()) - .append('\n'); - for (StackTraceElementData element : throwableData.getStackTrace()) { - if (prefix != null ) builder.append(prefix); - builder.append(" at ") - .append(element.getClassName()) - .append('.') - .append(element.getMethodName()) - .append("(") - .append(element.getFileName()) - .append(':') - .append(element.getLineNumber()) - .append(")\n"); - - } - - ThrowableData cause = throwableData.getCause(); - if (cause != null) { - if (prefix != null ) builder.append(prefix); - builder.append("Caused by: "); - append(prefix, builder, cause); - } - } -} diff --git a/core/java/android/server/data/package.html b/core/java/android/server/data/package.html deleted file mode 100755 index 1c9bf9d..0000000 --- a/core/java/android/server/data/package.html +++ /dev/null @@ -1,5 +0,0 @@ -<html> -<body> - {@hide} -</body> -</html> diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java index 2572679..e95d0be 100644 --- a/core/java/android/util/Log.java +++ b/core/java/android/util/Log.java @@ -216,9 +216,7 @@ public final class Log { * @param tr An exception to log */ public static int e(String tag, String msg, Throwable tr) { - int r = println(ERROR, tag, msg + '\n' + getStackTraceString(tr)); - RuntimeInit.reportException(tag, tr, false); // asynchronous - return r; + return println(ERROR, tag, msg + '\n' + getStackTraceString(tr)); } /** diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java index c782c8c..b7bb72d 100644 --- a/core/java/com/android/internal/os/RuntimeInit.java +++ b/core/java/com/android/internal/os/RuntimeInit.java @@ -17,7 +17,9 @@ package com.android.internal.os; import android.app.ActivityManagerNative; +import android.app.ApplicationErrorReport; import android.app.IActivityManager; +import android.os.Build; import android.os.Debug; import android.os.IBinder; import android.os.ICheckinService; @@ -25,8 +27,6 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; -import android.os.Build; -import android.server.data.CrashData; import android.util.Config; import android.util.Log; @@ -309,51 +309,18 @@ public class RuntimeInit { */ public static void crash(String tag, Throwable t) { if (mApplicationObject != null) { - byte[] crashData = null; try { // Log exception. Log.e(TAG, Log.getStackTraceString(t)); - crashData = marshallException(tag, t); - if (crashData == null) { - throw new NullPointerException("Can't marshall crash data"); - } - } catch (Throwable t2) { - try { - // Log exception as a string so we don't get in an infinite loop. - Log.e(TAG, "Error reporting crash: " - + Log.getStackTraceString(t2)); - } catch (Throwable t3) { - // Do nothing, must be OOM so we can't format the message - } - } - - try { - // Display user-visible error message. - String msg = t.getMessage(); - if (msg == null) { - msg = t.toString(); - } + // Show a message to the user. IActivityManager am = ActivityManagerNative.getDefault(); - try { - int res = am.handleApplicationError(mApplicationObject, - 0, tag, msg, t.toString(), crashData); - // Is waiting for the debugger the right thing? - // For now I have turned off the Debug button, because - // I'm not sure what we should do if it is actually - // selected. - //Log.i(TAG, "Got app error result: " + res); - if (res == 1) { - Debug.waitForDebugger(); - return; - } - } catch (RemoteException e) { - } + am.handleApplicationError(mApplicationObject, tag, + new ApplicationErrorReport.CrashInfo(t)); } catch (Throwable t2) { try { // Log exception as a string so we don't get in an infinite loop. - Log.e(TAG, "Error reporting crash: " - + Log.getStackTraceString(t2)); + Log.e(TAG, "Error reporting crash: " + Log.getStackTraceString(t2)); } catch (Throwable t3) { // Do nothing, must be OOM so we can't format the message } @@ -366,7 +333,6 @@ public class RuntimeInit { try { Log.e(TAG, "*** EXCEPTION IN SYSTEM PROCESS. System will crash."); Log.e(tag, Log.getStackTraceString(t)); - reportException(tag, t, true); // synchronous } catch (Throwable t2) { // Do nothing, must be OOM so we can't format the message } finally { @@ -381,82 +347,6 @@ public class RuntimeInit { private static final AtomicInteger sInReportException = new AtomicInteger(); /** - * Report an error in the current process. The exception information will - * be handed off to the checkin service and eventually uploaded for analysis. - * This is expensive! Only use this when the exception indicates a programming - * error ("should not happen"). - * - * @param tag to use when logging the error - * @param t exception that was generated by the error - * @param sync true to wait for the report, false to "fire and forget" - */ - public static void reportException(String tag, Throwable t, boolean sync) { - if (!initialized) { - // Exceptions during, eg, zygote cannot use this mechanism - return; - } - - // It's important to prevent an infinite crash-reporting loop: - // while this function is running, don't let it be called again. - int reenter = sInReportException.getAndIncrement(); - if (reenter != 0) { - sInReportException.decrementAndGet(); - Log.e(TAG, "Crash logging skipped, already logging another crash"); - return; - } - - // TODO: Enable callers to specify a level (i.e. warn or error). - try { - // Submit crash data to statistics service. - byte[] crashData = marshallException(tag, t); - ICheckinService checkin = ICheckinService.Stub.asInterface( - ServiceManager.getService("checkin")); - if (checkin == null) { - Log.e(TAG, "Crash logging skipped, no checkin service"); - } else if (sync) { - checkin.reportCrashSync(crashData); - } else { - checkin.reportCrashAsync(crashData); - } - } catch (Throwable t2) { - // Log exception as a string so we don't get in an infinite loop. - Log.e(TAG, "Crash logging failed: " + t2); - } finally { - sInReportException.decrementAndGet(); - } - } - - private static byte[] marshallException(String tag, Throwable t) { - // Convert crash data to bytes. - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - DataOutputStream dout = new DataOutputStream(bout); - try { - new CrashData(tag, t).write(dout); - dout.close(); - } catch (IOException e) { - return null; - } - return bout.toByteArray(); - } - - /** - * Replay an encoded CrashData record back into a useable CrashData record. This can be - * helpful for providing debugging output after a process error. - * - * @param crashDataBytes The byte array containing the encoded crash record - * @return new CrashData record, or null if could not create one. - */ - public static CrashData unmarshallException(byte[] crashDataBytes) { - try { - ByteArrayInputStream bin = new ByteArrayInputStream(crashDataBytes); - DataInputStream din = new DataInputStream(bin); - return new CrashData(din); - } catch (IOException e) { - return null; - } - } - - /** * Set the object identifying this application/process, for reporting VM * errors. */ @@ -473,5 +363,4 @@ public class RuntimeInit { } private static IBinder mApplicationObject; - } diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 3683aab..9e72f64 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1844,8 +1844,6 @@ <string name="report">Report</string> <!-- Button allowing the user to choose to wait for an application that is not responding to become responsive again. --> <string name="wait">Wait</string> - <!-- Button allowing a developer to connect a debugger to an application that is not responding. --> - <string name="debug">Debug</string> <!-- Displayed in the title of the chooser for things to do with text that is to be sent to another application. For example, I can send text through SMS or IM. A dialog with those choices would be shown, and this would be the title. --> |