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