Add some compatibility support for resizing.
This includes changes to:
1) Allow app crash at most twice during resizing w/o interrupting
resizing process -- this is also necessary to support relaunching pre-N
app when user force maximizing/restoring pre-N apps.
2) Add crash tag to indicate that a crash happens during resizing.
This is one of starter tasks to improve large display UX, and a
spiritual cherry pick of a6364ef4af9e7e78934859f0ae2ea48e678a09c2 and
19bda6841f321ba780577265c90b0d4b7a066b1f.
Bug: 111840655
Test: go/wm-smoke
Change-Id: Ief9e1ee9cefbfd5cfd5047158f2bb1a12b19ed6f
diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java
index e645261..8874554 100644
--- a/core/java/android/app/ApplicationErrorReport.java
+++ b/core/java/android/app/ApplicationErrorReport.java
@@ -29,6 +29,7 @@
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 String stackTrace;
/**
+ * Crash tag for some context.
+ * @hide
+ */
+ public String crashTag;
+
+ /**
* Create an uninitialized instance of CrashInfo.
*/
public CrashInfo() {
@@ -416,6 +423,7 @@
throwMethodName = in.readString();
throwLineNumber = in.readInt();
stackTrace = in.readString();
+ crashTag = in.readString();
}
/**
@@ -430,6 +438,7 @@
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 b5ff8c1..a6b2594 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -11869,6 +11869,15 @@
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;
@@ -12023,6 +12032,9 @@
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 b17aada..2c68d6c 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -338,6 +338,17 @@
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.
@@ -2616,6 +2627,15 @@
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);
@@ -2737,6 +2757,11 @@
| 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;
@@ -3016,6 +3041,17 @@
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 d08784f..d48d3ac 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_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 @@
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 4e39033..242cda5 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_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 @@
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 de732c7..b79d9e9 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -1192,6 +1192,8 @@
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 27567a7..7652dd4 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 @@
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 @@
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 817905a..bd6dbe9 100644
--- a/services/core/java/com/android/server/am/WindowProcessController.java
+++ b/services/core/java/com/android/server/am/WindowProcessController.java
@@ -431,6 +431,19 @@
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 d83f28c..8b634b1 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 boolean isDragResizing() {
+ synchronized (mWindowMap) {
+ return mContainer.isDragResizing();
+ }
+ }
+
void reportSnapshotChanged(TaskSnapshot snapshot) {
mHandler.obtainMessage(H.REPORT_SNAPSHOT_CHANGED, snapshot).sendToTarget();
}