Loading services/core/java/com/android/server/wm/ActivityTaskManagerService.java +3 −0 Original line number Diff line number Diff line Loading @@ -732,6 +732,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { WindowOrganizerController mWindowOrganizerController; TaskOrganizerController mTaskOrganizerController; TaskFragmentOrganizerController mTaskFragmentOrganizerController; @Nullable private BackgroundActivityStartCallback mBackgroundActivityStartCallback; Loading Loading @@ -805,6 +806,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", GL_ES_VERSION_UNDEFINED); mWindowOrganizerController = new WindowOrganizerController(this); mTaskOrganizerController = mWindowOrganizerController.mTaskOrganizerController; mTaskFragmentOrganizerController = mWindowOrganizerController.mTaskFragmentOrganizerController; } public void onSystemReady() { Loading services/core/java/com/android/server/wm/RootWindowContainer.java +1 −0 Original line number Diff line number Diff line Loading @@ -858,6 +858,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // Send any pending task-info changes that were queued-up during a layout deferment mWmService.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); mWmService.mAtmService.mTaskFragmentOrganizerController.dispatchPendingEvents(); mWmService.mSyncEngine.onSurfacePlacement(); mWmService.mAnimator.executeAfterPrepareSurfacesRunnables(); Loading services/core/java/com/android/server/wm/TaskFragment.java +17 −5 Original line number Diff line number Diff line Loading @@ -82,6 +82,7 @@ import android.util.DisplayMetrics; import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.view.DisplayInfo; import android.view.SurfaceControl; import android.window.ITaskFragmentOrganizer; import android.window.TaskFragmentInfo; Loading Loading @@ -160,6 +161,11 @@ class TaskFragment extends WindowContainer<WindowContainer> { // The TaskFragment that adjacent to this one. private TaskFragment mAdjacentTaskFragment; /** * Prevents duplicate calls to onTaskAppeared. */ boolean mTaskFragmentAppearedSent; /** * When we are in the process of pausing an activity, before starting the * next one, this variable holds the activity that is currently being paused. Loading Loading @@ -1970,18 +1976,24 @@ class TaskFragment extends WindowContainer<WindowContainer> { @Override public void onConfigurationChanged(Configuration newParentConfig) { super.onConfigurationChanged(newParentConfig); sendTaskFragmentInfoChanged(); } @Override void setSurfaceControl(SurfaceControl sc) { super.setSurfaceControl(sc); // If the TaskFragmentOrganizer was set before we created the SurfaceControl, we need to // emit the callbacks now. sendTaskFragmentAppeared(); } void sendTaskFragmentInfoChanged() { if (mTaskFragmentOrganizer != null) { // Parent config may have changed. The controller will check if there is any important // config change for the organizer. mTaskFragmentOrganizerController .onTaskFragmentParentInfoChanged(mTaskFragmentOrganizer, this); mTaskFragmentOrganizerController .onTaskFragmentInfoChanged(mTaskFragmentOrganizer, this); } } // TODO(b/190433129) call when TaskFragment is created from WCT#createTaskFragment private void sendTaskFragmentAppeared() { if (mTaskFragmentOrganizer != null) { mTaskFragmentOrganizerController.onTaskFragmentAppeared(mTaskFragmentOrganizer, this); Loading services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +264 −84 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.server.wm; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER; import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer; import android.annotation.IntDef; import android.annotation.Nullable; import android.content.res.Configuration; import android.os.Binder; import android.os.IBinder; Loading @@ -33,6 +35,8 @@ import android.window.TaskFragmentInfo; import com.android.internal.protolog.common.ProtoLog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Map; import java.util.WeakHashMap; Loading @@ -45,16 +49,17 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr private final ActivityTaskManagerService mAtmService; private final WindowManagerGlobalLock mGlobalLock; private final Map<TaskFragment, TaskFragmentInfo> mLastSentTaskFragmentInfos = new WeakHashMap<>(); private final Map<TaskFragment, Configuration> mLastSentTaskFragmentParentConfigs = new WeakHashMap<>(); /** * A Map which manages the relationship between * {@link ITaskFragmentOrganizer} and {@link TaskFragmentOrganizerState} */ private final ArrayMap<IBinder, TaskFragmentController> mTaskFragmentOrganizerControllers = private final ArrayMap<IBinder, TaskFragmentOrganizerState> mTaskFragmentOrganizerState = new ArrayMap<>(); /** * A List which manages the TaskFragment pending event {@link PendingTaskFragmentEvent} */ private final ArrayList<PendingTaskFragmentEvent> mPendingTaskFragmentEvents = new ArrayList<>(); TaskFragmentOrganizerController(ActivityTaskManagerService atm) { mAtmService = atm; Loading @@ -65,11 +70,15 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr * A class to manage {@link ITaskFragmentOrganizer} and its organized * {@link TaskFragment TaskFragments}. */ private class TaskFragmentController implements IBinder.DeathRecipient { private class TaskFragmentOrganizerState implements IBinder.DeathRecipient { private final ArrayList<TaskFragment> mOrganizedTaskFragments = new ArrayList<>(); private final ITaskFragmentOrganizer mOrganizer; private final Map<TaskFragment, TaskFragmentInfo> mLastSentTaskFragmentInfos = new WeakHashMap<>(); private final Map<TaskFragment, Configuration> mLastSentTaskFragmentParentConfigs = new WeakHashMap<>(); TaskFragmentController(ITaskFragmentOrganizer organizer) { TaskFragmentOrganizerState(ITaskFragmentOrganizer organizer) { mOrganizer = organizer; try { mOrganizer.asBinder().linkToDeath(this, 0 /*flags*/); Loading @@ -85,10 +94,18 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } } void addTaskFragment(TaskFragment taskFragment) { if (!mOrganizedTaskFragments.contains(taskFragment)) { mOrganizedTaskFragments.add(taskFragment); /** * @return {@code true} if taskFragment is organized and not sent the appeared event before. */ boolean addTaskFragment(TaskFragment taskFragment) { if (taskFragment.mTaskFragmentAppearedSent) { return false; } if (mOrganizedTaskFragments.contains(taskFragment)) { return false; } mOrganizedTaskFragments.add(taskFragment); return true; } void removeTaskFragment(TaskFragment taskFragment) { Loading @@ -100,57 +117,39 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr mOrganizedTaskFragments.clear(); mOrganizer.asBinder().unlinkToDeath(this, 0 /*flags*/); } } @Override public void registerOrganizer(ITaskFragmentOrganizer organizer) { final int pid = Binder.getCallingPid(); final long uid = Binder.getCallingUid(); synchronized (mGlobalLock) { ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register task fragment organizer=%s uid=%d pid=%d", organizer.asBinder(), uid, pid); if (mTaskFragmentOrganizerControllers.containsKey(organizer.asBinder())) { throw new IllegalStateException( "Replacing existing organizer currently unsupported"); } mTaskFragmentOrganizerControllers.put(organizer.asBinder(), new TaskFragmentController(organizer)); } } @Override public void unregisterOrganizer(ITaskFragmentOrganizer organizer) { validateAndGetController(organizer); final int pid = Binder.getCallingPid(); final long uid = Binder.getCallingUid(); synchronized (mGlobalLock) { ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Unregister task fragment organizer=%s uid=%d pid=%d", organizer.asBinder(), uid, pid); removeOrganizer(organizer); } } void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment tf) { final TaskFragmentController controller = validateAndGetController(organizer); ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment appeared name=%s", tf.getName()); final TaskFragmentInfo info = tf.getTaskFragmentInfo(); final SurfaceControl outSurfaceControl = new SurfaceControl(tf.getSurfaceControl(), "TaskFragmentOrganizerController.onTaskFragmentInfoAppeared"); controller.addTaskFragment(tf); try { organizer.onTaskFragmentAppeared( new TaskFragmentAppearedInfo(info, outSurfaceControl)); mLastSentTaskFragmentInfos.put(tf, info); tf.mTaskFragmentAppearedSent = true; } catch (RemoteException e) { Slog.e(TAG, "Exception sending onTaskFragmentAppeared callback", e); } onTaskFragmentParentInfoChanged(organizer, tf); } void onTaskFragmentVanished(ITaskFragmentOrganizer organizer, TaskFragment tf) { ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment vanished name=%s", tf.getName()); try { organizer.onTaskFragmentVanished(tf.getTaskFragmentInfo()); } catch (RemoteException e) { Slog.e(TAG, "Exception sending onTaskFragmentVanished callback", e); } tf.mTaskFragmentAppearedSent = false; mLastSentTaskFragmentInfos.remove(tf); mLastSentTaskFragmentParentConfigs.remove(tf); } void onTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) { validateAndGetController(organizer); // Parent config may have changed. The controller will check if there is any important // config change for the organizer. onTaskFragmentParentInfoChanged(organizer, tf); // Check if the info is different from the last reported info. final TaskFragmentInfo info = tf.getTaskFragmentInfo(); Loading @@ -159,8 +158,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr info.getConfiguration(), lastInfo.getConfiguration())) { return; } ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s", tf.getName()); ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s", tf.getName()); try { organizer.onTaskFragmentInfoChanged(tf.getTaskFragmentInfo()); mLastSentTaskFragmentInfos.put(tf, info); Loading @@ -169,23 +168,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } } void onTaskFragmentVanished(ITaskFragmentOrganizer organizer, TaskFragment tf) { final TaskFragmentController controller = validateAndGetController(organizer); ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment vanished name=%s", tf.getName()); try { organizer.onTaskFragmentVanished(tf.getTaskFragmentInfo()); } catch (RemoteException e) { Slog.e(TAG, "Exception sending onTaskFragmentVanished callback", e); } mLastSentTaskFragmentInfos.remove(tf); mLastSentTaskFragmentParentConfigs.remove(tf); controller.removeTaskFragment(tf); } void onTaskFragmentParentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) { validateAndGetController(organizer); // Check if the parent info is different from the last reported parent info. if (tf.getParent() == null || tf.getParent().asTask() == null) { mLastSentTaskFragmentParentConfigs.remove(tf); Loading @@ -197,7 +180,6 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr if (configurationsAreEqualForOrganizer(parentConfig, lastParentConfig)) { return; } ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment parent info changed name=%s parentTaskId=%d", tf.getName(), parent.mTaskId); Loading @@ -208,12 +190,110 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr Slog.e(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e); } } } @Override public void registerOrganizer(ITaskFragmentOrganizer organizer) { final int pid = Binder.getCallingPid(); final long uid = Binder.getCallingUid(); synchronized (mGlobalLock) { ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register task fragment organizer=%s uid=%d pid=%d", organizer.asBinder(), uid, pid); if (mTaskFragmentOrganizerState.containsKey(organizer.asBinder())) { throw new IllegalStateException( "Replacing existing organizer currently unsupported"); } mTaskFragmentOrganizerState.put(organizer.asBinder(), new TaskFragmentOrganizerState(organizer)); } } @Override public void unregisterOrganizer(ITaskFragmentOrganizer organizer) { validateAndGetState(organizer); final int pid = Binder.getCallingPid(); final long uid = Binder.getCallingUid(); synchronized (mGlobalLock) { ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Unregister task fragment organizer=%s uid=%d pid=%d", organizer.asBinder(), uid, pid); removeOrganizer(organizer); } } void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) { final TaskFragmentOrganizerState state = validateAndGetState(organizer); if (!state.addTaskFragment(taskFragment)) { return; } PendingTaskFragmentEvent pendingEvent = getPendingTaskFragmentEvent(taskFragment, PendingTaskFragmentEvent.EVENT_APPEARED); if (pendingEvent == null) { pendingEvent = new PendingTaskFragmentEvent(taskFragment, organizer, PendingTaskFragmentEvent.EVENT_APPEARED); mPendingTaskFragmentEvents.add(pendingEvent); } } void onTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) { handleTaskFragmentInfoChanged(organizer, taskFragment, PendingTaskFragmentEvent.EVENT_INFO_CHANGED); } void onTaskFragmentParentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) { handleTaskFragmentInfoChanged(organizer, taskFragment, PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED); } private void handleTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment taskFragment, int eventType) { validateAndGetState(organizer); if (!taskFragment.mTaskFragmentAppearedSent) { // Skip if TaskFragment still not appeared. return; } PendingTaskFragmentEvent pendingEvent = getLastPendingLifecycleEvent(taskFragment); if (pendingEvent == null) { pendingEvent = new PendingTaskFragmentEvent(taskFragment, organizer, eventType); } else { if (pendingEvent.mEventType == PendingTaskFragmentEvent.EVENT_VANISHED) { // Skipped the info changed event if vanished event is pending. return; } // Remove and add for re-ordering. mPendingTaskFragmentEvents.remove(pendingEvent); } mPendingTaskFragmentEvents.add(pendingEvent); } void onTaskFragmentVanished(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) { final TaskFragmentOrganizerState state = validateAndGetState(organizer); for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) { PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i); if (taskFragment == entry.mTaskFragment) { mPendingTaskFragmentEvents.remove(i); if (entry.mEventType == PendingTaskFragmentEvent.EVENT_APPEARED) { // If taskFragment appeared callback is pending, ignore the vanished request. return; } } } if (!taskFragment.mTaskFragmentAppearedSent) { return; } PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent(taskFragment, organizer, PendingTaskFragmentEvent.EVENT_VANISHED); mPendingTaskFragmentEvents.add(pendingEvent); state.removeTaskFragment(taskFragment); } private void removeOrganizer(ITaskFragmentOrganizer organizer) { final TaskFragmentController controller = validateAndGetController(organizer); final TaskFragmentOrganizerState state = validateAndGetState(organizer); // remove all of the children of the organized TaskFragment controller.dispose(); mTaskFragmentOrganizerControllers.remove(organizer.asBinder()); state.dispose(); mTaskFragmentOrganizerState.remove(organizer.asBinder()); } /** Loading @@ -222,13 +302,113 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr * we wouldn't register {@link DeathRecipient} for the organizer, and might not remove the * {@link TaskFragment} after the organizer process died. */ private TaskFragmentController validateAndGetController(ITaskFragmentOrganizer organizer) { final TaskFragmentController controller = mTaskFragmentOrganizerControllers.get(organizer.asBinder()); if (controller == null) { private TaskFragmentOrganizerState validateAndGetState(ITaskFragmentOrganizer organizer) { final TaskFragmentOrganizerState state = mTaskFragmentOrganizerState.get(organizer.asBinder()); if (state == null) { throw new IllegalArgumentException( "TaskFragmentOrganizer has not been registered. Organizer=" + organizer); } return controller; return state; } /** * A class to store {@link ITaskFragmentOrganizer} and its organized * {@link TaskFragment TaskFragments} with different pending event request. */ private static class PendingTaskFragmentEvent { static final int EVENT_APPEARED = 0; static final int EVENT_VANISHED = 1; static final int EVENT_INFO_CHANGED = 2; static final int EVENT_PARENT_INFO_CHANGED = 3; @IntDef(prefix = "EVENT_", value = { EVENT_APPEARED, EVENT_VANISHED, EVENT_INFO_CHANGED, EVENT_PARENT_INFO_CHANGED }) @Retention(RetentionPolicy.SOURCE) public @interface EventType {} @EventType final int mEventType; final TaskFragment mTaskFragment; final ITaskFragmentOrganizer mTaskFragmentOrg; PendingTaskFragmentEvent(TaskFragment taskFragment, ITaskFragmentOrganizer taskFragmentOrg, @EventType int eventType) { mTaskFragment = taskFragment; mTaskFragmentOrg = taskFragmentOrg; mEventType = eventType; } /** * @return {@code true} if the pending event is related with taskFragment created, vanished * and information changed. */ boolean isLifecycleEvent() { switch (mEventType) { case EVENT_APPEARED: case EVENT_VANISHED: case EVENT_INFO_CHANGED: case EVENT_PARENT_INFO_CHANGED: return true; default: return false; } } } @Nullable private PendingTaskFragmentEvent getLastPendingLifecycleEvent(TaskFragment tf) { for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) { PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i); if (tf == entry.mTaskFragment && entry.isLifecycleEvent()) { return entry; } } return null; } @Nullable private PendingTaskFragmentEvent getPendingTaskFragmentEvent(TaskFragment taskFragment, int type) { for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) { PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i); if (taskFragment == entry.mTaskFragment && type == entry.mEventType) { return entry; } } return null; } void dispatchPendingEvents() { if (mAtmService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred() || mPendingTaskFragmentEvents.isEmpty()) { return; } for (int i = 0, n = mPendingTaskFragmentEvents.size(); i < n; i++) { PendingTaskFragmentEvent event = mPendingTaskFragmentEvents.get(i); final ITaskFragmentOrganizer taskFragmentOrg = event.mTaskFragmentOrg; final TaskFragment taskFragment = event.mTaskFragment; final TaskFragmentOrganizerState state = mTaskFragmentOrganizerState.get(taskFragmentOrg.asBinder()); if (state == null) continue; switch (event.mEventType) { case PendingTaskFragmentEvent.EVENT_APPEARED: state.onTaskFragmentAppeared(taskFragmentOrg, taskFragment); break; case PendingTaskFragmentEvent.EVENT_VANISHED: state.onTaskFragmentVanished(taskFragmentOrg, taskFragment); break; case PendingTaskFragmentEvent.EVENT_INFO_CHANGED: state.onTaskFragmentInfoChanged(taskFragmentOrg, taskFragment); break; case PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED: state.onTaskFragmentParentInfoChanged(taskFragmentOrg, taskFragment); } } mPendingTaskFragmentEvents.clear(); } } services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java +10 −0 Original line number Diff line number Diff line Loading @@ -102,6 +102,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.registerOrganizer(mIOrganizer); mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); verify(mOrganizer).onTaskFragmentAppeared(any()); } Loading @@ -110,6 +111,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { public void testOnTaskFragmentInfoChanged() { mController.registerOrganizer(mIOrganizer); mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); // No callback if the info is not changed. doReturn(true).when(mTaskFragmentInfo).equalsForTaskFragmentOrganizer(any()); Loading @@ -117,6 +119,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); verify(mOrganizer, never()).onTaskFragmentInfoChanged(any()); Loading @@ -125,6 +128,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); verify(mOrganizer).onTaskFragmentInfoChanged(mTaskFragmentInfo); } Loading @@ -133,7 +137,9 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { public void testOnTaskFragmentVanished() { mController.registerOrganizer(mIOrganizer); mTaskFragment.mTaskFragmentAppearedSent = true; mController.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); verify(mOrganizer).onTaskFragmentVanished(any()); } Loading @@ -148,8 +154,10 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { doReturn(parentConfig).when(parent).getConfiguration(); doReturn(parent).when(parent).asTask(); mTaskFragment.mTaskFragmentAppearedSent = true; mController.onTaskFragmentParentInfoChanged( mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any()); Loading @@ -158,6 +166,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.onTaskFragmentParentInfoChanged( mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); verify(mOrganizer, never()).onTaskFragmentParentInfoChanged(any(), any()); Loading @@ -166,6 +175,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.onTaskFragmentParentInfoChanged( mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any()); } Loading Loading
services/core/java/com/android/server/wm/ActivityTaskManagerService.java +3 −0 Original line number Diff line number Diff line Loading @@ -732,6 +732,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { WindowOrganizerController mWindowOrganizerController; TaskOrganizerController mTaskOrganizerController; TaskFragmentOrganizerController mTaskFragmentOrganizerController; @Nullable private BackgroundActivityStartCallback mBackgroundActivityStartCallback; Loading Loading @@ -805,6 +806,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", GL_ES_VERSION_UNDEFINED); mWindowOrganizerController = new WindowOrganizerController(this); mTaskOrganizerController = mWindowOrganizerController.mTaskOrganizerController; mTaskFragmentOrganizerController = mWindowOrganizerController.mTaskFragmentOrganizerController; } public void onSystemReady() { Loading
services/core/java/com/android/server/wm/RootWindowContainer.java +1 −0 Original line number Diff line number Diff line Loading @@ -858,6 +858,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // Send any pending task-info changes that were queued-up during a layout deferment mWmService.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); mWmService.mAtmService.mTaskFragmentOrganizerController.dispatchPendingEvents(); mWmService.mSyncEngine.onSurfacePlacement(); mWmService.mAnimator.executeAfterPrepareSurfacesRunnables(); Loading
services/core/java/com/android/server/wm/TaskFragment.java +17 −5 Original line number Diff line number Diff line Loading @@ -82,6 +82,7 @@ import android.util.DisplayMetrics; import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.view.DisplayInfo; import android.view.SurfaceControl; import android.window.ITaskFragmentOrganizer; import android.window.TaskFragmentInfo; Loading Loading @@ -160,6 +161,11 @@ class TaskFragment extends WindowContainer<WindowContainer> { // The TaskFragment that adjacent to this one. private TaskFragment mAdjacentTaskFragment; /** * Prevents duplicate calls to onTaskAppeared. */ boolean mTaskFragmentAppearedSent; /** * When we are in the process of pausing an activity, before starting the * next one, this variable holds the activity that is currently being paused. Loading Loading @@ -1970,18 +1976,24 @@ class TaskFragment extends WindowContainer<WindowContainer> { @Override public void onConfigurationChanged(Configuration newParentConfig) { super.onConfigurationChanged(newParentConfig); sendTaskFragmentInfoChanged(); } @Override void setSurfaceControl(SurfaceControl sc) { super.setSurfaceControl(sc); // If the TaskFragmentOrganizer was set before we created the SurfaceControl, we need to // emit the callbacks now. sendTaskFragmentAppeared(); } void sendTaskFragmentInfoChanged() { if (mTaskFragmentOrganizer != null) { // Parent config may have changed. The controller will check if there is any important // config change for the organizer. mTaskFragmentOrganizerController .onTaskFragmentParentInfoChanged(mTaskFragmentOrganizer, this); mTaskFragmentOrganizerController .onTaskFragmentInfoChanged(mTaskFragmentOrganizer, this); } } // TODO(b/190433129) call when TaskFragment is created from WCT#createTaskFragment private void sendTaskFragmentAppeared() { if (mTaskFragmentOrganizer != null) { mTaskFragmentOrganizerController.onTaskFragmentAppeared(mTaskFragmentOrganizer, this); Loading
services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +264 −84 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.server.wm; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER; import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer; import android.annotation.IntDef; import android.annotation.Nullable; import android.content.res.Configuration; import android.os.Binder; import android.os.IBinder; Loading @@ -33,6 +35,8 @@ import android.window.TaskFragmentInfo; import com.android.internal.protolog.common.ProtoLog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Map; import java.util.WeakHashMap; Loading @@ -45,16 +49,17 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr private final ActivityTaskManagerService mAtmService; private final WindowManagerGlobalLock mGlobalLock; private final Map<TaskFragment, TaskFragmentInfo> mLastSentTaskFragmentInfos = new WeakHashMap<>(); private final Map<TaskFragment, Configuration> mLastSentTaskFragmentParentConfigs = new WeakHashMap<>(); /** * A Map which manages the relationship between * {@link ITaskFragmentOrganizer} and {@link TaskFragmentOrganizerState} */ private final ArrayMap<IBinder, TaskFragmentController> mTaskFragmentOrganizerControllers = private final ArrayMap<IBinder, TaskFragmentOrganizerState> mTaskFragmentOrganizerState = new ArrayMap<>(); /** * A List which manages the TaskFragment pending event {@link PendingTaskFragmentEvent} */ private final ArrayList<PendingTaskFragmentEvent> mPendingTaskFragmentEvents = new ArrayList<>(); TaskFragmentOrganizerController(ActivityTaskManagerService atm) { mAtmService = atm; Loading @@ -65,11 +70,15 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr * A class to manage {@link ITaskFragmentOrganizer} and its organized * {@link TaskFragment TaskFragments}. */ private class TaskFragmentController implements IBinder.DeathRecipient { private class TaskFragmentOrganizerState implements IBinder.DeathRecipient { private final ArrayList<TaskFragment> mOrganizedTaskFragments = new ArrayList<>(); private final ITaskFragmentOrganizer mOrganizer; private final Map<TaskFragment, TaskFragmentInfo> mLastSentTaskFragmentInfos = new WeakHashMap<>(); private final Map<TaskFragment, Configuration> mLastSentTaskFragmentParentConfigs = new WeakHashMap<>(); TaskFragmentController(ITaskFragmentOrganizer organizer) { TaskFragmentOrganizerState(ITaskFragmentOrganizer organizer) { mOrganizer = organizer; try { mOrganizer.asBinder().linkToDeath(this, 0 /*flags*/); Loading @@ -85,10 +94,18 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } } void addTaskFragment(TaskFragment taskFragment) { if (!mOrganizedTaskFragments.contains(taskFragment)) { mOrganizedTaskFragments.add(taskFragment); /** * @return {@code true} if taskFragment is organized and not sent the appeared event before. */ boolean addTaskFragment(TaskFragment taskFragment) { if (taskFragment.mTaskFragmentAppearedSent) { return false; } if (mOrganizedTaskFragments.contains(taskFragment)) { return false; } mOrganizedTaskFragments.add(taskFragment); return true; } void removeTaskFragment(TaskFragment taskFragment) { Loading @@ -100,57 +117,39 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr mOrganizedTaskFragments.clear(); mOrganizer.asBinder().unlinkToDeath(this, 0 /*flags*/); } } @Override public void registerOrganizer(ITaskFragmentOrganizer organizer) { final int pid = Binder.getCallingPid(); final long uid = Binder.getCallingUid(); synchronized (mGlobalLock) { ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register task fragment organizer=%s uid=%d pid=%d", organizer.asBinder(), uid, pid); if (mTaskFragmentOrganizerControllers.containsKey(organizer.asBinder())) { throw new IllegalStateException( "Replacing existing organizer currently unsupported"); } mTaskFragmentOrganizerControllers.put(organizer.asBinder(), new TaskFragmentController(organizer)); } } @Override public void unregisterOrganizer(ITaskFragmentOrganizer organizer) { validateAndGetController(organizer); final int pid = Binder.getCallingPid(); final long uid = Binder.getCallingUid(); synchronized (mGlobalLock) { ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Unregister task fragment organizer=%s uid=%d pid=%d", organizer.asBinder(), uid, pid); removeOrganizer(organizer); } } void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment tf) { final TaskFragmentController controller = validateAndGetController(organizer); ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment appeared name=%s", tf.getName()); final TaskFragmentInfo info = tf.getTaskFragmentInfo(); final SurfaceControl outSurfaceControl = new SurfaceControl(tf.getSurfaceControl(), "TaskFragmentOrganizerController.onTaskFragmentInfoAppeared"); controller.addTaskFragment(tf); try { organizer.onTaskFragmentAppeared( new TaskFragmentAppearedInfo(info, outSurfaceControl)); mLastSentTaskFragmentInfos.put(tf, info); tf.mTaskFragmentAppearedSent = true; } catch (RemoteException e) { Slog.e(TAG, "Exception sending onTaskFragmentAppeared callback", e); } onTaskFragmentParentInfoChanged(organizer, tf); } void onTaskFragmentVanished(ITaskFragmentOrganizer organizer, TaskFragment tf) { ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment vanished name=%s", tf.getName()); try { organizer.onTaskFragmentVanished(tf.getTaskFragmentInfo()); } catch (RemoteException e) { Slog.e(TAG, "Exception sending onTaskFragmentVanished callback", e); } tf.mTaskFragmentAppearedSent = false; mLastSentTaskFragmentInfos.remove(tf); mLastSentTaskFragmentParentConfigs.remove(tf); } void onTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) { validateAndGetController(organizer); // Parent config may have changed. The controller will check if there is any important // config change for the organizer. onTaskFragmentParentInfoChanged(organizer, tf); // Check if the info is different from the last reported info. final TaskFragmentInfo info = tf.getTaskFragmentInfo(); Loading @@ -159,8 +158,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr info.getConfiguration(), lastInfo.getConfiguration())) { return; } ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s", tf.getName()); ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s", tf.getName()); try { organizer.onTaskFragmentInfoChanged(tf.getTaskFragmentInfo()); mLastSentTaskFragmentInfos.put(tf, info); Loading @@ -169,23 +168,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } } void onTaskFragmentVanished(ITaskFragmentOrganizer organizer, TaskFragment tf) { final TaskFragmentController controller = validateAndGetController(organizer); ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment vanished name=%s", tf.getName()); try { organizer.onTaskFragmentVanished(tf.getTaskFragmentInfo()); } catch (RemoteException e) { Slog.e(TAG, "Exception sending onTaskFragmentVanished callback", e); } mLastSentTaskFragmentInfos.remove(tf); mLastSentTaskFragmentParentConfigs.remove(tf); controller.removeTaskFragment(tf); } void onTaskFragmentParentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) { validateAndGetController(organizer); // Check if the parent info is different from the last reported parent info. if (tf.getParent() == null || tf.getParent().asTask() == null) { mLastSentTaskFragmentParentConfigs.remove(tf); Loading @@ -197,7 +180,6 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr if (configurationsAreEqualForOrganizer(parentConfig, lastParentConfig)) { return; } ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment parent info changed name=%s parentTaskId=%d", tf.getName(), parent.mTaskId); Loading @@ -208,12 +190,110 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr Slog.e(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e); } } } @Override public void registerOrganizer(ITaskFragmentOrganizer organizer) { final int pid = Binder.getCallingPid(); final long uid = Binder.getCallingUid(); synchronized (mGlobalLock) { ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register task fragment organizer=%s uid=%d pid=%d", organizer.asBinder(), uid, pid); if (mTaskFragmentOrganizerState.containsKey(organizer.asBinder())) { throw new IllegalStateException( "Replacing existing organizer currently unsupported"); } mTaskFragmentOrganizerState.put(organizer.asBinder(), new TaskFragmentOrganizerState(organizer)); } } @Override public void unregisterOrganizer(ITaskFragmentOrganizer organizer) { validateAndGetState(organizer); final int pid = Binder.getCallingPid(); final long uid = Binder.getCallingUid(); synchronized (mGlobalLock) { ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Unregister task fragment organizer=%s uid=%d pid=%d", organizer.asBinder(), uid, pid); removeOrganizer(organizer); } } void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) { final TaskFragmentOrganizerState state = validateAndGetState(organizer); if (!state.addTaskFragment(taskFragment)) { return; } PendingTaskFragmentEvent pendingEvent = getPendingTaskFragmentEvent(taskFragment, PendingTaskFragmentEvent.EVENT_APPEARED); if (pendingEvent == null) { pendingEvent = new PendingTaskFragmentEvent(taskFragment, organizer, PendingTaskFragmentEvent.EVENT_APPEARED); mPendingTaskFragmentEvents.add(pendingEvent); } } void onTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) { handleTaskFragmentInfoChanged(organizer, taskFragment, PendingTaskFragmentEvent.EVENT_INFO_CHANGED); } void onTaskFragmentParentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) { handleTaskFragmentInfoChanged(organizer, taskFragment, PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED); } private void handleTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment taskFragment, int eventType) { validateAndGetState(organizer); if (!taskFragment.mTaskFragmentAppearedSent) { // Skip if TaskFragment still not appeared. return; } PendingTaskFragmentEvent pendingEvent = getLastPendingLifecycleEvent(taskFragment); if (pendingEvent == null) { pendingEvent = new PendingTaskFragmentEvent(taskFragment, organizer, eventType); } else { if (pendingEvent.mEventType == PendingTaskFragmentEvent.EVENT_VANISHED) { // Skipped the info changed event if vanished event is pending. return; } // Remove and add for re-ordering. mPendingTaskFragmentEvents.remove(pendingEvent); } mPendingTaskFragmentEvents.add(pendingEvent); } void onTaskFragmentVanished(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) { final TaskFragmentOrganizerState state = validateAndGetState(organizer); for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) { PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i); if (taskFragment == entry.mTaskFragment) { mPendingTaskFragmentEvents.remove(i); if (entry.mEventType == PendingTaskFragmentEvent.EVENT_APPEARED) { // If taskFragment appeared callback is pending, ignore the vanished request. return; } } } if (!taskFragment.mTaskFragmentAppearedSent) { return; } PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent(taskFragment, organizer, PendingTaskFragmentEvent.EVENT_VANISHED); mPendingTaskFragmentEvents.add(pendingEvent); state.removeTaskFragment(taskFragment); } private void removeOrganizer(ITaskFragmentOrganizer organizer) { final TaskFragmentController controller = validateAndGetController(organizer); final TaskFragmentOrganizerState state = validateAndGetState(organizer); // remove all of the children of the organized TaskFragment controller.dispose(); mTaskFragmentOrganizerControllers.remove(organizer.asBinder()); state.dispose(); mTaskFragmentOrganizerState.remove(organizer.asBinder()); } /** Loading @@ -222,13 +302,113 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr * we wouldn't register {@link DeathRecipient} for the organizer, and might not remove the * {@link TaskFragment} after the organizer process died. */ private TaskFragmentController validateAndGetController(ITaskFragmentOrganizer organizer) { final TaskFragmentController controller = mTaskFragmentOrganizerControllers.get(organizer.asBinder()); if (controller == null) { private TaskFragmentOrganizerState validateAndGetState(ITaskFragmentOrganizer organizer) { final TaskFragmentOrganizerState state = mTaskFragmentOrganizerState.get(organizer.asBinder()); if (state == null) { throw new IllegalArgumentException( "TaskFragmentOrganizer has not been registered. Organizer=" + organizer); } return controller; return state; } /** * A class to store {@link ITaskFragmentOrganizer} and its organized * {@link TaskFragment TaskFragments} with different pending event request. */ private static class PendingTaskFragmentEvent { static final int EVENT_APPEARED = 0; static final int EVENT_VANISHED = 1; static final int EVENT_INFO_CHANGED = 2; static final int EVENT_PARENT_INFO_CHANGED = 3; @IntDef(prefix = "EVENT_", value = { EVENT_APPEARED, EVENT_VANISHED, EVENT_INFO_CHANGED, EVENT_PARENT_INFO_CHANGED }) @Retention(RetentionPolicy.SOURCE) public @interface EventType {} @EventType final int mEventType; final TaskFragment mTaskFragment; final ITaskFragmentOrganizer mTaskFragmentOrg; PendingTaskFragmentEvent(TaskFragment taskFragment, ITaskFragmentOrganizer taskFragmentOrg, @EventType int eventType) { mTaskFragment = taskFragment; mTaskFragmentOrg = taskFragmentOrg; mEventType = eventType; } /** * @return {@code true} if the pending event is related with taskFragment created, vanished * and information changed. */ boolean isLifecycleEvent() { switch (mEventType) { case EVENT_APPEARED: case EVENT_VANISHED: case EVENT_INFO_CHANGED: case EVENT_PARENT_INFO_CHANGED: return true; default: return false; } } } @Nullable private PendingTaskFragmentEvent getLastPendingLifecycleEvent(TaskFragment tf) { for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) { PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i); if (tf == entry.mTaskFragment && entry.isLifecycleEvent()) { return entry; } } return null; } @Nullable private PendingTaskFragmentEvent getPendingTaskFragmentEvent(TaskFragment taskFragment, int type) { for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) { PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i); if (taskFragment == entry.mTaskFragment && type == entry.mEventType) { return entry; } } return null; } void dispatchPendingEvents() { if (mAtmService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred() || mPendingTaskFragmentEvents.isEmpty()) { return; } for (int i = 0, n = mPendingTaskFragmentEvents.size(); i < n; i++) { PendingTaskFragmentEvent event = mPendingTaskFragmentEvents.get(i); final ITaskFragmentOrganizer taskFragmentOrg = event.mTaskFragmentOrg; final TaskFragment taskFragment = event.mTaskFragment; final TaskFragmentOrganizerState state = mTaskFragmentOrganizerState.get(taskFragmentOrg.asBinder()); if (state == null) continue; switch (event.mEventType) { case PendingTaskFragmentEvent.EVENT_APPEARED: state.onTaskFragmentAppeared(taskFragmentOrg, taskFragment); break; case PendingTaskFragmentEvent.EVENT_VANISHED: state.onTaskFragmentVanished(taskFragmentOrg, taskFragment); break; case PendingTaskFragmentEvent.EVENT_INFO_CHANGED: state.onTaskFragmentInfoChanged(taskFragmentOrg, taskFragment); break; case PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED: state.onTaskFragmentParentInfoChanged(taskFragmentOrg, taskFragment); } } mPendingTaskFragmentEvents.clear(); } }
services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java +10 −0 Original line number Diff line number Diff line Loading @@ -102,6 +102,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.registerOrganizer(mIOrganizer); mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); verify(mOrganizer).onTaskFragmentAppeared(any()); } Loading @@ -110,6 +111,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { public void testOnTaskFragmentInfoChanged() { mController.registerOrganizer(mIOrganizer); mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); // No callback if the info is not changed. doReturn(true).when(mTaskFragmentInfo).equalsForTaskFragmentOrganizer(any()); Loading @@ -117,6 +119,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); verify(mOrganizer, never()).onTaskFragmentInfoChanged(any()); Loading @@ -125,6 +128,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); verify(mOrganizer).onTaskFragmentInfoChanged(mTaskFragmentInfo); } Loading @@ -133,7 +137,9 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { public void testOnTaskFragmentVanished() { mController.registerOrganizer(mIOrganizer); mTaskFragment.mTaskFragmentAppearedSent = true; mController.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); verify(mOrganizer).onTaskFragmentVanished(any()); } Loading @@ -148,8 +154,10 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { doReturn(parentConfig).when(parent).getConfiguration(); doReturn(parent).when(parent).asTask(); mTaskFragment.mTaskFragmentAppearedSent = true; mController.onTaskFragmentParentInfoChanged( mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any()); Loading @@ -158,6 +166,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.onTaskFragmentParentInfoChanged( mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); verify(mOrganizer, never()).onTaskFragmentParentInfoChanged(any(), any()); Loading @@ -166,6 +175,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.onTaskFragmentParentInfoChanged( mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any()); } Loading