diff options
9 files changed, 103 insertions, 1 deletions
diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java index e6452619b508..8874554f928c 100644 --- a/core/java/android/app/ApplicationErrorReport.java +++ b/core/java/android/app/ApplicationErrorReport.java @@ -29,6 +29,7 @@ import android.os.SystemProperties; import android.provider.Settings; import android.util.Printer; import android.util.Slog; + import com.android.internal.util.FastPrintWriter; import java.io.PrintWriter; @@ -333,6 +334,12 @@ public class ApplicationErrorReport implements Parcelable { public String stackTrace; /** + * Crash tag for some context. + * @hide + */ + public String crashTag; + + /** * Create an uninitialized instance of CrashInfo. */ public CrashInfo() { @@ -416,6 +423,7 @@ public class ApplicationErrorReport implements Parcelable { throwMethodName = in.readString(); throwLineNumber = in.readInt(); stackTrace = in.readString(); + crashTag = in.readString(); } /** @@ -430,6 +438,7 @@ public class ApplicationErrorReport implements Parcelable { dest.writeString(throwMethodName); dest.writeInt(throwLineNumber); dest.writeString(stackTrace); + dest.writeString(crashTag); int total = dest.dataPosition()-start; if (Binder.CHECK_PARCEL_SIZE && total > 20*1024) { Slog.d("Error", "ERR: exClass=" + exceptionClassName); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 3a7c00cbb141..0cf101cdcea3 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -10578,6 +10578,15 @@ public class ActivityManagerService extends IActivityManager.Stub StatsLog.write(StatsLog.WTF_OCCURRED, callingUid, tag, processName, callingPid); + final int relaunchReason = r == null ? ActivityRecord.RELAUNCH_REASON_NONE + : r.getWindowProcessController().computeRelaunchReason(); + final String relaunchReasonString = ActivityRecord.relaunchReasonToString(relaunchReason); + if (crashInfo.crashTag == null) { + crashInfo.crashTag = relaunchReasonString; + } else { + crashInfo.crashTag = crashInfo.crashTag + " " + relaunchReasonString; + } + addErrorToDropBox("wtf", r, processName, null, null, tag, null, null, crashInfo); return r; @@ -10732,6 +10741,9 @@ public class ActivityManagerService extends IActivityManager.Stub if (Debug.isDebuggerConnected()) { sb.append("Debugger: Connected\n"); } + if (crashInfo != null && crashInfo.crashTag != null && !crashInfo.crashTag.isEmpty()) { + sb.append("Crash-Tag: ").append(crashInfo.crashTag).append("\n"); + } sb.append("\n"); // Do the rest in a worker thread to avoid blocking the caller on I/O diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 68e70a9634d1..19ea9554e720 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -339,6 +339,17 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo int mStartingWindowState = STARTING_WINDOW_NOT_SHOWN; boolean mTaskOverlay = false; // Task is always on-top of other activities in the task. + // This activity is not being relaunched, or being relaunched for a non-resize reason. + static final int RELAUNCH_REASON_NONE = 0; + // This activity is being relaunched due to windowing mode change. + static final int RELAUNCH_REASON_WINDOWING_MODE_RESIZE = 1; + // This activity is being relaunched due to a free-resize operation. + static final int RELAUNCH_REASON_FREE_RESIZE = 2; + // Marking the reason why this activity is being relaunched. Mainly used to track that this + // activity is being relaunched to fulfill a resize request due to compatibility issues, e.g. in + // pre-NYC apps that don't have a sense of being resized. + int mRelaunchReason = RELAUNCH_REASON_NONE; + TaskDescription taskDescription; // the recents information for this activity boolean mLaunchTaskBehind; // this activity is actively being launched with // ActivityOptions.setLaunchTaskBehind, will be cleared once launch is completed. @@ -2617,6 +2628,15 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo startFreezingScreenLocked(app, globalChanges); forceNewConfig = false; preserveWindow &= isResizeOnlyChange(changes); + final boolean hasResizeChange = hasResizeChange(changes & ~info.getRealConfigChanged()); + if (hasResizeChange) { + final boolean isDragResizing = + getTask().getWindowContainerController().isDragResizing(); + mRelaunchReason = isDragResizing ? RELAUNCH_REASON_FREE_RESIZE + : RELAUNCH_REASON_WINDOWING_MODE_RESIZE; + } else { + mRelaunchReason = RELAUNCH_REASON_NONE; + } if (!attachedToProcess()) { if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Config is destroying non-running " + this); @@ -2738,6 +2758,11 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo | CONFIG_SCREEN_LAYOUT)) == 0; } + private static boolean hasResizeChange(int change) { + return (change & (CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE | CONFIG_ORIENTATION + | CONFIG_SCREEN_LAYOUT)) != 0; + } + void relaunchActivityLocked(boolean andResume, boolean preserveWindow) { if (service.mSuppressResizeConfigChanges && preserveWindow) { configChangeFlags = 0; @@ -3017,6 +3042,17 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo mWindowContainerController.registerRemoteAnimations(definition); } + static String relaunchReasonToString(int relaunchReason) { + switch (relaunchReason) { + case RELAUNCH_REASON_WINDOWING_MODE_RESIZE: + return "window_resize"; + case RELAUNCH_REASON_FREE_RESIZE: + return "free_resize"; + default: + return null; + } + } + @Override public String toString() { if (stringName != null) { diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index accb61f287ea..058c714148a4 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -72,6 +72,8 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_USER_LEAV import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.am.ActivityRecord.RELAUNCH_REASON_FREE_RESIZE; +import static com.android.server.am.ActivityRecord.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; import static com.android.server.am.ActivityStack.ActivityState.DESTROYED; import static com.android.server.am.ActivityStack.ActivityState.DESTROYING; import static com.android.server.am.ActivityStack.ActivityState.FINISHING; @@ -4483,7 +4485,14 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai hasVisibleActivities = true; } final boolean remove; - if ((!r.haveState && !r.stateNotNeeded) || r.finishing) { + if ((r.mRelaunchReason == RELAUNCH_REASON_WINDOWING_MODE_RESIZE + || r.mRelaunchReason == RELAUNCH_REASON_FREE_RESIZE) + && r.launchCount < 3 && !r.finishing) { + // If the process crashed during a resize, always try to relaunch it, unless + // it has failed more than twice. Skip activities that's already finishing + // cleanly by itself. + remove = false; + } else if ((!r.haveState && !r.stateNotNeeded) || r.finishing) { // Don't currently have state for the activity, or // it is finishing -- always remove it. remove = true; diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index b08efde051b7..a7325754f178 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -74,6 +74,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.ActivityManagerService.ANIMATE; import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG; +import static com.android.server.am.ActivityRecord.RELAUNCH_REASON_NONE; import static com.android.server.am.ActivityStack.ActivityState.DESTROYED; import static com.android.server.am.ActivityStack.ActivityState.DESTROYING; import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING; @@ -2100,6 +2101,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D if (isTopDisplayFocusedStack(r.getStack()) || fromTimeout) { booting = checkFinishBootingLocked(); } + + // When activity is idle, we consider the relaunch must be successful, so let's clear + // the flag. + r.mRelaunchReason = RELAUNCH_REASON_NONE; } if (allResumedActivitiesIdle()) { diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java index 20f2ece9565c..ab1ba6cce2f5 100644 --- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java @@ -1195,6 +1195,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (!res) { Slog.i(TAG, "Removing task failed to finish activity"); } + // Explicitly dismissing the activity so reset its relaunch flag. + r.mRelaunchReason = ActivityRecord.RELAUNCH_REASON_NONE; } else { res = tr.getStack().requestFinishActivityLocked(token, resultCode, resultData, "app-request", true); diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 27567a77f1f7..7652dd4d26e1 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -410,6 +410,10 @@ class AppErrors { RescueParty.notePersistentAppCrash(mContext, r.uid); } + final int relaunchReason = r != null + ? r.getWindowProcessController().computeRelaunchReason() + : ActivityRecord.RELAUNCH_REASON_NONE; + AppErrorResult result = new AppErrorResult(); TaskRecord task; synchronized (mService) { @@ -422,6 +426,12 @@ class AppErrors { return; } + // Suppress crash dialog if the process is being relaunched due to a crash during a free + // resize. + if (relaunchReason == ActivityRecord.RELAUNCH_REASON_FREE_RESIZE) { + return; + } + /** * If this process was running instrumentation, finish now - it will be handled in * {@link ActivityManagerService#handleAppDiedLocked}. diff --git a/services/core/java/com/android/server/am/WindowProcessController.java b/services/core/java/com/android/server/am/WindowProcessController.java index 6f3fb8eb9b72..d4c9bcb1c826 100644 --- a/services/core/java/com/android/server/am/WindowProcessController.java +++ b/services/core/java/com/android/server/am/WindowProcessController.java @@ -436,6 +436,19 @@ public class WindowProcessController { return minTaskLayer; } + int computeRelaunchReason() { + synchronized (mAtm.mGlobalLock) { + final int activitiesSize = mActivities.size(); + for (int i = activitiesSize - 1; i >= 0; i--) { + final ActivityRecord r = mActivities.get(i); + if (r.mRelaunchReason != ActivityRecord.RELAUNCH_REASON_NONE) { + return r.mRelaunchReason; + } + } + } + return ActivityRecord.RELAUNCH_REASON_NONE; + } + void clearProfilerIfNeeded() { if (mListener == null) return; // Posting on handler so WM lock isn't held when we call into AM. diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerController.java b/services/core/java/com/android/server/wm/TaskWindowContainerController.java index d83f28ccb31c..8b634b1bb938 100644 --- a/services/core/java/com/android/server/wm/TaskWindowContainerController.java +++ b/services/core/java/com/android/server/wm/TaskWindowContainerController.java @@ -209,6 +209,12 @@ public class TaskWindowContainerController } } + public boolean isDragResizing() { + synchronized (mWindowMap) { + return mContainer.isDragResizing(); + } + } + void reportSnapshotChanged(TaskSnapshot snapshot) { mHandler.obtainMessage(H.REPORT_SNAPSHOT_CHANGED, snapshot).sendToTarget(); } |