1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wm;
18 
19 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
20 import static com.android.server.wm.ActivityTaskManagerService.enforceTaskPermission;
21 import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
22 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_STARTING_REVEAL;
23 import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;
24 
25 import android.annotation.NonNull;
26 import android.annotation.Nullable;
27 import android.app.ActivityManager;
28 import android.app.ActivityManager.RunningTaskInfo;
29 import android.app.WindowConfiguration;
30 import android.content.Intent;
31 import android.content.pm.ParceledListSlice;
32 import android.os.Binder;
33 import android.os.IBinder;
34 import android.os.Parcel;
35 import android.os.RemoteException;
36 import android.util.Slog;
37 import android.util.proto.ProtoOutputStream;
38 import android.view.SurfaceControl;
39 import android.window.ITaskOrganizer;
40 import android.window.ITaskOrganizerController;
41 import android.window.SplashScreenView;
42 import android.window.StartingWindowInfo;
43 import android.window.StartingWindowRemovalInfo;
44 import android.window.TaskAppearedInfo;
45 import android.window.TaskSnapshot;
46 import android.window.WindowContainerToken;
47 
48 import com.android.internal.annotations.VisibleForTesting;
49 import com.android.internal.protolog.common.ProtoLog;
50 import com.android.internal.util.ArrayUtils;
51 
52 import java.io.PrintWriter;
53 import java.util.ArrayList;
54 import java.util.HashMap;
55 import java.util.HashSet;
56 import java.util.LinkedList;
57 import java.util.List;
58 import java.util.WeakHashMap;
59 import java.util.function.Consumer;
60 
61 /**
62  * Stores the TaskOrganizers associated with a given windowing mode and
63  * their associated state.
64  */
65 class TaskOrganizerController extends ITaskOrganizerController.Stub {
66     private static final String TAG = "TaskOrganizerController";
67 
68     private class DeathRecipient implements IBinder.DeathRecipient {
69         ITaskOrganizer mTaskOrganizer;
70 
DeathRecipient(ITaskOrganizer organizer)71         DeathRecipient(ITaskOrganizer organizer) {
72             mTaskOrganizer = organizer;
73         }
74 
75         @Override
binderDied()76         public void binderDied() {
77             synchronized (mGlobalLock) {
78                 final TaskOrganizerState state = mTaskOrganizerStates.remove(
79                         mTaskOrganizer.asBinder());
80                 if (state != null) {
81                     state.dispose();
82                 }
83             }
84         }
85     }
86 
87     /**
88      * A wrapper class around ITaskOrganizer to ensure that the calls are made in the right
89      * lifecycle order since we may be updating the visibility of task surface controls in a pending
90      * transaction before they are presented to the task org.
91      */
92     private class TaskOrganizerCallbacks {
93         final ITaskOrganizer mTaskOrganizer;
94         final Consumer<Runnable> mDeferTaskOrgCallbacksConsumer;
95 
TaskOrganizerCallbacks(ITaskOrganizer taskOrg, Consumer<Runnable> deferTaskOrgCallbacksConsumer)96         TaskOrganizerCallbacks(ITaskOrganizer taskOrg,
97                 Consumer<Runnable> deferTaskOrgCallbacksConsumer) {
98             mDeferTaskOrgCallbacksConsumer = deferTaskOrgCallbacksConsumer;
99             mTaskOrganizer = taskOrg;
100         }
101 
getBinder()102         IBinder getBinder() {
103             return mTaskOrganizer.asBinder();
104         }
105 
prepareLeash(Task task, String reason)106         SurfaceControl prepareLeash(Task task, String reason) {
107             return new SurfaceControl(task.getSurfaceControl(), reason);
108         }
109 
onTaskAppeared(Task task)110         void onTaskAppeared(Task task) {
111             ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task appeared taskId=%d", task.mTaskId);
112             final RunningTaskInfo taskInfo = task.getTaskInfo();
113             try {
114                 mTaskOrganizer.onTaskAppeared(taskInfo, prepareLeash(task,
115                         "TaskOrganizerController.onTaskAppeared"));
116             } catch (RemoteException e) {
117                 Slog.e(TAG, "Exception sending onTaskAppeared callback", e);
118             }
119         }
120 
121 
onTaskVanished(Task task)122         void onTaskVanished(Task task) {
123             ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task vanished taskId=%d", task.mTaskId);
124             final RunningTaskInfo taskInfo = task.getTaskInfo();
125             try {
126                 mTaskOrganizer.onTaskVanished(taskInfo);
127             } catch (RemoteException e) {
128                 Slog.e(TAG, "Exception sending onTaskVanished callback", e);
129             }
130         }
131 
onTaskInfoChanged(Task task, ActivityManager.RunningTaskInfo taskInfo)132         void onTaskInfoChanged(Task task, ActivityManager.RunningTaskInfo taskInfo) {
133             if (!task.mTaskAppearedSent) {
134                 // Skip if the task has not yet received taskAppeared().
135                 return;
136             }
137             ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task info changed taskId=%d", task.mTaskId);
138             if (!task.isOrganized()) {
139                 // This is safe to ignore if the task is no longer organized
140                 return;
141             }
142             try {
143                 // Purposely notify of task info change immediately instead of deferring (like
144                 // appear and vanish) to allow info changes (such as new PIP params) to flow
145                 // without waiting.
146                 mTaskOrganizer.onTaskInfoChanged(taskInfo);
147             } catch (RemoteException e) {
148                 Slog.e(TAG, "Exception sending onTaskInfoChanged callback", e);
149             }
150         }
151 
onBackPressedOnTaskRoot(Task task)152         void onBackPressedOnTaskRoot(Task task) {
153             ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task back pressed on root taskId=%d",
154                     task.mTaskId);
155             if (!task.mTaskAppearedSent) {
156                 // Skip if the task has not yet received taskAppeared().
157                 return;
158             }
159             if (!task.isOrganized()) {
160                 // This is safe to ignore if the task is no longer organized
161                 return;
162             }
163             try {
164                 mTaskOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo());
165             } catch (Exception e) {
166                 Slog.e(TAG, "Exception sending onBackPressedOnTaskRoot callback", e);
167             }
168         }
169     }
170 
171     private class TaskOrganizerState {
172         private final TaskOrganizerCallbacks mOrganizer;
173         private final DeathRecipient mDeathRecipient;
174         private final ArrayList<Task> mOrganizedTasks = new ArrayList<>();
175         private final int mUid;
176 
TaskOrganizerState(ITaskOrganizer organizer, int uid)177         TaskOrganizerState(ITaskOrganizer organizer, int uid) {
178             final Consumer<Runnable> deferTaskOrgCallbacksConsumer =
179                     mDeferTaskOrgCallbacksConsumer != null
180                             ? mDeferTaskOrgCallbacksConsumer
181                             : mService.mWindowManager.mAnimator::addAfterPrepareSurfacesRunnable;
182             mOrganizer = new TaskOrganizerCallbacks(organizer, deferTaskOrgCallbacksConsumer);
183             mDeathRecipient = new DeathRecipient(organizer);
184             try {
185                 organizer.asBinder().linkToDeath(mDeathRecipient, 0);
186             } catch (RemoteException e) {
187                 Slog.e(TAG, "TaskOrganizer failed to register death recipient");
188             }
189             mUid = uid;
190         }
191 
192         /**
193          * Register this task with this state, but doesn't trigger the task appeared callback to
194          * the organizer.
195          */
addTaskWithoutCallback(Task t, String reason)196         SurfaceControl addTaskWithoutCallback(Task t, String reason) {
197             t.mTaskAppearedSent = true;
198             if (!mOrganizedTasks.contains(t)) {
199                 mOrganizedTasks.add(t);
200             }
201             return mOrganizer.prepareLeash(t, reason);
202         }
203 
addTask(Task t)204         private boolean addTask(Task t) {
205             if (t.mTaskAppearedSent) {
206                 return false;
207             }
208 
209             if (!mOrganizedTasks.contains(t)) {
210                 mOrganizedTasks.add(t);
211             }
212 
213             if (t.taskAppearedReady()) {
214                 t.mTaskAppearedSent = true;
215                 return true;
216             }
217             return false;
218         }
219 
removeTask(Task t, boolean removeFromSystem)220         private boolean removeTask(Task t, boolean removeFromSystem) {
221             mOrganizedTasks.remove(t);
222             mInterceptBackPressedOnRootTasks.remove(t.mTaskId);
223             boolean taskAppearedSent = t.mTaskAppearedSent;
224             if (taskAppearedSent) {
225                 if (t.getSurfaceControl() != null) {
226                     t.migrateToNewSurfaceControl(t.getSyncTransaction());
227                 }
228                 t.mTaskAppearedSent = false;
229             }
230             if (removeFromSystem) {
231                 mService.removeTask(t.mTaskId);
232             }
233             return taskAppearedSent;
234         }
235 
dispose()236         void dispose() {
237             // Move organizer from managing specific windowing modes
238             mTaskOrganizers.remove(mOrganizer.mTaskOrganizer);
239 
240             // Update tasks currently managed by this organizer to the next one available if
241             // possible.
242             while (!mOrganizedTasks.isEmpty()) {
243                 final Task t = mOrganizedTasks.get(0);
244                 t.updateTaskOrganizerState(true /* forceUpdate */);
245                 if (mOrganizedTasks.contains(t)) {
246                     // updateTaskOrganizerState should remove the task from the list, but still
247                     // check it again to avoid while-loop isn't terminate.
248                     if (removeTask(t, t.mRemoveWithTaskOrganizer)) {
249                         TaskOrganizerController.this.onTaskVanishedInternal(
250                                 mOrganizer.mTaskOrganizer, t);
251                     }
252                 }
253                 if (mService.getTransitionController().isShellTransitionsEnabled()) {
254                     // dispose is only called outside of transitions (eg during unregister). Since
255                     // we "migrate" surfaces when replacing organizers, visibility gets delegated
256                     // to transitions; however, since there is no transition at this point, we have
257                     // to manually show the surface here.
258                     if (t.mTaskOrganizer != null && t.getSurfaceControl() != null) {
259                         t.getSyncTransaction().show(t.getSurfaceControl());
260                     }
261                 }
262             }
263 
264             // Remove organizer state after removing tasks so we get a chance to send
265             // onTaskVanished.
266             mTaskOrganizerStates.remove(asBinder());
267         }
268 
unlinkDeath()269         void unlinkDeath() {
270             mOrganizer.getBinder().unlinkToDeath(mDeathRecipient, 0);
271         }
272     }
273 
274     static class PendingTaskEvent {
275         static final int EVENT_APPEARED = 0;
276         static final int EVENT_VANISHED = 1;
277         static final int EVENT_INFO_CHANGED = 2;
278         static final int EVENT_ROOT_BACK_PRESSED = 3;
279 
280         final int mEventType;
281         final Task mTask;
282         final ITaskOrganizer mTaskOrg;
283         boolean mForce;
284 
PendingTaskEvent(Task task, int event)285         PendingTaskEvent(Task task, int event) {
286             this(task, task.mTaskOrganizer, event);
287         }
288 
PendingTaskEvent(Task task, ITaskOrganizer taskOrg, int eventType)289         PendingTaskEvent(Task task, ITaskOrganizer taskOrg, int eventType) {
290             mTask = task;
291             mTaskOrg = taskOrg;
292             mEventType = eventType;
293         }
294 
isLifecycleEvent()295         boolean isLifecycleEvent() {
296             return mEventType == EVENT_APPEARED || mEventType == EVENT_VANISHED
297                     || mEventType == EVENT_INFO_CHANGED;
298         }
299     }
300 
301     private final ActivityTaskManagerService mService;
302     private final WindowManagerGlobalLock mGlobalLock;
303 
304     // List of task organizers by priority
305     private final LinkedList<ITaskOrganizer> mTaskOrganizers = new LinkedList<>();
306     private final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap<>();
307     private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
308     // Pending task events due to layout deferred.
309     private final ArrayList<PendingTaskEvent> mPendingTaskEvents = new ArrayList<>();
310     // Set of organized tasks (by taskId) that dispatch back pressed to their organizers
311     private final HashSet<Integer> mInterceptBackPressedOnRootTasks = new HashSet();
312 
313     private RunningTaskInfo mTmpTaskInfo;
314     private Consumer<Runnable> mDeferTaskOrgCallbacksConsumer;
315 
TaskOrganizerController(ActivityTaskManagerService atm)316     TaskOrganizerController(ActivityTaskManagerService atm) {
317         mService = atm;
318         mGlobalLock = atm.mGlobalLock;
319     }
320 
321     @Override
onTransact(int code, Parcel data, Parcel reply, int flags)322     public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
323             throws RemoteException {
324         try {
325             return super.onTransact(code, data, reply, flags);
326         } catch (RuntimeException e) {
327             throw ActivityTaskManagerService.logAndRethrowRuntimeExceptionOnTransact(TAG, e);
328         }
329     }
330 
331     /**
332      * Specifies the consumer to run to defer the task org callbacks. Can be overridden while
333      * testing to allow the callbacks to be sent synchronously.
334      */
335     @VisibleForTesting
setDeferTaskOrgCallbacksConsumer(Consumer<Runnable> consumer)336     public void setDeferTaskOrgCallbacksConsumer(Consumer<Runnable> consumer) {
337         mDeferTaskOrgCallbacksConsumer = consumer;
338     }
339 
340     @VisibleForTesting
getPendingEventList()341     ArrayList<PendingTaskEvent> getPendingEventList() {
342         return mPendingTaskEvents;
343     }
344 
345     /**
346      * Register a TaskOrganizer to manage tasks as they enter the a supported windowing mode.
347      */
348     @Override
registerTaskOrganizer(ITaskOrganizer organizer)349     public ParceledListSlice<TaskAppearedInfo> registerTaskOrganizer(ITaskOrganizer organizer) {
350         enforceTaskPermission("registerTaskOrganizer()");
351         final int uid = Binder.getCallingUid();
352         final long origId = Binder.clearCallingIdentity();
353         try {
354             final ArrayList<TaskAppearedInfo> taskInfos = new ArrayList<>();
355             final Runnable withGlobalLock = () -> {
356                 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register task organizer=%s uid=%d",
357                         organizer.asBinder(), uid);
358                 if (!mTaskOrganizerStates.containsKey(organizer.asBinder())) {
359                     mTaskOrganizers.add(organizer);
360                     mTaskOrganizerStates.put(organizer.asBinder(),
361                             new TaskOrganizerState(organizer, uid));
362                 }
363 
364                 final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
365                 mService.mRootWindowContainer.forAllTasks((task) -> {
366                     boolean returnTask = !task.mCreatedByOrganizer;
367                     task.updateTaskOrganizerState(true /* forceUpdate */,
368                             returnTask /* skipTaskAppeared */);
369                     if (returnTask) {
370                         SurfaceControl outSurfaceControl = state.addTaskWithoutCallback(task,
371                                 "TaskOrganizerController.registerTaskOrganizer");
372                         taskInfos.add(
373                                 new TaskAppearedInfo(task.getTaskInfo(), outSurfaceControl));
374                     }
375                 });
376             };
377             if (mService.getTransitionController().isShellTransitionsEnabled()) {
378                 mService.getTransitionController().mRunningLock.runWhenIdle(1000, withGlobalLock);
379             } else {
380                 synchronized (mGlobalLock) {
381                     withGlobalLock.run();
382                 }
383             }
384             return new ParceledListSlice<>(taskInfos);
385         } finally {
386             Binder.restoreCallingIdentity(origId);
387         }
388     }
389 
390     @Override
unregisterTaskOrganizer(ITaskOrganizer organizer)391     public void unregisterTaskOrganizer(ITaskOrganizer organizer) {
392         enforceTaskPermission("unregisterTaskOrganizer()");
393         final int uid = Binder.getCallingUid();
394         final long origId = Binder.clearCallingIdentity();
395         try {
396             final Runnable withGlobalLock = () -> {
397                 final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
398                 if (state == null) {
399                     return;
400                 }
401                 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Unregister task organizer=%s uid=%d",
402                         organizer.asBinder(), uid);
403                 state.unlinkDeath();
404                 state.dispose();
405             };
406             if (mService.getTransitionController().isShellTransitionsEnabled()) {
407                 mService.getTransitionController().mRunningLock.runWhenIdle(1000, withGlobalLock);
408             } else {
409                 synchronized (mGlobalLock) {
410                     withGlobalLock.run();
411                 }
412             }
413         } finally {
414             Binder.restoreCallingIdentity(origId);
415         }
416     }
417 
418     /**
419      * @return the task organizer key for a given windowing mode.
420      */
getTaskOrganizer()421     ITaskOrganizer getTaskOrganizer() {
422         return mTaskOrganizers.peekLast();
423     }
424 
425     // Capture the animation surface control for activity's main window
426     static class StartingWindowAnimationAdaptor implements AnimationAdapter {
427         SurfaceControl mAnimationLeash;
428         @Override
getShowWallpaper()429         public boolean getShowWallpaper() {
430             return false;
431         }
432 
433         @Override
startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t, int type, @NonNull SurfaceAnimator.OnAnimationFinishedCallback finishCallback)434         public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t,
435                 int type, @NonNull SurfaceAnimator.OnAnimationFinishedCallback finishCallback) {
436             mAnimationLeash = animationLeash;
437         }
438 
439         @Override
onAnimationCancelled(SurfaceControl animationLeash)440         public void onAnimationCancelled(SurfaceControl animationLeash) {
441             if (mAnimationLeash == animationLeash) {
442                 mAnimationLeash = null;
443             }
444         }
445 
446         @Override
getDurationHint()447         public long getDurationHint() {
448             return 0;
449         }
450 
451         @Override
getStatusBarTransitionsStartTime()452         public long getStatusBarTransitionsStartTime() {
453             return 0;
454         }
455 
456         @Override
dump(PrintWriter pw, String prefix)457         public void dump(PrintWriter pw, String prefix) {
458             pw.print(prefix + "StartingWindowAnimationAdaptor mCapturedLeash=");
459             pw.print(mAnimationLeash);
460             pw.println();
461         }
462 
463         @Override
dumpDebug(ProtoOutputStream proto)464         public void dumpDebug(ProtoOutputStream proto) {
465         }
466     }
467 
applyStartingWindowAnimation(WindowContainer window)468     static SurfaceControl applyStartingWindowAnimation(WindowContainer window) {
469         final StartingWindowAnimationAdaptor adaptor = new StartingWindowAnimationAdaptor();
470         window.startAnimation(window.getPendingTransaction(), adaptor, false,
471                 ANIMATION_TYPE_STARTING_REVEAL);
472         return adaptor.mAnimationLeash;
473     }
474 
addStartingWindow(Task task, ActivityRecord activity, int launchTheme, TaskSnapshot taskSnapshot)475     boolean addStartingWindow(Task task, ActivityRecord activity, int launchTheme,
476             TaskSnapshot taskSnapshot) {
477         final Task rootTask = task.getRootTask();
478         if (rootTask == null || activity.mStartingData == null) {
479             return false;
480         }
481         final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast();
482         if (lastOrganizer == null) {
483             return false;
484         }
485         final StartingWindowInfo info = task.getStartingWindowInfo(activity);
486         if (launchTheme != 0) {
487             info.splashScreenThemeResId = launchTheme;
488         }
489         info.taskSnapshot = taskSnapshot;
490         // make this happen prior than prepare surface
491         try {
492             lastOrganizer.addStartingWindow(info, activity.token);
493         } catch (RemoteException e) {
494             Slog.e(TAG, "Exception sending onTaskStart callback", e);
495             return false;
496         }
497         return true;
498     }
499 
removeStartingWindow(Task task, boolean prepareAnimation)500     void removeStartingWindow(Task task, boolean prepareAnimation) {
501         final Task rootTask = task.getRootTask();
502         if (rootTask == null) {
503             return;
504         }
505         final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast();
506         if (lastOrganizer == null) {
507             return;
508         }
509         final StartingWindowRemovalInfo removalInfo = new StartingWindowRemovalInfo();
510         removalInfo.taskId = task.mTaskId;
511         removalInfo.playRevealAnimation = prepareAnimation;
512         final boolean playShiftUpAnimation = !task.inMultiWindowMode();
513         final ActivityRecord topActivity = task.topActivityContainsStartingWindow();
514         if (topActivity != null) {
515             removalInfo.deferRemoveForIme = topActivity.mDisplayContent
516                     .mayImeShowOnLaunchingActivity(topActivity);
517             if (prepareAnimation && playShiftUpAnimation) {
518                 final WindowState mainWindow =
519                         topActivity.findMainWindow(false/* includeStartingApp */);
520                 if (mainWindow != null) {
521                     final SurfaceControl.Transaction t = mainWindow.getPendingTransaction();
522                     removalInfo.windowAnimationLeash = applyStartingWindowAnimation(mainWindow);
523                     removalInfo.mainFrame = mainWindow.getRelativeFrame();
524                     t.setPosition(removalInfo.windowAnimationLeash,
525                             removalInfo.mainFrame.left, removalInfo.mainFrame.top);
526                 }
527             }
528         }
529         try {
530             lastOrganizer.removeStartingWindow(removalInfo);
531         } catch (RemoteException e) {
532             Slog.e(TAG, "Exception sending onStartTaskFinished callback", e);
533         }
534     }
535 
copySplashScreenView(Task task)536     boolean copySplashScreenView(Task task) {
537         final Task rootTask = task.getRootTask();
538         if (rootTask == null) {
539             return false;
540         }
541         final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast();
542         if (lastOrganizer == null) {
543             return false;
544         }
545         try {
546             lastOrganizer.copySplashScreenView(task.mTaskId);
547         } catch (RemoteException e) {
548             Slog.e(TAG, "Exception sending copyStartingWindowView callback", e);
549             return false;
550         }
551         return true;
552     }
553 
554     /**
555      * Notify the shell ({@link com.android.wm.shell.ShellTaskOrganizer} that the client has
556      * removed the splash screen view.
557      * @see com.android.wm.shell.ShellTaskOrganizer#onAppSplashScreenViewRemoved(int)
558      * @see SplashScreenView#remove()
559      */
onAppSplashScreenViewRemoved(Task task)560     public void onAppSplashScreenViewRemoved(Task task) {
561         final Task rootTask = task.getRootTask();
562         if (rootTask == null) {
563             return;
564         }
565         final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast();
566         if (lastOrganizer == null) {
567             return;
568         }
569         try {
570             lastOrganizer.onAppSplashScreenViewRemoved(task.mTaskId);
571         } catch (RemoteException e) {
572             Slog.e(TAG, "Exception sending onAppSplashScreenViewRemoved callback", e);
573         }
574     }
575 
onTaskAppeared(ITaskOrganizer organizer, Task task)576     void onTaskAppeared(ITaskOrganizer organizer, Task task) {
577         final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
578         if (state != null && state.addTask(task)) {
579             PendingTaskEvent pending = getPendingTaskEvent(task, PendingTaskEvent.EVENT_APPEARED);
580             if (pending == null) {
581                 pending = new PendingTaskEvent(task, PendingTaskEvent.EVENT_APPEARED);
582                 mPendingTaskEvents.add(pending);
583             }
584         }
585     }
586 
onTaskVanished(ITaskOrganizer organizer, Task task)587     void onTaskVanished(ITaskOrganizer organizer, Task task) {
588         final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
589         if (state != null && state.removeTask(task, false /* removeFromSystem */)) {
590             onTaskVanishedInternal(organizer, task);
591         }
592     }
593 
onTaskVanishedInternal(ITaskOrganizer organizer, Task task)594     private void onTaskVanishedInternal(ITaskOrganizer organizer, Task task) {
595         for (int i = mPendingTaskEvents.size() - 1; i >= 0; i--) {
596             PendingTaskEvent entry = mPendingTaskEvents.get(i);
597             if (task.mTaskId == entry.mTask.mTaskId) {
598                 // This task is vanished so remove all pending event of it.
599                 mPendingTaskEvents.remove(i);
600                 if (entry.mEventType == PendingTaskEvent.EVENT_APPEARED) {
601                     // If task appeared callback still pend, ignore this callback too.
602                     return;
603                 }
604             }
605         }
606 
607         PendingTaskEvent pending =
608                 new PendingTaskEvent(task, organizer, PendingTaskEvent.EVENT_VANISHED);
609         mPendingTaskEvents.add(pending);
610     }
611 
612     @Override
createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie)613     public void createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie) {
614         enforceTaskPermission("createRootTask()");
615         final long origId = Binder.clearCallingIdentity();
616         try {
617             synchronized (mGlobalLock) {
618                 DisplayContent display = mService.mRootWindowContainer.getDisplayContent(displayId);
619                 if (display == null) {
620                     ProtoLog.e(WM_DEBUG_WINDOW_ORGANIZER,
621                             "createRootTask unknown displayId=%d", displayId);
622                     return;
623                 }
624 
625                 createRootTask(display, windowingMode, launchCookie);
626             }
627         } finally {
628             Binder.restoreCallingIdentity(origId);
629         }
630     }
631 
632     @VisibleForTesting
createRootTask(DisplayContent display, int windowingMode, @Nullable IBinder launchCookie)633     Task createRootTask(DisplayContent display, int windowingMode, @Nullable IBinder launchCookie) {
634         ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Create root task displayId=%d winMode=%d",
635                 display.mDisplayId, windowingMode);
636         // We want to defer the task appear signal until the task is fully created and attached to
637         // to the hierarchy so that the complete starting configuration is in the task info we send
638         // over to the organizer.
639         final Task task = new Task.Builder(mService)
640                 .setWindowingMode(windowingMode)
641                 .setIntent(new Intent())
642                 .setCreatedByOrganizer(true)
643                 .setDeferTaskAppear(true)
644                 .setLaunchCookie(launchCookie)
645                 .setParent(display.getDefaultTaskDisplayArea())
646                 .build();
647         task.setDeferTaskAppear(false /* deferTaskAppear */);
648         return task;
649     }
650 
651     @Override
deleteRootTask(WindowContainerToken token)652     public boolean deleteRootTask(WindowContainerToken token) {
653         enforceTaskPermission("deleteRootTask()");
654         final long origId = Binder.clearCallingIdentity();
655         try {
656             synchronized (mGlobalLock) {
657                 final WindowContainer wc = WindowContainer.fromBinder(token.asBinder());
658                 if (wc == null) return false;
659                 final Task task = wc.asTask();
660                 if (task == null) return false;
661                 if (!task.mCreatedByOrganizer) {
662                     throw new IllegalArgumentException(
663                             "Attempt to delete task not created by organizer task=" + task);
664                 }
665 
666                 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Delete root task display=%d winMode=%d",
667                         task.getDisplayId(), task.getWindowingMode());
668                 task.remove(true /* withTransition */, "deleteRootTask");
669                 return true;
670             }
671         } finally {
672             Binder.restoreCallingIdentity(origId);
673         }
674     }
675 
dispatchPendingEvents()676     void dispatchPendingEvents() {
677         if (mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()
678                 || mPendingTaskEvents.isEmpty()) {
679             return;
680         }
681 
682         for (int i = 0, n = mPendingTaskEvents.size(); i < n; i++) {
683             PendingTaskEvent event = mPendingTaskEvents.get(i);
684             final Task task = event.mTask;
685             final TaskOrganizerState state;
686             switch (event.mEventType) {
687                 case PendingTaskEvent.EVENT_APPEARED:
688                     state = mTaskOrganizerStates.get(event.mTaskOrg.asBinder());
689                     if (state != null && task.taskAppearedReady()) {
690                         state.mOrganizer.onTaskAppeared(task);
691                     }
692                     break;
693                 case PendingTaskEvent.EVENT_VANISHED:
694                     state = mTaskOrganizerStates.get(event.mTaskOrg.asBinder());
695                     if (state != null) {
696                         state.mOrganizer.onTaskVanished(task);
697                     }
698                     mLastSentTaskInfos.remove(task);
699                     break;
700                 case PendingTaskEvent.EVENT_INFO_CHANGED:
701                     dispatchTaskInfoChanged(event.mTask, event.mForce);
702                     break;
703                 case PendingTaskEvent.EVENT_ROOT_BACK_PRESSED:
704                     state = mTaskOrganizerStates.get(event.mTaskOrg.asBinder());
705                     if (state != null) {
706                         state.mOrganizer.onBackPressedOnTaskRoot(task);
707                     }
708                     break;
709             }
710         }
711         mPendingTaskEvents.clear();
712     }
713 
reportImeDrawnOnTask(Task task)714     void reportImeDrawnOnTask(Task task) {
715         final TaskOrganizerState state = mTaskOrganizerStates.get(task.mTaskOrganizer.asBinder());
716         if (state != null) {
717             try {
718                 state.mOrganizer.mTaskOrganizer.onImeDrawnOnTask(task.mTaskId);
719             } catch (RemoteException e) {
720                 Slog.e(TAG, "Exception sending onImeDrawnOnTask callback", e);
721             }
722         }
723     }
724 
onTaskInfoChanged(Task task, boolean force)725     void onTaskInfoChanged(Task task, boolean force) {
726         if (!task.mTaskAppearedSent) {
727             // Skip if task still not appeared.
728             return;
729         }
730 
731         // Defer task info reporting while layout is deferred. This is because layout defer
732         // blocks tend to do lots of re-ordering which can mess up animations in receivers.
733         PendingTaskEvent pending = getPendingLifecycleTaskEvent(task);
734         if (pending == null) {
735             pending = new PendingTaskEvent(task, PendingTaskEvent.EVENT_INFO_CHANGED);
736         } else {
737             if (pending.mEventType != PendingTaskEvent.EVENT_INFO_CHANGED) {
738                 // If queued event is appeared, it means task still not appeared so ignore
739                 // this info changed. If queued event is vanished, it means task should
740                 // will vanished early so do not need this info changed.
741                 return;
742             }
743             // Remove and add for re-ordering.
744             mPendingTaskEvents.remove(pending);
745         }
746         pending.mForce |= force;
747         mPendingTaskEvents.add(pending);
748     }
749 
dispatchTaskInfoChanged(Task task, boolean force)750     private void dispatchTaskInfoChanged(Task task, boolean force) {
751         RunningTaskInfo lastInfo = mLastSentTaskInfos.get(task);
752         if (mTmpTaskInfo == null) {
753             mTmpTaskInfo = new RunningTaskInfo();
754         }
755         mTmpTaskInfo.configuration.unset();
756         task.fillTaskInfo(mTmpTaskInfo);
757 
758         boolean changed = !mTmpTaskInfo.equalsForTaskOrganizer(lastInfo)
759                 || !configurationsAreEqualForOrganizer(
760                         mTmpTaskInfo.configuration, lastInfo.configuration);
761         if (!(changed || force)) {
762             // mTmpTaskInfo will be reused next time.
763             return;
764         }
765         final RunningTaskInfo newInfo = mTmpTaskInfo;
766         mLastSentTaskInfos.put(task, mTmpTaskInfo);
767         // Since we've stored this, clean up the reference so a new one will be created next time.
768         // Transferring it this way means we only have to construct new RunningTaskInfos when they
769         // change.
770         mTmpTaskInfo = null;
771 
772         if (task.isOrganized()) {
773             // Because we defer sending taskAppeared() until the app has drawn, we may receive a
774             // configuration change before the state actually has the task registered. As such we
775             // should ignore these change events to the organizer until taskAppeared(). If the task
776             // was created by the organizer, then we always send the info change.
777             final TaskOrganizerState state = mTaskOrganizerStates.get(
778                     task.mTaskOrganizer.asBinder());
779             if (state != null) {
780                 state.mOrganizer.onTaskInfoChanged(task, newInfo);
781             }
782         }
783     }
784 
785     @Override
getImeTarget(int displayId)786     public WindowContainerToken getImeTarget(int displayId) {
787         enforceTaskPermission("getImeTarget()");
788         final long origId = Binder.clearCallingIdentity();
789         try {
790             synchronized (mGlobalLock) {
791                 DisplayContent dc = mService.mWindowManager.mRoot
792                         .getDisplayContent(displayId);
793                 if (dc == null || dc.getImeTarget(IME_TARGET_LAYERING) == null) {
794                     return null;
795                 }
796                 // Avoid WindowState#getRootTask() so we don't attribute system windows to a task.
797                 final Task task = dc.getImeTarget(IME_TARGET_LAYERING).getWindow().getTask();
798                 if (task == null) {
799                     return null;
800                 }
801                 return task.getRootTask().mRemoteToken.toWindowContainerToken();
802             }
803         } finally {
804             Binder.restoreCallingIdentity(origId);
805         }
806     }
807 
808     @Override
getChildTasks(WindowContainerToken parent, @Nullable int[] activityTypes)809     public List<RunningTaskInfo> getChildTasks(WindowContainerToken parent,
810             @Nullable int[] activityTypes) {
811         enforceTaskPermission("getChildTasks()");
812         final long ident = Binder.clearCallingIdentity();
813         try {
814             synchronized (mGlobalLock) {
815                 if (parent == null) {
816                     throw new IllegalArgumentException("Can't get children of null parent");
817                 }
818                 final WindowContainer container = WindowContainer.fromBinder(parent.asBinder());
819                 if (container == null) {
820                     Slog.e(TAG, "Can't get children of " + parent + " because it is not valid.");
821                     return null;
822                 }
823                 final Task task = container.asTask();
824                 if (task == null) {
825                     Slog.e(TAG, container + " is not a task...");
826                     return null;
827                 }
828                 // For now, only support returning children of tasks created by the organizer.
829                 if (!task.mCreatedByOrganizer) {
830                     Slog.w(TAG, "Can only get children of root tasks created via createRootTask");
831                     return null;
832                 }
833                 ArrayList<RunningTaskInfo> out = new ArrayList<>();
834                 for (int i = task.getChildCount() - 1; i >= 0; --i) {
835                     final Task child = task.getChildAt(i).asTask();
836                     if (child == null) continue;
837                     if (activityTypes != null
838                             && !ArrayUtils.contains(activityTypes, child.getActivityType())) {
839                         continue;
840                     }
841                     out.add(child.getTaskInfo());
842                 }
843                 return out;
844             }
845         } finally {
846             Binder.restoreCallingIdentity(ident);
847         }
848     }
849 
850     @Override
getRootTasks(int displayId, @Nullable int[] activityTypes)851     public List<RunningTaskInfo> getRootTasks(int displayId, @Nullable int[] activityTypes) {
852         enforceTaskPermission("getRootTasks()");
853         final long ident = Binder.clearCallingIdentity();
854         try {
855             synchronized (mGlobalLock) {
856                 final DisplayContent dc =
857                         mService.mRootWindowContainer.getDisplayContent(displayId);
858                 if (dc == null) {
859                     throw new IllegalArgumentException("Display " + displayId + " doesn't exist");
860                 }
861                 final ArrayList<RunningTaskInfo> out = new ArrayList<>();
862                 dc.forAllRootTasks(task -> {
863                     if (activityTypes != null
864                             && !ArrayUtils.contains(activityTypes, task.getActivityType())) {
865                         return;
866                     }
867                     out.add(task.getTaskInfo());
868                 });
869                 return out;
870             }
871         } finally {
872             Binder.restoreCallingIdentity(ident);
873         }
874     }
875 
876     @Override
setInterceptBackPressedOnTaskRoot(WindowContainerToken token, boolean interceptBackPressed)877     public void setInterceptBackPressedOnTaskRoot(WindowContainerToken token,
878             boolean interceptBackPressed) {
879         enforceTaskPermission("setInterceptBackPressedOnTaskRoot()");
880         final long origId = Binder.clearCallingIdentity();
881         try {
882             synchronized (mGlobalLock) {
883                 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Set intercept back pressed on root=%b",
884                         interceptBackPressed);
885                 final WindowContainer wc = WindowContainer.fromBinder(token.asBinder());
886                 if (wc == null) {
887                     Slog.w(TAG, "Could not resolve window from token");
888                     return;
889                 }
890                 final Task task = wc.asTask();
891                 if (task == null) {
892                     Slog.w(TAG, "Could not resolve task from token");
893                     return;
894                 }
895                 if (interceptBackPressed) {
896                     mInterceptBackPressedOnRootTasks.add(task.mTaskId);
897                 } else {
898                     mInterceptBackPressedOnRootTasks.remove(task.mTaskId);
899                 }
900             }
901         } finally {
902             Binder.restoreCallingIdentity(origId);
903         }
904     }
905 
906     @Override
restartTaskTopActivityProcessIfVisible(WindowContainerToken token)907     public void restartTaskTopActivityProcessIfVisible(WindowContainerToken token) {
908         enforceTaskPermission("restartTopActivityProcessIfVisible()");
909         final long origId = Binder.clearCallingIdentity();
910         try {
911             synchronized (mGlobalLock) {
912                 final WindowContainer wc = WindowContainer.fromBinder(token.asBinder());
913                 if (wc == null) {
914                     Slog.w(TAG, "Could not resolve window from token");
915                     return;
916                 }
917                 final Task task = wc.asTask();
918                 if (task == null) {
919                     Slog.w(TAG, "Could not resolve task from token");
920                     return;
921                 }
922                 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
923                         "Restart top activity process of Task taskId=%d", task.mTaskId);
924                 final ActivityRecord activity = task.getTopNonFinishingActivity();
925                 if (activity != null) {
926                     activity.restartProcessIfVisible();
927                 }
928             }
929         } finally {
930             Binder.restoreCallingIdentity(origId);
931         }
932     }
933 
handleInterceptBackPressedOnTaskRoot(Task task)934     public boolean handleInterceptBackPressedOnTaskRoot(Task task) {
935         if (task == null || !task.isOrganized()
936                 || !mInterceptBackPressedOnRootTasks.contains(task.mTaskId)) {
937             return false;
938         }
939 
940         PendingTaskEvent pendingVanished =
941                 getPendingTaskEvent(task, PendingTaskEvent.EVENT_VANISHED);
942         if (pendingVanished != null) {
943             // This task will vanish before this callback so just ignore.
944             return false;
945         }
946 
947         PendingTaskEvent pending = getPendingTaskEvent(
948                 task, PendingTaskEvent.EVENT_ROOT_BACK_PRESSED);
949         if (pending == null) {
950             pending = new PendingTaskEvent(task, PendingTaskEvent.EVENT_ROOT_BACK_PRESSED);
951         } else {
952             // Pending already exist, remove and add for re-ordering.
953             mPendingTaskEvents.remove(pending);
954         }
955         mPendingTaskEvents.add(pending);
956         mService.mWindowManager.mWindowPlacerLocked.requestTraversal();
957         return true;
958     }
959 
960     @Nullable
getPendingTaskEvent(Task task, int type)961     private PendingTaskEvent getPendingTaskEvent(Task task, int type) {
962         for (int i = mPendingTaskEvents.size() - 1; i >= 0; i--) {
963             PendingTaskEvent entry = mPendingTaskEvents.get(i);
964             if (task.mTaskId == entry.mTask.mTaskId && type == entry.mEventType) {
965                 return entry;
966             }
967         }
968         return null;
969     }
970 
971     @VisibleForTesting
972     @Nullable
getPendingLifecycleTaskEvent(Task task)973     PendingTaskEvent getPendingLifecycleTaskEvent(Task task) {
974         for (int i = mPendingTaskEvents.size() - 1; i >= 0; i--) {
975             PendingTaskEvent entry = mPendingTaskEvents.get(i);
976             if (task.mTaskId == entry.mTask.mTaskId && entry.isLifecycleEvent()) {
977                 return entry;
978             }
979         }
980         return null;
981     }
982 
dump(PrintWriter pw, String prefix)983     public void dump(PrintWriter pw, String prefix) {
984         final String innerPrefix = prefix + "  ";
985         pw.print(prefix); pw.println("TaskOrganizerController:");
986         for (final TaskOrganizerState state : mTaskOrganizerStates.values()) {
987             final ArrayList<Task> tasks = state.mOrganizedTasks;
988             pw.print(innerPrefix + "  ");
989             pw.println(state.mOrganizer.mTaskOrganizer + " uid=" + state.mUid + ":");
990             for (int k = 0; k < tasks.size(); k++) {
991                 final Task task = tasks.get(k);
992                 final int mode = task.getWindowingMode();
993                 pw.println(innerPrefix + "    ("
994                         + WindowConfiguration.windowingModeToString(mode) + ") " + task);
995             }
996 
997         }
998         pw.println();
999     }
1000 }
1001