Merge change 1860 into donut
* changes: ActivityManagerService sends bug reports on crashes and ANRs
This commit is contained in:
295
core/java/android/app/ApplicationErrorReport.java
Normal file
295
core/java/android/app/ApplicationErrorReport.java
Normal file
@ -0,0 +1,295 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -1757,6 +1757,8 @@
|
||||
<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. -->
|
||||
<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. -->
|
||||
<string name="wait">Wait</string>
|
||||
<!-- Button allowing a developer to connect a debugger to an application that is not responding. -->
|
||||
|
@ -30,6 +30,7 @@ import android.app.ActivityManager;
|
||||
import android.app.ActivityManagerNative;
|
||||
import android.app.ActivityThread;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ApplicationErrorReport;
|
||||
import android.app.Dialog;
|
||||
import android.app.IActivityWatcher;
|
||||
import android.app.IApplicationThread;
|
||||
@ -41,6 +42,7 @@ import android.app.IThumbnailReceiver;
|
||||
import android.app.Instrumentation;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.ResultInfo;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
@ -78,10 +80,14 @@ import android.os.SystemClock;
|
||||
import android.os.SystemProperties;
|
||||
import android.provider.Checkin;
|
||||
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.util.Config;
|
||||
import android.util.EventLog;
|
||||
import android.util.Log;
|
||||
import android.util.LogPrinter;
|
||||
import android.util.PrintWriterPrinter;
|
||||
import android.util.SparseArray;
|
||||
import android.view.Gravity;
|
||||
@ -92,10 +98,13 @@ import android.view.WindowManagerPolicy;
|
||||
|
||||
import dalvik.system.Zygote;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.IllegalStateException;
|
||||
import java.lang.ref.WeakReference;
|
||||
@ -7809,6 +7818,30 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
|
||||
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,
|
||||
String tag, String shortMsg, String longMsg, byte[] crashData) {
|
||||
app.notResponding = true;
|
||||
@ -7927,6 +7960,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
|
||||
}
|
||||
|
||||
void startAppProblemLocked(ProcessRecord app) {
|
||||
app.errorReportReceiver = getErrorReportReceiver(app);
|
||||
skipCurrentReceiverLocked(app);
|
||||
}
|
||||
|
||||
@ -7959,7 +7993,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
|
||||
public int handleApplicationError(IBinder app, int flags,
|
||||
String tag, String shortMsg, String longMsg, byte[] crashData) {
|
||||
AppErrorResult result = new AppErrorResult();
|
||||
|
||||
ProcessRecord r = null;
|
||||
synchronized (this) {
|
||||
if (app != null) {
|
||||
@ -8048,16 +8081,96 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
|
||||
|
||||
int res = result.get();
|
||||
|
||||
Intent appErrorIntent = null;
|
||||
synchronized (this) {
|
||||
if (r != null) {
|
||||
mProcessCrashTimes.put(r.info.processName, r.info.uid,
|
||||
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;
|
||||
}
|
||||
|
||||
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() {
|
||||
// assume our apps are happy - lazy create the list
|
||||
List<ActivityManager.ProcessErrorStateInfo> errList = null;
|
||||
|
@ -19,17 +19,22 @@ package com.android.server.am;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
|
||||
class AppErrorDialog extends BaseErrorDialog {
|
||||
private final static String TAG = "AppErrorDialog";
|
||||
|
||||
private final AppErrorResult mResult;
|
||||
private final ProcessRecord mProc;
|
||||
|
||||
// Event 'what' codes
|
||||
static final int FORCE_QUIT = 0;
|
||||
static final int DEBUG = 1;
|
||||
static final int FORCE_QUIT_AND_REPORT = 2;
|
||||
|
||||
// 5-minute timeout, then we automatically dismiss the crash dialog
|
||||
static final long DISMISS_TIMEOUT = 1000 * 60 * 5;
|
||||
@ -58,12 +63,22 @@ class AppErrorDialog extends BaseErrorDialog {
|
||||
|
||||
setCancelable(false);
|
||||
|
||||
setButton(res.getText(com.android.internal.R.string.force_close),
|
||||
mHandler.obtainMessage(FORCE_QUIT));
|
||||
setButton(DialogInterface.BUTTON_POSITIVE,
|
||||
res.getText(com.android.internal.R.string.force_close),
|
||||
mHandler.obtainMessage(FORCE_QUIT));
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
getWindow().addFlags(FLAG_SYSTEM_ERROR);
|
||||
getWindow().setTitle("Application Error: " + app.info.processName);
|
||||
|
@ -18,7 +18,10 @@ package com.android.server.am;
|
||||
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR;
|
||||
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
@ -26,6 +29,13 @@ import android.os.Process;
|
||||
import android.util.Log;
|
||||
|
||||
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 ProcessRecord mProc;
|
||||
|
||||
@ -67,10 +77,19 @@ class AppNotRespondingDialog extends BaseErrorDialog {
|
||||
? res.getString(resid, name1.toString(), name2.toString())
|
||||
: res.getString(resid, name1.toString()));
|
||||
|
||||
setButton(res.getText(com.android.internal.R.string.force_close),
|
||||
mHandler.obtainMessage(1));
|
||||
setButton2(res.getText(com.android.internal.R.string.wait),
|
||||
mHandler.obtainMessage(2));
|
||||
setButton(DialogInterface.BUTTON_POSITIVE,
|
||||
res.getText(com.android.internal.R.string.force_close),
|
||||
mHandler.obtainMessage(FORCE_CLOSE));
|
||||
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));
|
||||
getWindow().addFlags(FLAG_SYSTEM_ERROR);
|
||||
getWindow().setTitle("Application Not Responding: " + app.info.processName);
|
||||
@ -81,16 +100,23 @@ class AppNotRespondingDialog extends BaseErrorDialog {
|
||||
|
||||
private final Handler mHandler = new Handler() {
|
||||
public void handleMessage(Message msg) {
|
||||
Intent appErrorIntent = null;
|
||||
switch (msg.what) {
|
||||
case 1:
|
||||
case FORCE_CLOSE:
|
||||
// Kill the application.
|
||||
mService.killAppAtUsersRequest(mProc,
|
||||
AppNotRespondingDialog.this, true);
|
||||
break;
|
||||
case 2:
|
||||
case WAIT_AND_REPORT:
|
||||
case WAIT:
|
||||
// Continue waiting for the application.
|
||||
synchronized (mService) {
|
||||
ProcessRecord app = mProc;
|
||||
|
||||
if (msg.what == WAIT_AND_REPORT) {
|
||||
appErrorIntent = mService.createAppErrorIntentLocked(app);
|
||||
}
|
||||
|
||||
app.notResponding = false;
|
||||
app.notRespondingReport = null;
|
||||
if (app.anrDialog == AppNotRespondingDialog.this) {
|
||||
@ -99,6 +125,14 @@ class AppNotRespondingDialog extends BaseErrorDialog {
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (appErrorIntent != null) {
|
||||
try {
|
||||
getContext().startActivity(appErrorIntent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Log.w(TAG, "bug report receiver dissappeared", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -107,6 +107,10 @@ class ProcessRecord implements Watchdog.PssRequestor {
|
||||
ActivityManager.ProcessErrorStateInfo crashingReport;
|
||||
ActivityManager.ProcessErrorStateInfo notRespondingReport;
|
||||
|
||||
// Who will be notified of the error. This is usually an activity in the
|
||||
// app that installed the package.
|
||||
ComponentName errorReportReceiver;
|
||||
|
||||
void dump(PrintWriter pw, String prefix) {
|
||||
if (info.className != null) {
|
||||
pw.print(prefix); pw.print("class="); pw.println(info.className);
|
||||
@ -157,7 +161,14 @@ class ProcessRecord implements Watchdog.PssRequestor {
|
||||
pw.print(" "); pw.print(crashDialog);
|
||||
pw.print(" notResponding="); pw.print(notResponding);
|
||||
pw.print(" " ); pw.print(anrDialog);
|
||||
pw.print(" bad="); pw.println(bad);
|
||||
pw.print(" bad="); pw.print(bad);
|
||||
|
||||
// crashing or notResponding is always set before errorReportReceiver
|
||||
if (errorReportReceiver != null) {
|
||||
pw.print(" errorReportReceiver=");
|
||||
pw.print(errorReportReceiver.flattenToShortString());
|
||||
}
|
||||
pw.println();
|
||||
}
|
||||
if (activities.size() > 0) {
|
||||
pw.print(prefix); pw.print("activities="); pw.println(activities);
|
||||
|
Reference in New Issue
Block a user