Merge "Fix crash loop when activity controller was set" into nyc-dev

This commit is contained in:
Andrii Kulian
2016-04-29 19:20:15 +00:00
committed by Android (Google) Code Review

View File

@@ -304,6 +304,15 @@ class AppErrors {
* @param crashInfo describing the failure * @param crashInfo describing the failure
*/ */
void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) { void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
final long origId = Binder.clearCallingIdentity();
try {
crashApplicationInner(r, crashInfo);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
long timeMillis = System.currentTimeMillis(); long timeMillis = System.currentTimeMillis();
String shortMsg = crashInfo.exceptionClassName; String shortMsg = crashInfo.exceptionClassName;
String longMsg = crashInfo.exceptionMessage; String longMsg = crashInfo.exceptionMessage;
@@ -317,49 +326,20 @@ class AppErrors {
AppErrorResult result = new AppErrorResult(); AppErrorResult result = new AppErrorResult();
TaskRecord task; TaskRecord task;
synchronized (mService) { synchronized (mService) {
if (mService.mController != null) { /**
try { * If crash is handled by instance of {@link android.app.IActivityController},
String name = r != null ? r.processName : null; * finish now and don't show the app error dialog.
int pid = r != null ? r.pid : Binder.getCallingPid(); */
int uid = r != null ? r.info.uid : Binder.getCallingUid(); if (handleAppCrashInActivityController(r, crashInfo, shortMsg, longMsg, stackTrace,
if (!mService.mController.appCrashed(name, pid, timeMillis)) {
shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) { return;
if ("1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"))
&& "Native crash".equals(crashInfo.exceptionClassName)) {
Slog.w(TAG, "Skip killing native crashed app " + name
+ "(" + pid + ") during testing");
} else {
Slog.w(TAG, "Force-killing crashed app " + name
+ " at watcher's request");
if (r != null) {
r.kill("crash", true);
} else {
// Huh.
Process.killProcess(pid);
ActivityManagerService.killProcessGroup(uid, pid);
}
}
return;
}
} catch (RemoteException e) {
mService.mController = null;
Watchdog.getInstance().setActivityController(null);
}
} }
final long origId = Binder.clearCallingIdentity(); /**
* If this process was running instrumentation, finish now - it will be handled in
// If this process is running instrumentation, finish it. * {@link ActivityManagerService#handleAppDiedLocked}.
*/
if (r != null && r.instrumentationClass != null) { if (r != null && r.instrumentationClass != null) {
Slog.w(TAG, "Error in app " + r.processName
+ " running instrumentation " + r.instrumentationClass + ":");
if (shortMsg != null) Slog.w(TAG, " " + shortMsg);
if (longMsg != null) Slog.w(TAG, " " + longMsg);
Bundle info = new Bundle();
info.putString("shortMsg", shortMsg);
info.putString("longMsg", longMsg);
mService.finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
Binder.restoreCallingIdentity(origId);
return; return;
} }
@@ -375,7 +355,6 @@ class AppErrors {
// If we can't identify the process or it's already exceeded its crash quota, // If we can't identify the process or it's already exceeded its crash quota,
// quit right away without showing a crash dialog. // quit right away without showing a crash dialog.
if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, data)) { if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, data)) {
Binder.restoreCallingIdentity(origId);
return; return;
} }
@@ -385,97 +364,90 @@ class AppErrors {
task = data.task; task = data.task;
msg.obj = data; msg.obj = data;
mService.mUiHandler.sendMessage(msg); mService.mUiHandler.sendMessage(msg);
Binder.restoreCallingIdentity(origId);
} }
int res = result.get(); int res = result.get();
Intent appErrorIntent = null; Intent appErrorIntent = null;
final long ident = Binder.clearCallingIdentity(); MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_CRASH, res);
try { if (res == AppErrorDialog.TIMEOUT) {
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_CRASH, res); res = AppErrorDialog.FORCE_QUIT;
if (res == AppErrorDialog.TIMEOUT) { }
res = AppErrorDialog.FORCE_QUIT; if (res == AppErrorDialog.RESET) {
} String[] packageList = r.getPackageList();
if (res == AppErrorDialog.RESET) { if (packageList != null) {
String[] packageList = r.getPackageList(); PackageManager pm = mContext.getPackageManager();
if (packageList != null) { final Semaphore s = new Semaphore(0);
PackageManager pm = mContext.getPackageManager(); for (int i = 0; i < packageList.length; i++) {
final Semaphore s = new Semaphore(0); if (i < packageList.length - 1) {
for (int i = 0; i < packageList.length; i++) { pm.deleteApplicationCacheFiles(packageList[i], null);
if (i < packageList.length - 1) { } else {
pm.deleteApplicationCacheFiles(packageList[i], null); pm.deleteApplicationCacheFiles(packageList[i],
} else { new IPackageDataObserver.Stub() {
pm.deleteApplicationCacheFiles(packageList[i], @Override
new IPackageDataObserver.Stub() { public void onRemoveCompleted(String packageName,
@Override boolean succeeded) {
public void onRemoveCompleted(String packageName, s.release();
boolean succeeded) { }
s.release(); });
}
});
// Wait until cache has been cleared before we restart. // Wait until cache has been cleared before we restart.
try {
s.acquire();
} catch (InterruptedException e) {
}
}
}
}
// If there was nothing to reset, just restart;
res = AppErrorDialog.RESTART;
}
synchronized (mService) {
if (res == AppErrorDialog.MUTE) {
stopReportingCrashesLocked(r);
}
if (res == AppErrorDialog.RESTART) {
mService.removeProcessLocked(r, false, true, "crash");
if (task != null) {
try { try {
mService.startActivityFromRecents(task.taskId, s.acquire();
ActivityOptions.makeBasic().toBundle()); } catch (InterruptedException e) {
} catch (IllegalArgumentException e) {
// Hmm, that didn't work, app might have crashed before creating a
// recents entry. Let's see if we have a safe-to-restart intent.
if (task.intent.getCategories().contains(
Intent.CATEGORY_LAUNCHER)) {
mService.startActivityInPackage(task.mCallingUid,
task.mCallingPackage, task.intent,
null, null, null, 0, 0,
ActivityOptions.makeBasic().toBundle(),
task.userId, null, null);
}
} }
} }
} }
if (res == AppErrorDialog.FORCE_QUIT) {
long orig = Binder.clearCallingIdentity();
try {
// Kill it with fire!
mService.mStackSupervisor.handleAppCrashLocked(r);
if (!r.persistent) {
mService.removeProcessLocked(r, false, false, "crash");
mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
} finally {
Binder.restoreCallingIdentity(orig);
}
}
if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
}
if (r != null && !r.isolated && res != AppErrorDialog.RESTART) {
// XXX Can't keep track of crash time for isolated processes,
// since they don't have a persistent identity.
mProcessCrashTimes.put(r.info.processName, r.uid,
SystemClock.uptimeMillis());
}
} }
} finally { // If there was nothing to reset, just restart;
Binder.restoreCallingIdentity(ident); res = AppErrorDialog.RESTART;
}
synchronized (mService) {
if (res == AppErrorDialog.MUTE) {
stopReportingCrashesLocked(r);
}
if (res == AppErrorDialog.RESTART) {
mService.removeProcessLocked(r, false, true, "crash");
if (task != null) {
try {
mService.startActivityFromRecents(task.taskId,
ActivityOptions.makeBasic().toBundle());
} catch (IllegalArgumentException e) {
// Hmm, that didn't work, app might have crashed before creating a
// recents entry. Let's see if we have a safe-to-restart intent.
if (task.intent.getCategories().contains(
Intent.CATEGORY_LAUNCHER)) {
mService.startActivityInPackage(task.mCallingUid,
task.mCallingPackage, task.intent,
null, null, null, 0, 0,
ActivityOptions.makeBasic().toBundle(),
task.userId, null, null);
}
}
}
}
if (res == AppErrorDialog.FORCE_QUIT) {
long orig = Binder.clearCallingIdentity();
try {
// Kill it with fire!
mService.mStackSupervisor.handleAppCrashLocked(r);
if (!r.persistent) {
mService.removeProcessLocked(r, false, false, "crash");
mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
} finally {
Binder.restoreCallingIdentity(orig);
}
}
if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
}
if (r != null && !r.isolated && res != AppErrorDialog.RESTART) {
// XXX Can't keep track of crash time for isolated processes,
// since they don't have a persistent identity.
mProcessCrashTimes.put(r.info.processName, r.uid,
SystemClock.uptimeMillis());
}
} }
if (appErrorIntent != null) { if (appErrorIntent != null) {
@@ -487,6 +459,47 @@ class AppErrors {
} }
} }
private boolean handleAppCrashInActivityController(ProcessRecord r,
ApplicationErrorReport.CrashInfo crashInfo,
String shortMsg, String longMsg,
String stackTrace, long timeMillis) {
if (mService.mController == null) {
return false;
}
try {
String name = r != null ? r.processName : null;
int pid = r != null ? r.pid : Binder.getCallingPid();
int uid = r != null ? r.info.uid : Binder.getCallingUid();
if (!mService.mController.appCrashed(name, pid,
shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
if ("1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"))
&& "Native crash".equals(crashInfo.exceptionClassName)) {
Slog.w(TAG, "Skip killing native crashed app " + name
+ "(" + pid + ") during testing");
} else {
Slog.w(TAG, "Force-killing crashed app " + name
+ " at watcher's request");
if (r != null) {
if (!makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, null))
{
r.kill("crash", true);
}
} else {
// Huh.
Process.killProcess(pid);
ActivityManagerService.killProcessGroup(uid, pid);
}
}
return true;
}
} catch (RemoteException e) {
mService.mController = null;
Watchdog.getInstance().setActivityController(null);
}
return false;
}
private boolean makeAppCrashingLocked(ProcessRecord app, private boolean makeAppCrashingLocked(ProcessRecord app,
String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) { String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
app.crashing = true; app.crashing = true;