Loading core/java/android/app/ApplicationErrorReport.java 0 → 100644 +295 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2008 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.app; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; import android.util.Printer; /** * Describes an application error. * * A report has a type, which is one of * <ul> * <li> {@link #TYPE_CRASH} application crash. Information about the crash * is stored in {@link #crashInfo}. * <li> {@link #TYPE_ANR} application not responding. Information about the * ANR is stored in {@link #anrInfo}. * <li> {@link #TYPE_NONE} uninitialized instance of {@link ApplicationErrorReport}. * </ul> * * @hide */ public class ApplicationErrorReport implements Parcelable { /** * Uninitialized error report. */ public static final int TYPE_NONE = 0; /** * An error report about an application crash. */ public static final int TYPE_CRASH = 1; /** * An error report about an application that's not responding. */ public static final int TYPE_ANR = 2; /** * Type of this report. Can be one of {@link #TYPE_NONE}, * {@link #TYPE_CRASH} or {@link #TYPE_ANR}. */ public int type; /** * Package name of the application. */ public String packageName; /** * Package name of the application which installed the application this * report pertains to. * This identifies which Market the application came from. */ public String installerPackageName; /** * Process name of the application. */ public String processName; /** * Time at which the error occurred. */ public long time; /** * If this report is of type {@link #TYPE_CRASH}, contains an instance * of CrashInfo describing the crash; otherwise null. */ public CrashInfo crashInfo; /** * If this report is of type {@link #TYPE_ANR}, contains an instance * of AnrInfo describing the ANR; otherwise null. */ public AnrInfo anrInfo; /** * Create an uninitialized instance of {@link ApplicationErrorReport}. */ public ApplicationErrorReport() { } /** * Create an instance of {@link ApplicationErrorReport} initialized from * a parcel. */ ApplicationErrorReport(Parcel in) { type = in.readInt(); packageName = in.readString(); installerPackageName = in.readString(); processName = in.readString(); time = in.readLong(); switch (type) { case TYPE_CRASH: crashInfo = new CrashInfo(in); break; case TYPE_ANR: anrInfo = new AnrInfo(in); break; } } public void writeToParcel(Parcel dest, int flags) { dest.writeInt(type); dest.writeString(packageName); dest.writeString(installerPackageName); dest.writeString(processName); dest.writeLong(time); switch (type) { case TYPE_CRASH: crashInfo.writeToParcel(dest, flags); break; case TYPE_ANR: anrInfo.writeToParcel(dest, flags); break; } } /** * Describes an application crash. */ public static class CrashInfo { /** * Class name of the exception that caused the crash. */ public String exceptionClassName; /** * File which the exception was thrown from. */ public String throwFileName; /** * Class which the exception was thrown from. */ public String throwClassName; /** * Method which the exception was thrown from. */ public String throwMethodName; /** * Stack trace. */ public String stackTrace; /** * Create an uninitialized instance of CrashInfo. */ public CrashInfo() { } /** * Create an instance of CrashInfo initialized from a Parcel. */ public CrashInfo(Parcel in) { exceptionClassName = in.readString(); throwFileName = in.readString(); throwClassName = in.readString(); throwMethodName = in.readString(); stackTrace = in.readString(); } /** * Save a CrashInfo instance to a parcel. */ public void writeToParcel(Parcel dest, int flags) { dest.writeString(exceptionClassName); dest.writeString(throwFileName); dest.writeString(throwClassName); dest.writeString(throwMethodName); dest.writeString(stackTrace); } /** * Dump a CrashInfo instance to a Printer. */ public void dump(Printer pw, String prefix) { pw.println(prefix + "exceptionClassName: " + exceptionClassName); pw.println(prefix + "throwFileName: " + throwFileName); pw.println(prefix + "throwClassName: " + throwClassName); pw.println(prefix + "throwMethodName: " + throwMethodName); pw.println(prefix + "stackTrace: " + stackTrace); } } /** * Describes an application not responding error. */ public static class AnrInfo { /** * Activity name. */ public String activity; /** * Description of the operation that timed out. */ public String cause; /** * Additional info, including CPU stats. */ public String info; /** * Create an uninitialized instance of AnrInfo. */ public AnrInfo() { } /** * Create an instance of AnrInfo initialized from a Parcel. */ public AnrInfo(Parcel in) { activity = in.readString(); cause = in.readString(); info = in.readString(); } /** * Save an AnrInfo instance to a parcel. */ public void writeToParcel(Parcel dest, int flags) { dest.writeString(activity); dest.writeString(cause); dest.writeString(info); } /** * Dump an AnrInfo instance to a Printer. */ public void dump(Printer pw, String prefix) { pw.println(prefix + "activity: " + activity); pw.println(prefix + "cause: " + cause); pw.println(prefix + "info: " + info); } } public static final Parcelable.Creator<ApplicationErrorReport> CREATOR = new Parcelable.Creator<ApplicationErrorReport>() { public ApplicationErrorReport createFromParcel(Parcel source) { return new ApplicationErrorReport(source); } public ApplicationErrorReport[] newArray(int size) { return new ApplicationErrorReport[size]; } }; public int describeContents() { return 0; } /** * Dump the report to a Printer. */ public void dump(Printer pw, String prefix) { pw.println(prefix + "type: " + type); pw.println(prefix + "packageName: " + packageName); pw.println(prefix + "installerPackageName: " + installerPackageName); pw.println(prefix + "processName: " + processName); pw.println(prefix + "time: " + time); switch (type) { case TYPE_CRASH: crashInfo.dump(pw, prefix); break; case TYPE_ANR: anrInfo.dump(pw, prefix); break; } } } core/res/res/values/strings.xml +2 −0 Original line number Original line Diff line number Diff line Loading @@ -1761,6 +1761,8 @@ <string name="anr_process">Process <xliff:g id="process">%1$s</xliff:g> is not responding.</string> <string name="anr_process">Process <xliff:g id="process">%1$s</xliff:g> is not responding.</string> <!-- Button allowing the user to close an application that is not responding. This will kill the application. --> <!-- Button allowing the user to close an application that is not responding. This will kill the application. --> <string name="force_close">Force close</string> <string name="force_close">Force close</string> <!-- Button allowing the user to send a bug report for application which has encountered an error. --> <string name="report">Report</string> <!-- Button allowing the user to choose to wait for an application that is not responding to become responsive again. --> <!-- Button allowing the user to choose to wait for an application that is not responding to become responsive again. --> <string name="wait">Wait</string> <string name="wait">Wait</string> <!-- Button allowing a developer to connect a debugger to an application that is not responding. --> <!-- Button allowing a developer to connect a debugger to an application that is not responding. --> Loading services/java/com/android/server/am/ActivityManagerService.java +114 −1 Original line number Original line Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.ActivityManagerNative; import android.app.ActivityThread; import android.app.ActivityThread; import android.app.AlertDialog; import android.app.AlertDialog; import android.app.ApplicationErrorReport; import android.app.Dialog; import android.app.Dialog; import android.app.IActivityWatcher; import android.app.IActivityWatcher; import android.app.IApplicationThread; import android.app.IApplicationThread; Loading @@ -41,6 +42,7 @@ import android.app.IThumbnailReceiver; import android.app.Instrumentation; import android.app.Instrumentation; import android.app.PendingIntent; import android.app.PendingIntent; import android.app.ResultInfo; import android.app.ResultInfo; import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.ComponentName; import android.content.ContentResolver; import android.content.ContentResolver; import android.content.Context; import android.content.Context; Loading Loading @@ -78,10 +80,14 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.SystemProperties; import android.provider.Checkin; import android.provider.Checkin; import android.provider.Settings; import android.provider.Settings; import android.server.data.CrashData; import android.server.data.StackTraceElementData; import android.server.data.ThrowableData; import android.text.TextUtils; import android.text.TextUtils; import android.util.Config; import android.util.Config; import android.util.EventLog; import android.util.EventLog; import android.util.Log; import android.util.Log; import android.util.LogPrinter; import android.util.PrintWriterPrinter; import android.util.PrintWriterPrinter; import android.util.SparseArray; import android.util.SparseArray; import android.view.Gravity; import android.view.Gravity; Loading @@ -92,10 +98,13 @@ import android.view.WindowManagerPolicy; import dalvik.system.Zygote; import dalvik.system.Zygote; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.File; import java.io.File; import java.io.FileDescriptor; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; import java.io.PrintWriter; import java.lang.IllegalStateException; import java.lang.IllegalStateException; import java.lang.ref.WeakReference; import java.lang.ref.WeakReference; Loading Loading @@ -7809,6 +7818,30 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return handleAppCrashLocked(app); return handleAppCrashLocked(app); } } private ComponentName getErrorReportReceiver(ProcessRecord app) { IPackageManager pm = ActivityThread.getPackageManager(); try { // was an installer package name specified when this app was // installed? String installerPackageName = pm.getInstallerPackageName(app.info.packageName); if (installerPackageName == null) { return null; } // is there an Activity in this package that handles ACTION_APP_ERROR? Intent intent = new Intent(Intent.ACTION_APP_ERROR); ResolveInfo info = pm.resolveIntentForPackage(intent, null, 0, installerPackageName); if (info == null || info.activityInfo == null) { return null; } return new ComponentName(installerPackageName, info.activityInfo.name); } catch (RemoteException e) { // will return null and no error report will be delivered } return null; } void makeAppNotRespondingLocked(ProcessRecord app, void makeAppNotRespondingLocked(ProcessRecord app, String tag, String shortMsg, String longMsg, byte[] crashData) { String tag, String shortMsg, String longMsg, byte[] crashData) { app.notResponding = true; app.notResponding = true; Loading Loading @@ -7927,6 +7960,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } void startAppProblemLocked(ProcessRecord app) { void startAppProblemLocked(ProcessRecord app) { app.errorReportReceiver = getErrorReportReceiver(app); skipCurrentReceiverLocked(app); skipCurrentReceiverLocked(app); } } Loading Loading @@ -7959,7 +7993,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen public int handleApplicationError(IBinder app, int flags, public int handleApplicationError(IBinder app, int flags, String tag, String shortMsg, String longMsg, byte[] crashData) { String tag, String shortMsg, String longMsg, byte[] crashData) { AppErrorResult result = new AppErrorResult(); AppErrorResult result = new AppErrorResult(); ProcessRecord r = null; ProcessRecord r = null; synchronized (this) { synchronized (this) { if (app != null) { if (app != null) { Loading Loading @@ -8048,16 +8081,96 @@ public final class ActivityManagerService extends ActivityManagerNative implemen int res = result.get(); int res = result.get(); Intent appErrorIntent = null; synchronized (this) { synchronized (this) { if (r != null) { if (r != null) { mProcessCrashTimes.put(r.info.processName, r.info.uid, mProcessCrashTimes.put(r.info.processName, r.info.uid, SystemClock.uptimeMillis()); SystemClock.uptimeMillis()); } } if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) { appErrorIntent = createAppErrorIntentLocked(r); res = AppErrorDialog.FORCE_QUIT; } } if (appErrorIntent != null) { try { mContext.startActivity(appErrorIntent); } catch (ActivityNotFoundException e) { Log.w(TAG, "bug report receiver dissappeared", e); } } } return res; return res; } } Intent createAppErrorIntentLocked(ProcessRecord r) { ApplicationErrorReport report = createAppErrorReportLocked(r); if (report == null) { return null; } Intent result = new Intent(Intent.ACTION_APP_ERROR); result.setComponent(r.errorReportReceiver); result.putExtra(Intent.EXTRA_BUG_REPORT, report); result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); return result; } ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) { if (r.errorReportReceiver == null) { return null; } if (!r.crashing && !r.notResponding) { return null; } try { ApplicationErrorReport report = new ApplicationErrorReport(); report.packageName = r.info.packageName; report.installerPackageName = r.errorReportReceiver.getPackageName(); report.processName = r.processName; if (r.crashing) { report.type = ApplicationErrorReport.TYPE_CRASH; report.crashInfo = new ApplicationErrorReport.CrashInfo(); ByteArrayInputStream byteStream = new ByteArrayInputStream( r.crashingReport.crashData); DataInputStream dataStream = new DataInputStream(byteStream); CrashData crashData = new CrashData(dataStream); ThrowableData throwData = crashData.getThrowableData(); report.time = crashData.getTime(); report.crashInfo.stackTrace = throwData.toString(); // extract the source of the exception, useful for report // clustering while (throwData.getCause() != null) { throwData = throwData.getCause(); } StackTraceElementData trace = throwData.getStackTrace()[0]; report.crashInfo.exceptionClassName = throwData.getType(); report.crashInfo.throwFileName = trace.getFileName(); report.crashInfo.throwClassName = trace.getClassName(); report.crashInfo.throwMethodName = trace.getMethodName(); } else if (r.notResponding) { report.type = ApplicationErrorReport.TYPE_ANR; report.anrInfo = new ApplicationErrorReport.AnrInfo(); report.anrInfo.activity = r.notRespondingReport.tag; report.anrInfo.cause = r.notRespondingReport.shortMsg; report.anrInfo.info = r.notRespondingReport.longMsg; } return report; } catch (IOException e) { // we don't send it } return null; } public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() { public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() { // assume our apps are happy - lazy create the list // assume our apps are happy - lazy create the list List<ActivityManager.ProcessErrorStateInfo> errList = null; List<ActivityManager.ProcessErrorStateInfo> errList = null; Loading services/java/com/android/server/am/AppErrorDialog.java +18 −3 Original line number Original line Diff line number Diff line Loading @@ -19,17 +19,22 @@ package com.android.server.am; import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR; import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR; import android.content.Context; import android.content.Context; import android.content.DialogInterface; import android.content.res.Resources; import android.content.res.Resources; import android.os.Handler; import android.os.Handler; import android.os.Message; import android.os.Message; import android.util.Log; class AppErrorDialog extends BaseErrorDialog { class AppErrorDialog extends BaseErrorDialog { private final static String TAG = "AppErrorDialog"; private final AppErrorResult mResult; private final AppErrorResult mResult; private final ProcessRecord mProc; private final ProcessRecord mProc; // Event 'what' codes // Event 'what' codes static final int FORCE_QUIT = 0; static final int FORCE_QUIT = 0; static final int DEBUG = 1; static final int DEBUG = 1; static final int FORCE_QUIT_AND_REPORT = 2; // 5-minute timeout, then we automatically dismiss the crash dialog // 5-minute timeout, then we automatically dismiss the crash dialog static final long DISMISS_TIMEOUT = 1000 * 60 * 5; static final long DISMISS_TIMEOUT = 1000 * 60 * 5; Loading Loading @@ -58,12 +63,22 @@ class AppErrorDialog extends BaseErrorDialog { setCancelable(false); setCancelable(false); setButton(res.getText(com.android.internal.R.string.force_close), setButton(DialogInterface.BUTTON_POSITIVE, res.getText(com.android.internal.R.string.force_close), mHandler.obtainMessage(FORCE_QUIT)); mHandler.obtainMessage(FORCE_QUIT)); if ((flags&1) != 0) { if ((flags&1) != 0) { setButton(res.getText(com.android.internal.R.string.debug), setButton(DialogInterface.BUTTON_NEUTRAL, res.getText(com.android.internal.R.string.debug), mHandler.obtainMessage(DEBUG)); mHandler.obtainMessage(DEBUG)); } } if (app.errorReportReceiver != null) { setButton(DialogInterface.BUTTON_NEGATIVE, res.getText(com.android.internal.R.string.report), mHandler.obtainMessage(FORCE_QUIT_AND_REPORT)); } setTitle(res.getText(com.android.internal.R.string.aerr_title)); setTitle(res.getText(com.android.internal.R.string.aerr_title)); getWindow().addFlags(FLAG_SYSTEM_ERROR); getWindow().addFlags(FLAG_SYSTEM_ERROR); getWindow().setTitle("Application Error: " + app.info.processName); getWindow().setTitle("Application Error: " + app.info.processName); Loading services/java/com/android/server/am/AppNotRespondingDialog.java +40 −6 Original line number Original line Diff line number Diff line Loading @@ -18,7 +18,10 @@ package com.android.server.am; import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR; import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Resources; import android.content.res.Resources; import android.os.Handler; import android.os.Handler; import android.os.Message; import android.os.Message; Loading @@ -26,6 +29,13 @@ import android.os.Process; import android.util.Log; import android.util.Log; class AppNotRespondingDialog extends BaseErrorDialog { class AppNotRespondingDialog extends BaseErrorDialog { private static final String TAG = "AppNotRespondingDialog"; // Event 'what' codes static final int FORCE_CLOSE = 1; static final int WAIT = 2; static final int WAIT_AND_REPORT = 3; private final ActivityManagerService mService; private final ActivityManagerService mService; private final ProcessRecord mProc; private final ProcessRecord mProc; Loading Loading @@ -67,10 +77,19 @@ class AppNotRespondingDialog extends BaseErrorDialog { ? res.getString(resid, name1.toString(), name2.toString()) ? res.getString(resid, name1.toString(), name2.toString()) : res.getString(resid, name1.toString())); : res.getString(resid, name1.toString())); setButton(res.getText(com.android.internal.R.string.force_close), setButton(DialogInterface.BUTTON_POSITIVE, mHandler.obtainMessage(1)); res.getText(com.android.internal.R.string.force_close), setButton2(res.getText(com.android.internal.R.string.wait), mHandler.obtainMessage(FORCE_CLOSE)); mHandler.obtainMessage(2)); setButton(DialogInterface.BUTTON_NEUTRAL, res.getText(com.android.internal.R.string.wait), mHandler.obtainMessage(WAIT)); if (app.errorReportReceiver != null) { setButton(DialogInterface.BUTTON_NEGATIVE, res.getText(com.android.internal.R.string.report), mHandler.obtainMessage(WAIT_AND_REPORT)); } setTitle(res.getText(com.android.internal.R.string.anr_title)); setTitle(res.getText(com.android.internal.R.string.anr_title)); getWindow().addFlags(FLAG_SYSTEM_ERROR); getWindow().addFlags(FLAG_SYSTEM_ERROR); getWindow().setTitle("Application Not Responding: " + app.info.processName); getWindow().setTitle("Application Not Responding: " + app.info.processName); Loading @@ -81,16 +100,23 @@ class AppNotRespondingDialog extends BaseErrorDialog { private final Handler mHandler = new Handler() { private final Handler mHandler = new Handler() { public void handleMessage(Message msg) { public void handleMessage(Message msg) { Intent appErrorIntent = null; switch (msg.what) { switch (msg.what) { case 1: case FORCE_CLOSE: // Kill the application. // Kill the application. mService.killAppAtUsersRequest(mProc, mService.killAppAtUsersRequest(mProc, AppNotRespondingDialog.this, true); AppNotRespondingDialog.this, true); break; break; case 2: case WAIT_AND_REPORT: case WAIT: // Continue waiting for the application. // Continue waiting for the application. synchronized (mService) { synchronized (mService) { ProcessRecord app = mProc; ProcessRecord app = mProc; if (msg.what == WAIT_AND_REPORT) { appErrorIntent = mService.createAppErrorIntentLocked(app); } app.notResponding = false; app.notResponding = false; app.notRespondingReport = null; app.notRespondingReport = null; if (app.anrDialog == AppNotRespondingDialog.this) { if (app.anrDialog == AppNotRespondingDialog.this) { Loading @@ -99,6 +125,14 @@ class AppNotRespondingDialog extends BaseErrorDialog { } } break; break; } } if (appErrorIntent != null) { try { getContext().startActivity(appErrorIntent); } catch (ActivityNotFoundException e) { Log.w(TAG, "bug report receiver dissappeared", e); } } } } }; }; } } Loading
core/java/android/app/ApplicationErrorReport.java 0 → 100644 +295 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2008 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.app; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; import android.util.Printer; /** * Describes an application error. * * A report has a type, which is one of * <ul> * <li> {@link #TYPE_CRASH} application crash. Information about the crash * is stored in {@link #crashInfo}. * <li> {@link #TYPE_ANR} application not responding. Information about the * ANR is stored in {@link #anrInfo}. * <li> {@link #TYPE_NONE} uninitialized instance of {@link ApplicationErrorReport}. * </ul> * * @hide */ public class ApplicationErrorReport implements Parcelable { /** * Uninitialized error report. */ public static final int TYPE_NONE = 0; /** * An error report about an application crash. */ public static final int TYPE_CRASH = 1; /** * An error report about an application that's not responding. */ public static final int TYPE_ANR = 2; /** * Type of this report. Can be one of {@link #TYPE_NONE}, * {@link #TYPE_CRASH} or {@link #TYPE_ANR}. */ public int type; /** * Package name of the application. */ public String packageName; /** * Package name of the application which installed the application this * report pertains to. * This identifies which Market the application came from. */ public String installerPackageName; /** * Process name of the application. */ public String processName; /** * Time at which the error occurred. */ public long time; /** * If this report is of type {@link #TYPE_CRASH}, contains an instance * of CrashInfo describing the crash; otherwise null. */ public CrashInfo crashInfo; /** * If this report is of type {@link #TYPE_ANR}, contains an instance * of AnrInfo describing the ANR; otherwise null. */ public AnrInfo anrInfo; /** * Create an uninitialized instance of {@link ApplicationErrorReport}. */ public ApplicationErrorReport() { } /** * Create an instance of {@link ApplicationErrorReport} initialized from * a parcel. */ ApplicationErrorReport(Parcel in) { type = in.readInt(); packageName = in.readString(); installerPackageName = in.readString(); processName = in.readString(); time = in.readLong(); switch (type) { case TYPE_CRASH: crashInfo = new CrashInfo(in); break; case TYPE_ANR: anrInfo = new AnrInfo(in); break; } } public void writeToParcel(Parcel dest, int flags) { dest.writeInt(type); dest.writeString(packageName); dest.writeString(installerPackageName); dest.writeString(processName); dest.writeLong(time); switch (type) { case TYPE_CRASH: crashInfo.writeToParcel(dest, flags); break; case TYPE_ANR: anrInfo.writeToParcel(dest, flags); break; } } /** * Describes an application crash. */ public static class CrashInfo { /** * Class name of the exception that caused the crash. */ public String exceptionClassName; /** * File which the exception was thrown from. */ public String throwFileName; /** * Class which the exception was thrown from. */ public String throwClassName; /** * Method which the exception was thrown from. */ public String throwMethodName; /** * Stack trace. */ public String stackTrace; /** * Create an uninitialized instance of CrashInfo. */ public CrashInfo() { } /** * Create an instance of CrashInfo initialized from a Parcel. */ public CrashInfo(Parcel in) { exceptionClassName = in.readString(); throwFileName = in.readString(); throwClassName = in.readString(); throwMethodName = in.readString(); stackTrace = in.readString(); } /** * Save a CrashInfo instance to a parcel. */ public void writeToParcel(Parcel dest, int flags) { dest.writeString(exceptionClassName); dest.writeString(throwFileName); dest.writeString(throwClassName); dest.writeString(throwMethodName); dest.writeString(stackTrace); } /** * Dump a CrashInfo instance to a Printer. */ public void dump(Printer pw, String prefix) { pw.println(prefix + "exceptionClassName: " + exceptionClassName); pw.println(prefix + "throwFileName: " + throwFileName); pw.println(prefix + "throwClassName: " + throwClassName); pw.println(prefix + "throwMethodName: " + throwMethodName); pw.println(prefix + "stackTrace: " + stackTrace); } } /** * Describes an application not responding error. */ public static class AnrInfo { /** * Activity name. */ public String activity; /** * Description of the operation that timed out. */ public String cause; /** * Additional info, including CPU stats. */ public String info; /** * Create an uninitialized instance of AnrInfo. */ public AnrInfo() { } /** * Create an instance of AnrInfo initialized from a Parcel. */ public AnrInfo(Parcel in) { activity = in.readString(); cause = in.readString(); info = in.readString(); } /** * Save an AnrInfo instance to a parcel. */ public void writeToParcel(Parcel dest, int flags) { dest.writeString(activity); dest.writeString(cause); dest.writeString(info); } /** * Dump an AnrInfo instance to a Printer. */ public void dump(Printer pw, String prefix) { pw.println(prefix + "activity: " + activity); pw.println(prefix + "cause: " + cause); pw.println(prefix + "info: " + info); } } public static final Parcelable.Creator<ApplicationErrorReport> CREATOR = new Parcelable.Creator<ApplicationErrorReport>() { public ApplicationErrorReport createFromParcel(Parcel source) { return new ApplicationErrorReport(source); } public ApplicationErrorReport[] newArray(int size) { return new ApplicationErrorReport[size]; } }; public int describeContents() { return 0; } /** * Dump the report to a Printer. */ public void dump(Printer pw, String prefix) { pw.println(prefix + "type: " + type); pw.println(prefix + "packageName: " + packageName); pw.println(prefix + "installerPackageName: " + installerPackageName); pw.println(prefix + "processName: " + processName); pw.println(prefix + "time: " + time); switch (type) { case TYPE_CRASH: crashInfo.dump(pw, prefix); break; case TYPE_ANR: anrInfo.dump(pw, prefix); break; } } }
core/res/res/values/strings.xml +2 −0 Original line number Original line Diff line number Diff line Loading @@ -1761,6 +1761,8 @@ <string name="anr_process">Process <xliff:g id="process">%1$s</xliff:g> is not responding.</string> <string name="anr_process">Process <xliff:g id="process">%1$s</xliff:g> is not responding.</string> <!-- Button allowing the user to close an application that is not responding. This will kill the application. --> <!-- Button allowing the user to close an application that is not responding. This will kill the application. --> <string name="force_close">Force close</string> <string name="force_close">Force close</string> <!-- Button allowing the user to send a bug report for application which has encountered an error. --> <string name="report">Report</string> <!-- Button allowing the user to choose to wait for an application that is not responding to become responsive again. --> <!-- Button allowing the user to choose to wait for an application that is not responding to become responsive again. --> <string name="wait">Wait</string> <string name="wait">Wait</string> <!-- Button allowing a developer to connect a debugger to an application that is not responding. --> <!-- Button allowing a developer to connect a debugger to an application that is not responding. --> Loading
services/java/com/android/server/am/ActivityManagerService.java +114 −1 Original line number Original line Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.ActivityManagerNative; import android.app.ActivityThread; import android.app.ActivityThread; import android.app.AlertDialog; import android.app.AlertDialog; import android.app.ApplicationErrorReport; import android.app.Dialog; import android.app.Dialog; import android.app.IActivityWatcher; import android.app.IActivityWatcher; import android.app.IApplicationThread; import android.app.IApplicationThread; Loading @@ -41,6 +42,7 @@ import android.app.IThumbnailReceiver; import android.app.Instrumentation; import android.app.Instrumentation; import android.app.PendingIntent; import android.app.PendingIntent; import android.app.ResultInfo; import android.app.ResultInfo; import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.ComponentName; import android.content.ContentResolver; import android.content.ContentResolver; import android.content.Context; import android.content.Context; Loading Loading @@ -78,10 +80,14 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.SystemProperties; import android.provider.Checkin; import android.provider.Checkin; import android.provider.Settings; import android.provider.Settings; import android.server.data.CrashData; import android.server.data.StackTraceElementData; import android.server.data.ThrowableData; import android.text.TextUtils; import android.text.TextUtils; import android.util.Config; import android.util.Config; import android.util.EventLog; import android.util.EventLog; import android.util.Log; import android.util.Log; import android.util.LogPrinter; import android.util.PrintWriterPrinter; import android.util.PrintWriterPrinter; import android.util.SparseArray; import android.util.SparseArray; import android.view.Gravity; import android.view.Gravity; Loading @@ -92,10 +98,13 @@ import android.view.WindowManagerPolicy; import dalvik.system.Zygote; import dalvik.system.Zygote; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.File; import java.io.File; import java.io.FileDescriptor; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; import java.io.PrintWriter; import java.lang.IllegalStateException; import java.lang.IllegalStateException; import java.lang.ref.WeakReference; import java.lang.ref.WeakReference; Loading Loading @@ -7809,6 +7818,30 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return handleAppCrashLocked(app); return handleAppCrashLocked(app); } } private ComponentName getErrorReportReceiver(ProcessRecord app) { IPackageManager pm = ActivityThread.getPackageManager(); try { // was an installer package name specified when this app was // installed? String installerPackageName = pm.getInstallerPackageName(app.info.packageName); if (installerPackageName == null) { return null; } // is there an Activity in this package that handles ACTION_APP_ERROR? Intent intent = new Intent(Intent.ACTION_APP_ERROR); ResolveInfo info = pm.resolveIntentForPackage(intent, null, 0, installerPackageName); if (info == null || info.activityInfo == null) { return null; } return new ComponentName(installerPackageName, info.activityInfo.name); } catch (RemoteException e) { // will return null and no error report will be delivered } return null; } void makeAppNotRespondingLocked(ProcessRecord app, void makeAppNotRespondingLocked(ProcessRecord app, String tag, String shortMsg, String longMsg, byte[] crashData) { String tag, String shortMsg, String longMsg, byte[] crashData) { app.notResponding = true; app.notResponding = true; Loading Loading @@ -7927,6 +7960,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } void startAppProblemLocked(ProcessRecord app) { void startAppProblemLocked(ProcessRecord app) { app.errorReportReceiver = getErrorReportReceiver(app); skipCurrentReceiverLocked(app); skipCurrentReceiverLocked(app); } } Loading Loading @@ -7959,7 +7993,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen public int handleApplicationError(IBinder app, int flags, public int handleApplicationError(IBinder app, int flags, String tag, String shortMsg, String longMsg, byte[] crashData) { String tag, String shortMsg, String longMsg, byte[] crashData) { AppErrorResult result = new AppErrorResult(); AppErrorResult result = new AppErrorResult(); ProcessRecord r = null; ProcessRecord r = null; synchronized (this) { synchronized (this) { if (app != null) { if (app != null) { Loading Loading @@ -8048,16 +8081,96 @@ public final class ActivityManagerService extends ActivityManagerNative implemen int res = result.get(); int res = result.get(); Intent appErrorIntent = null; synchronized (this) { synchronized (this) { if (r != null) { if (r != null) { mProcessCrashTimes.put(r.info.processName, r.info.uid, mProcessCrashTimes.put(r.info.processName, r.info.uid, SystemClock.uptimeMillis()); SystemClock.uptimeMillis()); } } if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) { appErrorIntent = createAppErrorIntentLocked(r); res = AppErrorDialog.FORCE_QUIT; } } if (appErrorIntent != null) { try { mContext.startActivity(appErrorIntent); } catch (ActivityNotFoundException e) { Log.w(TAG, "bug report receiver dissappeared", e); } } } return res; return res; } } Intent createAppErrorIntentLocked(ProcessRecord r) { ApplicationErrorReport report = createAppErrorReportLocked(r); if (report == null) { return null; } Intent result = new Intent(Intent.ACTION_APP_ERROR); result.setComponent(r.errorReportReceiver); result.putExtra(Intent.EXTRA_BUG_REPORT, report); result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); return result; } ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) { if (r.errorReportReceiver == null) { return null; } if (!r.crashing && !r.notResponding) { return null; } try { ApplicationErrorReport report = new ApplicationErrorReport(); report.packageName = r.info.packageName; report.installerPackageName = r.errorReportReceiver.getPackageName(); report.processName = r.processName; if (r.crashing) { report.type = ApplicationErrorReport.TYPE_CRASH; report.crashInfo = new ApplicationErrorReport.CrashInfo(); ByteArrayInputStream byteStream = new ByteArrayInputStream( r.crashingReport.crashData); DataInputStream dataStream = new DataInputStream(byteStream); CrashData crashData = new CrashData(dataStream); ThrowableData throwData = crashData.getThrowableData(); report.time = crashData.getTime(); report.crashInfo.stackTrace = throwData.toString(); // extract the source of the exception, useful for report // clustering while (throwData.getCause() != null) { throwData = throwData.getCause(); } StackTraceElementData trace = throwData.getStackTrace()[0]; report.crashInfo.exceptionClassName = throwData.getType(); report.crashInfo.throwFileName = trace.getFileName(); report.crashInfo.throwClassName = trace.getClassName(); report.crashInfo.throwMethodName = trace.getMethodName(); } else if (r.notResponding) { report.type = ApplicationErrorReport.TYPE_ANR; report.anrInfo = new ApplicationErrorReport.AnrInfo(); report.anrInfo.activity = r.notRespondingReport.tag; report.anrInfo.cause = r.notRespondingReport.shortMsg; report.anrInfo.info = r.notRespondingReport.longMsg; } return report; } catch (IOException e) { // we don't send it } return null; } public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() { public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() { // assume our apps are happy - lazy create the list // assume our apps are happy - lazy create the list List<ActivityManager.ProcessErrorStateInfo> errList = null; List<ActivityManager.ProcessErrorStateInfo> errList = null; Loading
services/java/com/android/server/am/AppErrorDialog.java +18 −3 Original line number Original line Diff line number Diff line Loading @@ -19,17 +19,22 @@ package com.android.server.am; import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR; import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR; import android.content.Context; import android.content.Context; import android.content.DialogInterface; import android.content.res.Resources; import android.content.res.Resources; import android.os.Handler; import android.os.Handler; import android.os.Message; import android.os.Message; import android.util.Log; class AppErrorDialog extends BaseErrorDialog { class AppErrorDialog extends BaseErrorDialog { private final static String TAG = "AppErrorDialog"; private final AppErrorResult mResult; private final AppErrorResult mResult; private final ProcessRecord mProc; private final ProcessRecord mProc; // Event 'what' codes // Event 'what' codes static final int FORCE_QUIT = 0; static final int FORCE_QUIT = 0; static final int DEBUG = 1; static final int DEBUG = 1; static final int FORCE_QUIT_AND_REPORT = 2; // 5-minute timeout, then we automatically dismiss the crash dialog // 5-minute timeout, then we automatically dismiss the crash dialog static final long DISMISS_TIMEOUT = 1000 * 60 * 5; static final long DISMISS_TIMEOUT = 1000 * 60 * 5; Loading Loading @@ -58,12 +63,22 @@ class AppErrorDialog extends BaseErrorDialog { setCancelable(false); setCancelable(false); setButton(res.getText(com.android.internal.R.string.force_close), setButton(DialogInterface.BUTTON_POSITIVE, res.getText(com.android.internal.R.string.force_close), mHandler.obtainMessage(FORCE_QUIT)); mHandler.obtainMessage(FORCE_QUIT)); if ((flags&1) != 0) { if ((flags&1) != 0) { setButton(res.getText(com.android.internal.R.string.debug), setButton(DialogInterface.BUTTON_NEUTRAL, res.getText(com.android.internal.R.string.debug), mHandler.obtainMessage(DEBUG)); mHandler.obtainMessage(DEBUG)); } } if (app.errorReportReceiver != null) { setButton(DialogInterface.BUTTON_NEGATIVE, res.getText(com.android.internal.R.string.report), mHandler.obtainMessage(FORCE_QUIT_AND_REPORT)); } setTitle(res.getText(com.android.internal.R.string.aerr_title)); setTitle(res.getText(com.android.internal.R.string.aerr_title)); getWindow().addFlags(FLAG_SYSTEM_ERROR); getWindow().addFlags(FLAG_SYSTEM_ERROR); getWindow().setTitle("Application Error: " + app.info.processName); getWindow().setTitle("Application Error: " + app.info.processName); Loading
services/java/com/android/server/am/AppNotRespondingDialog.java +40 −6 Original line number Original line Diff line number Diff line Loading @@ -18,7 +18,10 @@ package com.android.server.am; import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR; import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Resources; import android.content.res.Resources; import android.os.Handler; import android.os.Handler; import android.os.Message; import android.os.Message; Loading @@ -26,6 +29,13 @@ import android.os.Process; import android.util.Log; import android.util.Log; class AppNotRespondingDialog extends BaseErrorDialog { class AppNotRespondingDialog extends BaseErrorDialog { private static final String TAG = "AppNotRespondingDialog"; // Event 'what' codes static final int FORCE_CLOSE = 1; static final int WAIT = 2; static final int WAIT_AND_REPORT = 3; private final ActivityManagerService mService; private final ActivityManagerService mService; private final ProcessRecord mProc; private final ProcessRecord mProc; Loading Loading @@ -67,10 +77,19 @@ class AppNotRespondingDialog extends BaseErrorDialog { ? res.getString(resid, name1.toString(), name2.toString()) ? res.getString(resid, name1.toString(), name2.toString()) : res.getString(resid, name1.toString())); : res.getString(resid, name1.toString())); setButton(res.getText(com.android.internal.R.string.force_close), setButton(DialogInterface.BUTTON_POSITIVE, mHandler.obtainMessage(1)); res.getText(com.android.internal.R.string.force_close), setButton2(res.getText(com.android.internal.R.string.wait), mHandler.obtainMessage(FORCE_CLOSE)); mHandler.obtainMessage(2)); setButton(DialogInterface.BUTTON_NEUTRAL, res.getText(com.android.internal.R.string.wait), mHandler.obtainMessage(WAIT)); if (app.errorReportReceiver != null) { setButton(DialogInterface.BUTTON_NEGATIVE, res.getText(com.android.internal.R.string.report), mHandler.obtainMessage(WAIT_AND_REPORT)); } setTitle(res.getText(com.android.internal.R.string.anr_title)); setTitle(res.getText(com.android.internal.R.string.anr_title)); getWindow().addFlags(FLAG_SYSTEM_ERROR); getWindow().addFlags(FLAG_SYSTEM_ERROR); getWindow().setTitle("Application Not Responding: " + app.info.processName); getWindow().setTitle("Application Not Responding: " + app.info.processName); Loading @@ -81,16 +100,23 @@ class AppNotRespondingDialog extends BaseErrorDialog { private final Handler mHandler = new Handler() { private final Handler mHandler = new Handler() { public void handleMessage(Message msg) { public void handleMessage(Message msg) { Intent appErrorIntent = null; switch (msg.what) { switch (msg.what) { case 1: case FORCE_CLOSE: // Kill the application. // Kill the application. mService.killAppAtUsersRequest(mProc, mService.killAppAtUsersRequest(mProc, AppNotRespondingDialog.this, true); AppNotRespondingDialog.this, true); break; break; case 2: case WAIT_AND_REPORT: case WAIT: // Continue waiting for the application. // Continue waiting for the application. synchronized (mService) { synchronized (mService) { ProcessRecord app = mProc; ProcessRecord app = mProc; if (msg.what == WAIT_AND_REPORT) { appErrorIntent = mService.createAppErrorIntentLocked(app); } app.notResponding = false; app.notResponding = false; app.notRespondingReport = null; app.notRespondingReport = null; if (app.anrDialog == AppNotRespondingDialog.this) { if (app.anrDialog == AppNotRespondingDialog.this) { Loading @@ -99,6 +125,14 @@ class AppNotRespondingDialog extends BaseErrorDialog { } } break; break; } } if (appErrorIntent != null) { try { getContext().startActivity(appErrorIntent); } catch (ActivityNotFoundException e) { Log.w(TAG, "bug report receiver dissappeared", e); } } } } }; }; } }