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.Manifest.permission.MANAGE_ACTIVITY_STACKS;
20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
21 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
23 
24 import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_CONFIGS;
25 import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_WINDOW_CONFIGS;
26 
27 import android.annotation.Nullable;
28 import android.app.ActivityManager;
29 import android.app.ActivityManager.RunningTaskInfo;
30 import android.app.ActivityManager.TaskDescription;
31 import android.app.WindowConfiguration;
32 import android.content.Intent;
33 import android.content.pm.ActivityInfo;
34 import android.os.Binder;
35 import android.os.IBinder;
36 import android.os.RemoteException;
37 import android.util.Slog;
38 import android.util.SparseArray;
39 import android.view.SurfaceControl;
40 import android.window.ITaskOrganizer;
41 import android.window.ITaskOrganizerController;
42 import android.window.WindowContainerToken;
43 
44 import com.android.internal.annotations.VisibleForTesting;
45 import com.android.internal.util.ArrayUtils;
46 
47 import java.io.PrintWriter;
48 import java.util.ArrayList;
49 import java.util.HashMap;
50 import java.util.LinkedList;
51 import java.util.List;
52 import java.util.WeakHashMap;
53 import java.util.function.Consumer;
54 
55 /**
56  * Stores the TaskOrganizers associated with a given windowing mode and
57  * their associated state.
58  */
59 class TaskOrganizerController extends ITaskOrganizerController.Stub {
60     private static final String TAG = "TaskOrganizerController";
61     private static final LinkedList<IBinder> EMPTY_LIST = new LinkedList<>();
62 
63     /**
64      * Masks specifying which configurations are important to report back to an organizer when
65      * changed.
66      */
67     private static final int REPORT_CONFIGS = CONTROLLABLE_CONFIGS;
68     private static final int REPORT_WINDOW_CONFIGS = CONTROLLABLE_WINDOW_CONFIGS;
69 
70     private final WindowManagerGlobalLock mGlobalLock;
71 
72     private class DeathRecipient implements IBinder.DeathRecipient {
73         ITaskOrganizer mTaskOrganizer;
74 
DeathRecipient(ITaskOrganizer organizer)75         DeathRecipient(ITaskOrganizer organizer) {
76             mTaskOrganizer = organizer;
77         }
78 
79         @Override
binderDied()80         public void binderDied() {
81             synchronized (mGlobalLock) {
82                 final TaskOrganizerState state = mTaskOrganizerStates.remove(
83                         mTaskOrganizer.asBinder());
84                 if (state != null) {
85                     state.dispose();
86                 }
87             }
88         }
89     }
90 
91     /**
92      * A wrapper class around ITaskOrganizer to ensure that the calls are made in the right
93      * lifecycle order since we may be updating the visibility of task surface controls in a pending
94      * transaction before they are presented to the task org.
95      */
96     private class TaskOrganizerCallbacks {
97         final WindowManagerService mService;
98         final ITaskOrganizer mTaskOrganizer;
99         final Consumer<Runnable> mDeferTaskOrgCallbacksConsumer;
100 
101         private final SurfaceControl.Transaction mTransaction;
102 
TaskOrganizerCallbacks(WindowManagerService wm, ITaskOrganizer taskOrg, Consumer<Runnable> deferTaskOrgCallbacksConsumer)103         TaskOrganizerCallbacks(WindowManagerService wm, ITaskOrganizer taskOrg,
104                 Consumer<Runnable> deferTaskOrgCallbacksConsumer) {
105             mService = wm;
106             mDeferTaskOrgCallbacksConsumer = deferTaskOrgCallbacksConsumer;
107             mTaskOrganizer = taskOrg;
108             mTransaction = wm.mTransactionFactory.get();
109         }
110 
getBinder()111         IBinder getBinder() {
112             return mTaskOrganizer.asBinder();
113         }
114 
onTaskAppeared(Task task)115         void onTaskAppeared(Task task) {
116             final boolean visible = task.isVisible();
117             final RunningTaskInfo taskInfo = task.getTaskInfo();
118             mDeferTaskOrgCallbacksConsumer.accept(() -> {
119                 try {
120                     SurfaceControl outSurfaceControl = new SurfaceControl(task.getSurfaceControl(),
121                             "TaskOrganizerController.onTaskAppeared");
122                     if (!task.mCreatedByOrganizer && !visible) {
123                         // To prevent flashes, we hide the task prior to sending the leash to the
124                         // task org if the task has previously hidden (ie. when entering PIP)
125                         mTransaction.hide(outSurfaceControl);
126                         mTransaction.apply();
127                     }
128                     mTaskOrganizer.onTaskAppeared(taskInfo, outSurfaceControl);
129                 } catch (RemoteException e) {
130                     Slog.e(TAG, "Exception sending onTaskAppeared callback", e);
131                 }
132             });
133         }
134 
135 
onTaskVanished(Task task)136         void onTaskVanished(Task task) {
137             final RunningTaskInfo taskInfo = task.getTaskInfo();
138             mDeferTaskOrgCallbacksConsumer.accept(() -> {
139                 try {
140                     mTaskOrganizer.onTaskVanished(taskInfo);
141                 } catch (RemoteException e) {
142                     Slog.e(TAG, "Exception sending onTaskVanished callback", e);
143                 }
144             });
145         }
146 
onTaskInfoChanged(Task task, ActivityManager.RunningTaskInfo taskInfo)147         void onTaskInfoChanged(Task task, ActivityManager.RunningTaskInfo taskInfo) {
148             if (!task.mCreatedByOrganizer && !task.mTaskAppearedSent) {
149                 // Skip if the task has not yet received taskAppeared(), except for tasks created
150                 // by the organizer that don't receive that signal
151                 return;
152             }
153             mDeferTaskOrgCallbacksConsumer.accept(() -> {
154                 if (!task.isOrganized()) {
155                     // This is safe to ignore if the task is no longer organized
156                     return;
157                 }
158                 try {
159                     mTaskOrganizer.onTaskInfoChanged(taskInfo);
160                 } catch (RemoteException e) {
161                     Slog.e(TAG, "Exception sending onTaskInfoChanged callback", e);
162                 }
163             });
164         }
165 
onBackPressedOnTaskRoot(Task task)166         void onBackPressedOnTaskRoot(Task task) {
167             if (!task.mCreatedByOrganizer && !task.mTaskAppearedSent) {
168                 // Skip if the task has not yet received taskAppeared(), except for tasks created
169                 // by the organizer that don't receive that signal
170                 return;
171             }
172             mDeferTaskOrgCallbacksConsumer.accept(() -> {
173                 if (!task.isOrganized()) {
174                     // This is safe to ignore if the task is no longer organized
175                     return;
176                 }
177                 try {
178                    mTaskOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo());
179                 } catch (Exception e) {
180                     Slog.e(TAG, "Exception sending onBackPressedOnTaskRoot callback", e);
181                 }
182             });
183         }
184     }
185 
186     private class TaskOrganizerState {
187         private final TaskOrganizerCallbacks mOrganizer;
188         private final DeathRecipient mDeathRecipient;
189         private final ArrayList<Task> mOrganizedTasks = new ArrayList<>();
190         private final int mUid;
191         private boolean mInterceptBackPressedOnTaskRoot;
192 
TaskOrganizerState(ITaskOrganizer organizer, int uid)193         TaskOrganizerState(ITaskOrganizer organizer, int uid) {
194             final Consumer<Runnable> deferTaskOrgCallbacksConsumer =
195                     mDeferTaskOrgCallbacksConsumer != null
196                             ? mDeferTaskOrgCallbacksConsumer
197                             : mService.mWindowManager.mAnimator::addAfterPrepareSurfacesRunnable;
198             mOrganizer = new TaskOrganizerCallbacks(mService.mWindowManager, organizer,
199                     deferTaskOrgCallbacksConsumer);
200             mDeathRecipient = new DeathRecipient(organizer);
201             try {
202                 organizer.asBinder().linkToDeath(mDeathRecipient, 0);
203             } catch (RemoteException e) {
204                 Slog.e(TAG, "TaskOrganizer failed to register death recipient");
205             }
206             mUid = uid;
207         }
208 
setInterceptBackPressedOnTaskRoot(boolean interceptBackPressed)209         void setInterceptBackPressedOnTaskRoot(boolean interceptBackPressed) {
210             mInterceptBackPressedOnTaskRoot = interceptBackPressed;
211         }
212 
addTask(Task t)213         void addTask(Task t) {
214             if (t.mTaskAppearedSent) return;
215 
216             if (!mOrganizedTasks.contains(t)) {
217                 mOrganizedTasks.add(t);
218             }
219             if (t.taskAppearedReady()) {
220                 t.mTaskAppearedSent = true;
221                 mOrganizer.onTaskAppeared(t);
222             }
223         }
224 
removeTask(Task t)225         void removeTask(Task t) {
226             if (t.mTaskAppearedSent) {
227                 t.migrateToNewSurfaceControl();
228                 t.mTaskAppearedSent = false;
229                 mOrganizer.onTaskVanished(t);
230             }
231             mOrganizedTasks.remove(t);
232         }
233 
dispose()234         void dispose() {
235             // Move organizer from managing specific windowing modes
236             for (int i = mTaskOrganizersForWindowingMode.size() - 1; i >= 0; --i) {
237                 mTaskOrganizersForWindowingMode.valueAt(i).remove(mOrganizer.getBinder());
238             }
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                     removeTask(t);
247                 }
248             }
249 
250             // Remove organizer state after removing tasks so we get a chance to send
251             // onTaskVanished.
252             mTaskOrganizerStates.remove(asBinder());
253         }
254 
unlinkDeath()255         void unlinkDeath() {
256             mOrganizer.getBinder().unlinkToDeath(mDeathRecipient, 0);
257         }
258     }
259 
260     private final SparseArray<LinkedList<IBinder>> mTaskOrganizersForWindowingMode =
261             new SparseArray<>();
262     private final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap<>();
263     private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
264     private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>();
265 
266     private final ActivityTaskManagerService mService;
267 
268     private RunningTaskInfo mTmpTaskInfo;
269     private Consumer<Runnable> mDeferTaskOrgCallbacksConsumer;
270 
TaskOrganizerController(ActivityTaskManagerService atm)271     TaskOrganizerController(ActivityTaskManagerService atm) {
272         mService = atm;
273         mGlobalLock = atm.mGlobalLock;
274     }
275 
enforceStackPermission(String func)276     private void enforceStackPermission(String func) {
277         mService.mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, func);
278     }
279 
280     /**
281      * Specifies the consumer to run to defer the task org callbacks. Can be overridden while
282      * testing to allow the callbacks to be sent synchronously.
283      */
284     @VisibleForTesting
setDeferTaskOrgCallbacksConsumer(Consumer<Runnable> consumer)285     public void setDeferTaskOrgCallbacksConsumer(Consumer<Runnable> consumer) {
286         mDeferTaskOrgCallbacksConsumer = consumer;
287     }
288 
289     /**
290      * Register a TaskOrganizer to manage tasks as they enter the given windowing mode.
291      * If there was already a TaskOrganizer for this windowing mode it will be evicted
292      * but will continue to organize it's existing tasks.
293      */
294     @Override
registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode)295     public void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode) {
296         if (windowingMode == WINDOWING_MODE_PINNED) {
297             if (!mService.mSupportsPictureInPicture) {
298                 throw new UnsupportedOperationException("Picture in picture is not supported on "
299                         + "this device");
300             }
301         } else if (WindowConfiguration.isSplitScreenWindowingMode(windowingMode)) {
302             if (!mService.mSupportsSplitScreenMultiWindow) {
303                 throw new UnsupportedOperationException("Split-screen is not supported on this "
304                         + "device");
305             }
306         } else if (windowingMode == WINDOWING_MODE_MULTI_WINDOW) {
307             if (!mService.mSupportsMultiWindow) {
308                 throw new UnsupportedOperationException("Multi-window is not supported on this "
309                         + "device");
310             }
311         } else {
312             throw new UnsupportedOperationException("As of now only Pinned/Split/Multiwindow"
313                     + " windowing modes are supported for registerTaskOrganizer");
314         }
315         enforceStackPermission("registerTaskOrganizer()");
316         final int uid = Binder.getCallingUid();
317         final long origId = Binder.clearCallingIdentity();
318         try {
319             synchronized (mGlobalLock) {
320                 if (getTaskOrganizer(windowingMode) != null) {
321                     Slog.w(TAG, "Task organizer already exists for windowing mode: "
322                             + windowingMode);
323                 }
324 
325                 LinkedList<IBinder> orgs = mTaskOrganizersForWindowingMode.get(windowingMode);
326                 if (orgs == null) {
327                     orgs = new LinkedList<>();
328                     mTaskOrganizersForWindowingMode.put(windowingMode, orgs);
329                 }
330                 orgs.add(organizer.asBinder());
331                 if (!mTaskOrganizerStates.containsKey(organizer.asBinder())) {
332                     mTaskOrganizerStates.put(organizer.asBinder(),
333                             new TaskOrganizerState(organizer, uid));
334                 }
335 
336                 mService.mRootWindowContainer.forAllTasks((task) -> {
337                     if (task.getWindowingMode() == windowingMode) {
338                         task.updateTaskOrganizerState(true /* forceUpdate */);
339                     }
340                 });
341             }
342         } finally {
343             Binder.restoreCallingIdentity(origId);
344         }
345     }
346 
347     @Override
unregisterTaskOrganizer(ITaskOrganizer organizer)348     public void unregisterTaskOrganizer(ITaskOrganizer organizer) {
349         enforceStackPermission("unregisterTaskOrganizer()");
350         final long origId = Binder.clearCallingIdentity();
351         try {
352             synchronized (mGlobalLock) {
353                 final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
354                 if (state == null) {
355                     return;
356                 }
357                 state.unlinkDeath();
358                 state.dispose();
359             }
360         } finally {
361             Binder.restoreCallingIdentity(origId);
362         }
363     }
364 
getTaskOrganizer(int windowingMode)365     ITaskOrganizer getTaskOrganizer(int windowingMode) {
366         final IBinder organizer =
367                 mTaskOrganizersForWindowingMode.get(windowingMode, EMPTY_LIST).peekLast();
368         if (organizer == null) {
369             return null;
370         }
371         final TaskOrganizerState state = mTaskOrganizerStates.get(organizer);
372         if (state == null) {
373             return null;
374         }
375         return state.mOrganizer.mTaskOrganizer;
376     }
377 
onTaskAppeared(ITaskOrganizer organizer, Task task)378     void onTaskAppeared(ITaskOrganizer organizer, Task task) {
379         final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
380         state.addTask(task);
381     }
382 
onTaskVanished(ITaskOrganizer organizer, Task task)383     void onTaskVanished(ITaskOrganizer organizer, Task task) {
384         final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
385         if (state != null) {
386             state.removeTask(task);
387         }
388     }
389 
390     @Override
createRootTask(int displayId, int windowingMode)391     public RunningTaskInfo createRootTask(int displayId, int windowingMode) {
392         enforceStackPermission("createRootTask()");
393         final long origId = Binder.clearCallingIdentity();
394         try {
395             synchronized (mGlobalLock) {
396                 DisplayContent display = mService.mRootWindowContainer.getDisplayContent(displayId);
397                 if (display == null) {
398                     return null;
399                 }
400 
401                 final Task task = display.getDefaultTaskDisplayArea().createStack(windowingMode,
402                         ACTIVITY_TYPE_UNDEFINED, false /* onTop */, null /* info */, new Intent(),
403                         true /* createdByOrganizer */);
404                 RunningTaskInfo out = task.getTaskInfo();
405                 mLastSentTaskInfos.put(task, out);
406                 return out;
407             }
408         } finally {
409             Binder.restoreCallingIdentity(origId);
410         }
411     }
412 
413     @Override
deleteRootTask(WindowContainerToken token)414     public boolean deleteRootTask(WindowContainerToken token) {
415         enforceStackPermission("deleteRootTask()");
416         final long origId = Binder.clearCallingIdentity();
417         try {
418             synchronized (mGlobalLock) {
419                 final Task task = WindowContainer.fromBinder(token.asBinder()).asTask();
420                 if (task == null) return false;
421                 if (!task.mCreatedByOrganizer) {
422                     throw new IllegalArgumentException(
423                             "Attempt to delete task not created by organizer task=" + task);
424                 }
425                 task.removeImmediately();
426                 return true;
427             }
428         } finally {
429             Binder.restoreCallingIdentity(origId);
430         }
431     }
432 
dispatchPendingTaskInfoChanges()433     void dispatchPendingTaskInfoChanges() {
434         if (mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) {
435             return;
436         }
437         for (int i = 0, n = mPendingTaskInfoChanges.size(); i < n; ++i) {
438             dispatchTaskInfoChanged(mPendingTaskInfoChanges.get(i), false /* force */);
439         }
440         mPendingTaskInfoChanges.clear();
441     }
442 
dispatchTaskInfoChanged(Task task, boolean force)443     void dispatchTaskInfoChanged(Task task, boolean force) {
444         if (!force && mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) {
445             // Defer task info reporting while layout is deferred. This is because layout defer
446             // blocks tend to do lots of re-ordering which can mess up animations in receivers.
447             mPendingTaskInfoChanges.remove(task);
448             mPendingTaskInfoChanges.add(task);
449             return;
450         }
451         RunningTaskInfo lastInfo = mLastSentTaskInfos.get(task);
452         if (mTmpTaskInfo == null) {
453             mTmpTaskInfo = new RunningTaskInfo();
454         }
455         mTmpTaskInfo.configuration.unset();
456         task.fillTaskInfo(mTmpTaskInfo);
457         boolean changed = lastInfo == null
458                 || mTmpTaskInfo.topActivityType != lastInfo.topActivityType
459                 || mTmpTaskInfo.isResizeable != lastInfo.isResizeable
460                 || mTmpTaskInfo.pictureInPictureParams != lastInfo.pictureInPictureParams
461                 || !TaskDescription.equals(mTmpTaskInfo.taskDescription, lastInfo.taskDescription);
462         if (!changed) {
463             int cfgChanges = mTmpTaskInfo.configuration.diff(lastInfo.configuration);
464             final int winCfgChanges = (cfgChanges & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0
465                     ? (int) mTmpTaskInfo.configuration.windowConfiguration.diff(
466                             lastInfo.configuration.windowConfiguration,
467                             true /* compareUndefined */) : 0;
468             if ((winCfgChanges & REPORT_WINDOW_CONFIGS) == 0) {
469                 cfgChanges &= ~ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
470             }
471             changed = (cfgChanges & REPORT_CONFIGS) != 0;
472         }
473         if (!(changed || force)) {
474             return;
475         }
476         final RunningTaskInfo newInfo = mTmpTaskInfo;
477         mLastSentTaskInfos.put(task, mTmpTaskInfo);
478         // Since we've stored this, clean up the reference so a new one will be created next time.
479         // Transferring it this way means we only have to construct new RunningTaskInfos when they
480         // change.
481         mTmpTaskInfo = null;
482 
483         if (task.isOrganized()) {
484             // Because we defer sending taskAppeared() until the app has drawn, we may receive a
485             // configuration change before the state actually has the task registered. As such we
486             // should ignore these change events to the organizer until taskAppeared(). If the task
487             // was created by the organizer, then we always send the info change.
488             final TaskOrganizerState state = mTaskOrganizerStates.get(
489                     task.mTaskOrganizer.asBinder());
490             if (state != null) {
491                 state.mOrganizer.onTaskInfoChanged(task, newInfo);
492             }
493         }
494     }
495 
496     @Override
getImeTarget(int displayId)497     public WindowContainerToken getImeTarget(int displayId) {
498         enforceStackPermission("getImeTarget()");
499         final long origId = Binder.clearCallingIdentity();
500         try {
501             synchronized (mGlobalLock) {
502                 DisplayContent dc = mService.mWindowManager.mRoot
503                         .getDisplayContent(displayId);
504                 if (dc == null || dc.mInputMethodTarget == null) {
505                     return null;
506                 }
507                 // Avoid WindowState#getRootTask() so we don't attribute system windows to a task.
508                 final Task task = dc.mInputMethodTarget.getTask();
509                 if (task == null) {
510                     return null;
511                 }
512                 return task.getRootTask().mRemoteToken.toWindowContainerToken();
513             }
514         } finally {
515             Binder.restoreCallingIdentity(origId);
516         }
517     }
518 
519     @Override
setLaunchRoot(int displayId, @Nullable WindowContainerToken token)520     public void setLaunchRoot(int displayId, @Nullable WindowContainerToken token) {
521         enforceStackPermission("setLaunchRoot()");
522         final long origId = Binder.clearCallingIdentity();
523         try {
524             synchronized (mGlobalLock) {
525                 TaskDisplayArea defaultTaskDisplayArea = mService.mRootWindowContainer
526                         .getDisplayContent(displayId).getDefaultTaskDisplayArea();
527                 if (defaultTaskDisplayArea == null) {
528                     return;
529                 }
530                 Task task = token == null
531                         ? null : WindowContainer.fromBinder(token.asBinder()).asTask();
532                 if (task == null) {
533                     defaultTaskDisplayArea.mLaunchRootTask = null;
534                     return;
535                 }
536                 if (!task.mCreatedByOrganizer) {
537                     throw new IllegalArgumentException("Attempt to set task not created by "
538                             + "organizer as launch root task=" + task);
539                 }
540                 if (task.getDisplayArea() == null
541                         || task.getDisplayArea().getDisplayId() != displayId) {
542                     throw new RuntimeException("Can't set launch root for display " + displayId
543                             + " to task on display " + task.getDisplayContent().getDisplayId());
544                 }
545                 task.getDisplayArea().mLaunchRootTask = task;
546             }
547         } finally {
548             Binder.restoreCallingIdentity(origId);
549         }
550     }
551 
552     @Override
getChildTasks(WindowContainerToken parent, @Nullable int[] activityTypes)553     public List<RunningTaskInfo> getChildTasks(WindowContainerToken parent,
554             @Nullable int[] activityTypes) {
555         enforceStackPermission("getChildTasks()");
556         final long ident = Binder.clearCallingIdentity();
557         try {
558             synchronized (mGlobalLock) {
559                 if (parent == null) {
560                     throw new IllegalArgumentException("Can't get children of null parent");
561                 }
562                 final WindowContainer container = WindowContainer.fromBinder(parent.asBinder());
563                 if (container == null) {
564                     Slog.e(TAG, "Can't get children of " + parent + " because it is not valid.");
565                     return null;
566                 }
567                 final Task task = container.asTask();
568                 if (task == null) {
569                     Slog.e(TAG, container + " is not a task...");
570                     return null;
571                 }
572                 // For now, only support returning children of tasks created by the organizer.
573                 if (!task.mCreatedByOrganizer) {
574                     Slog.w(TAG, "Can only get children of root tasks created via createRootTask");
575                     return null;
576                 }
577                 ArrayList<RunningTaskInfo> out = new ArrayList<>();
578                 for (int i = task.getChildCount() - 1; i >= 0; --i) {
579                     final Task child = task.getChildAt(i).asTask();
580                     if (child == null) continue;
581                     if (activityTypes != null
582                             && !ArrayUtils.contains(activityTypes, child.getActivityType())) {
583                         continue;
584                     }
585                     out.add(child.getTaskInfo());
586                 }
587                 return out;
588             }
589         } finally {
590             Binder.restoreCallingIdentity(ident);
591         }
592     }
593 
594     @Override
getRootTasks(int displayId, @Nullable int[] activityTypes)595     public List<RunningTaskInfo> getRootTasks(int displayId, @Nullable int[] activityTypes) {
596         enforceStackPermission("getRootTasks()");
597         final long ident = Binder.clearCallingIdentity();
598         try {
599             synchronized (mGlobalLock) {
600                 final DisplayContent dc =
601                         mService.mRootWindowContainer.getDisplayContent(displayId);
602                 if (dc == null) {
603                     throw new IllegalArgumentException("Display " + displayId + " doesn't exist");
604                 }
605                 ArrayList<RunningTaskInfo> out = new ArrayList<>();
606                 for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
607                     final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx);
608                     for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
609                         final Task task = taskDisplayArea.getStackAt(sNdx);
610                         if (activityTypes != null
611                                 && !ArrayUtils.contains(activityTypes, task.getActivityType())) {
612                             continue;
613                         }
614                         out.add(task.getTaskInfo());
615                     }
616                 }
617                 return out;
618             }
619         } finally {
620             Binder.restoreCallingIdentity(ident);
621         }
622     }
623 
624     @Override
setInterceptBackPressedOnTaskRoot(ITaskOrganizer organizer, boolean interceptBackPressed)625     public void setInterceptBackPressedOnTaskRoot(ITaskOrganizer organizer,
626             boolean interceptBackPressed) {
627         enforceStackPermission("setInterceptBackPressedOnTaskRoot()");
628         final long origId = Binder.clearCallingIdentity();
629         try {
630             synchronized (mGlobalLock) {
631                 final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
632                 if (state != null) {
633                     state.setInterceptBackPressedOnTaskRoot(interceptBackPressed);
634                 }
635             }
636         } finally {
637             Binder.restoreCallingIdentity(origId);
638         }
639     }
640 
handleInterceptBackPressedOnTaskRoot(Task task)641     public boolean handleInterceptBackPressedOnTaskRoot(Task task) {
642         if (task == null || !task.isOrganized()) {
643             return false;
644         }
645 
646         final TaskOrganizerState state = mTaskOrganizerStates.get(task.mTaskOrganizer.asBinder());
647         if (!state.mInterceptBackPressedOnTaskRoot) {
648             return false;
649         }
650 
651         state.mOrganizer.onBackPressedOnTaskRoot(task);
652         return true;
653     }
654 
dump(PrintWriter pw, String prefix)655     public void dump(PrintWriter pw, String prefix) {
656         final String innerPrefix = prefix + "  ";
657         pw.print(prefix); pw.println("TaskOrganizerController:");
658         pw.print(innerPrefix); pw.println("Per windowing mode:");
659         for (int i = 0; i < mTaskOrganizersForWindowingMode.size(); i++) {
660             final int windowingMode = mTaskOrganizersForWindowingMode.keyAt(i);
661             final List<IBinder> taskOrgs = mTaskOrganizersForWindowingMode.valueAt(i);
662             pw.println(innerPrefix + "  "
663                     + WindowConfiguration.windowingModeToString(windowingMode) + ":");
664             for (int j = 0; j < taskOrgs.size(); j++) {
665                 final TaskOrganizerState state =  mTaskOrganizerStates.get(taskOrgs.get(j));
666                 final ArrayList<Task> tasks = state.mOrganizedTasks;
667                 pw.print(innerPrefix + "    ");
668                 pw.println(state.mOrganizer.mTaskOrganizer + " uid=" + state.mUid + ":");
669                 for (int k = 0; k < tasks.size(); k++) {
670                     pw.println(innerPrefix + "      " + tasks.get(k));
671                 }
672             }
673 
674         }
675         pw.println();
676     }
677 }
678