From 029b1194ba5a9a12ef5fd279beef9b9f2c58cd00 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Sat, 18 Mar 2023 01:01:20 +0800 Subject: [PATCH] Keep visible process state if process embeds visible activity The top activity in a embedded task may be a different process than the organizer process, and the top activity can occlude all activities belong to the organizer process. Then there is no visible activities in the organizer process, which may cause the organizer process to be frozen due to the background state. Then when bringing the embedded task from background to front, the organizer process may be unable to respose for TaskFragmentOrganizerController#onTransactionHandled which is used for synchronization of animation. Then it will lead to a 5s timeout. Fix: 274017425 Test: atest TaskFragmentOrganizerControllerTest# testOnActivityReparentedToTask_activityNotInOrganizerProcess \ _useTemporaryToken Change-Id: I57ef9ebe95e05842e7f325c1a4775e98c7eb57bd --- .../com/android/server/wm/TaskFragment.java | 37 +++++++- .../server/wm/WindowProcessController.java | 91 ++++++++++++++++--- .../TaskFragmentOrganizerControllerTest.java | 11 +++ 3 files changed, 127 insertions(+), 12 deletions(-) diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 7c57dc17e8024..72878cfeaa128 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -458,6 +458,22 @@ class TaskFragment extends WindowContainer { && organizer.asBinder().equals(mTaskFragmentOrganizer.asBinder()); } + /** + * Returns the process of organizer if this TaskFragment is organized and the activity lives in + * a different process than the organizer. + */ + @Nullable + private WindowProcessController getOrganizerProcessIfDifferent(@Nullable ActivityRecord r) { + if ((r == null || mTaskFragmentOrganizerProcessName == null) + || (mTaskFragmentOrganizerProcessName.equals(r.processName) + && mTaskFragmentOrganizerUid == r.getUid())) { + // No organizer or the process is the same. + return null; + } + return mAtmService.getProcessController(mTaskFragmentOrganizerProcessName, + mTaskFragmentOrganizerUid); + } + void setAnimationParams(@NonNull TaskFragmentAnimationParams animationParams) { mAnimationParams = animationParams; } @@ -815,6 +831,16 @@ class TaskFragment extends WindowContainer { setResumedActivity(record, reason + " - onActivityStateChanged"); mTaskSupervisor.mRecentTasks.add(record.getTask()); } + + // Update the process state for the organizer process if the activity is in a different + // process in case the organizer process may not have activity state change in its process. + final WindowProcessController hostProcess = getOrganizerProcessIfDifferent(record); + if (hostProcess != null) { + mTaskSupervisor.onProcessActivityStateChanged(hostProcess, false /* forceBatch */); + hostProcess.updateProcessInfo(false /* updateServiceConnectionActivities */, + true /* activityChange */, true /* updateOomAdj */, + false /* addPendingTopUid */); + } } /** @@ -1942,6 +1968,11 @@ class TaskFragment extends WindowContainer { addingActivity.inHistory = true; task.onDescendantActivityAdded(taskHadActivity, activityType, addingActivity); } + + final WindowProcessController hostProcess = getOrganizerProcessIfDifferent(addingActivity); + if (hostProcess != null) { + hostProcess.addEmbeddedActivity(addingActivity); + } } @Override @@ -2757,14 +2788,18 @@ class TaskFragment extends WindowContainer { void removeChild(WindowContainer child, boolean removeSelfIfPossible) { super.removeChild(child); + final ActivityRecord r = child.asActivityRecord(); if (BackNavigationController.isScreenshotEnabled()) { //TODO(b/207481538) Remove once the infrastructure to support per-activity screenshot is // implemented - ActivityRecord r = child.asActivityRecord(); if (r != null) { mBackScreenshots.remove(r.mActivityComponent.flattenToString()); } } + final WindowProcessController hostProcess = getOrganizerProcessIfDifferent(r); + if (hostProcess != null) { + hostProcess.removeEmbeddedActivity(r); + } if (removeSelfIfPossible && shouldRemoveSelfOnLastChildRemoval() && !hasChild()) { removeImmediately("removeLastChild " + child); } diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 834b708f3f9a4..8685723a5807d 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -69,6 +69,7 @@ import android.os.Message; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; +import android.util.ArrayMap; import android.util.Log; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -228,8 +229,17 @@ public class WindowProcessController extends ConfigurationContainer mHostActivities = new ArrayList<>(); + private ArrayMap mRemoteActivities; /** Whether our process is currently running a {@link RecentsAnimation} */ private boolean mRunningRecentsAnimation; @@ -857,7 +867,7 @@ public class WindowProcessController extends ConfigurationContainer= 0; --i) { - final ActivityRecord r = mHostActivities.get(i); + private boolean hasEmbeddedWindow() { + if (mRemoteActivities == null) return false; + for (int i = mRemoteActivities.size() - 1; i >= 0; --i) { + if ((mRemoteActivities.valueAt(i)[0] & REMOTE_ACTIVITY_FLAG_HOST_ACTIVITY) == 0) { + continue; + } + final ActivityRecord r = mRemoteActivities.keyAt(i); if (r.isInterestingToUserLocked()) { return true; } @@ -1038,15 +1052,46 @@ public class WindowProcessController extends ConfigurationContainer(); + } + int[] flags = mRemoteActivities.get(r); + if (flags == null) { + mRemoteActivities.put(r, flags = new int[1]); + } + return flags; + } + + private void removeRemoteActivityFlags(ActivityRecord r, int flags) { + if (mRemoteActivities == null) return; + final int index = mRemoteActivities.indexOfKey(r); + if (index < 0) return; + final int[] currentFlags = mRemoteActivities.valueAt(index); + currentFlags[0] &= ~flags; + if (currentFlags[0] == 0) { + mRemoteActivities.removeAt(index); + } } public interface ComputeOomAdjCallback { @@ -1121,6 +1166,16 @@ public class WindowProcessController extends ConfigurationContainer= 0; i--) { + if ((mRemoteActivities.valueAt(i)[0] & REMOTE_ACTIVITY_FLAG_EMBEDDED_ACTIVITY) != 0 + && mRemoteActivities.keyAt(i).isVisibleRequested()) { + stateFlags |= ACTIVITY_STATE_FLAG_IS_VISIBLE; + } + } + } stateFlags |= minTaskLayer & ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER; if (visible) { @@ -1795,7 +1850,21 @@ public class WindowProcessController extends ConfigurationContainer= 0; i--) { + pw.print(prefix); pw.print(" - "); + pw.print(mRemoteActivities.keyAt(i)); pw.print(" flags="); + final int flags = mRemoteActivities.valueAt(i)[0]; + if ((flags & REMOTE_ACTIVITY_FLAG_HOST_ACTIVITY) != 0) { + pw.print("host "); + } + if ((flags & REMOTE_ACTIVITY_FLAG_EMBEDDED_ACTIVITY) != 0) { + pw.print("embedded"); + } + pw.println(); + } + } if (mRecentTasks.size() > 0) { pw.println(prefix + "Recent Tasks:"); for (int i = 0; i < mRecentTasks.size(); i++) { diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java index 378e8bed35246..99ab715ab9871 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java @@ -398,6 +398,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { public void testOnActivityReparentedToTask_activityNotInOrganizerProcess_useTemporaryToken() { final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); + final WindowProcessController organizerProc = mSystemServicesTestRule.addProcess( + "pkg.organizer", DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME, pid, uid); mTaskFragment.setTaskFragmentOrganizer(mOrganizer.getOrganizerToken(), uid, DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME); mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment); @@ -436,6 +438,15 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { // The temporary token can only be used once. assertNull(mController.getReparentActivityFromTemporaryToken(mIOrganizer, change.getActivityToken())); + + // The organizer process should also have visible state by the visible activity in a + // different process. + activity.setVisibleRequested(true); + activity.setState(ActivityRecord.State.RESUMED, "test"); + assertTrue(organizerProc.hasVisibleActivities()); + activity.setVisibleRequested(false); + activity.setState(ActivityRecord.State.STOPPED, "test"); + assertFalse(organizerProc.hasVisibleActivities()); } @Test