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