1 /* 2 * Copyright (C) 2021 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.ActivityTaskManager.INVALID_TASK_ID; 20 import static android.window.TaskFragmentOrganizer.putErrorInfoInBundle; 21 import static android.window.TaskFragmentTransaction.TYPE_ACTIVITY_REPARENTED_TO_TASK; 22 import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED; 23 import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR; 24 import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_INFO_CHANGED; 25 import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED; 26 import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED; 27 28 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER; 29 import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED; 30 import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer; 31 32 import static java.util.Objects.requireNonNull; 33 34 import android.annotation.IntDef; 35 import android.annotation.NonNull; 36 import android.annotation.Nullable; 37 import android.content.Intent; 38 import android.content.res.Configuration; 39 import android.os.Binder; 40 import android.os.Bundle; 41 import android.os.IBinder; 42 import android.os.RemoteException; 43 import android.util.ArrayMap; 44 import android.util.ArraySet; 45 import android.util.Slog; 46 import android.util.SparseArray; 47 import android.view.RemoteAnimationDefinition; 48 import android.view.WindowManager; 49 import android.window.ITaskFragmentOrganizer; 50 import android.window.ITaskFragmentOrganizerController; 51 import android.window.TaskFragmentInfo; 52 import android.window.TaskFragmentParentInfo; 53 import android.window.TaskFragmentTransaction; 54 import android.window.WindowContainerTransaction; 55 56 import com.android.internal.protolog.ProtoLogGroup; 57 import com.android.internal.protolog.common.ProtoLog; 58 59 import java.lang.annotation.Retention; 60 import java.lang.annotation.RetentionPolicy; 61 import java.util.ArrayList; 62 import java.util.List; 63 import java.util.Map; 64 import java.util.WeakHashMap; 65 66 /** 67 * Stores and manages the client {@link android.window.TaskFragmentOrganizer}. 68 */ 69 public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerController.Stub { 70 private static final String TAG = "TaskFragmentOrganizerController"; 71 private static final long TEMPORARY_ACTIVITY_TOKEN_TIMEOUT_MS = 5000; 72 73 private final ActivityTaskManagerService mAtmService; 74 private final WindowManagerGlobalLock mGlobalLock; 75 private final WindowOrganizerController mWindowOrganizerController; 76 77 /** 78 * A Map which manages the relationship between 79 * {@link ITaskFragmentOrganizer} and {@link TaskFragmentOrganizerState} 80 */ 81 private final ArrayMap<IBinder, TaskFragmentOrganizerState> mTaskFragmentOrganizerState = 82 new ArrayMap<>(); 83 /** 84 * Map from {@link ITaskFragmentOrganizer} to a list of related {@link PendingTaskFragmentEvent} 85 */ 86 private final ArrayMap<IBinder, List<PendingTaskFragmentEvent>> mPendingTaskFragmentEvents = 87 new ArrayMap<>(); 88 89 private final ArraySet<Task> mTmpTaskSet = new ArraySet<>(); 90 TaskFragmentOrganizerController(@onNull ActivityTaskManagerService atm, @NonNull WindowOrganizerController windowOrganizerController)91 TaskFragmentOrganizerController(@NonNull ActivityTaskManagerService atm, 92 @NonNull WindowOrganizerController windowOrganizerController) { 93 mAtmService = requireNonNull(atm); 94 mGlobalLock = atm.mGlobalLock; 95 mWindowOrganizerController = requireNonNull(windowOrganizerController); 96 } 97 98 /** 99 * A class to manage {@link ITaskFragmentOrganizer} and its organized 100 * {@link TaskFragment TaskFragments}. 101 */ 102 private class TaskFragmentOrganizerState implements IBinder.DeathRecipient { 103 private final ArrayList<TaskFragment> mOrganizedTaskFragments = new ArrayList<>(); 104 private final ITaskFragmentOrganizer mOrganizer; 105 private final int mOrganizerPid; 106 private final int mOrganizerUid; 107 108 /** 109 * Map from {@link TaskFragment} to the last {@link TaskFragmentInfo} sent to the 110 * organizer. 111 */ 112 private final Map<TaskFragment, TaskFragmentInfo> mLastSentTaskFragmentInfos = 113 new WeakHashMap<>(); 114 115 /** 116 * Map from {@link TaskFragment} to its leaf {@link Task#mTaskId}. Embedded 117 * {@link TaskFragment} will not be reparented until it is removed. 118 */ 119 private final Map<TaskFragment, Integer> mTaskFragmentTaskIds = new WeakHashMap<>(); 120 121 /** 122 * Map from {@link Task#mTaskId} to the last {@link TaskFragmentParentInfo} sent to the 123 * organizer. 124 */ 125 private final SparseArray<TaskFragmentParentInfo> mLastSentTaskFragmentParentInfos = 126 new SparseArray<>(); 127 128 /** 129 * Map from temporary activity token to the corresponding {@link ActivityRecord}. 130 */ 131 private final Map<IBinder, ActivityRecord> mTemporaryActivityTokens = 132 new WeakHashMap<>(); 133 134 /** 135 * {@link RemoteAnimationDefinition} for embedded activities transition animation that is 136 * organized by this organizer. 137 */ 138 @Nullable 139 private RemoteAnimationDefinition mRemoteAnimationDefinition; 140 141 /** 142 * Map from {@link TaskFragmentTransaction#getTransactionToken()} to the 143 * {@link Transition#getSyncId()} that has been deferred. {@link TransitionController} will 144 * wait until the organizer finished handling the {@link TaskFragmentTransaction}. 145 * @see #onTransactionFinished(IBinder) 146 */ 147 private final ArrayMap<IBinder, Integer> mDeferredTransitions = new ArrayMap<>(); 148 TaskFragmentOrganizerState(ITaskFragmentOrganizer organizer, int pid, int uid)149 TaskFragmentOrganizerState(ITaskFragmentOrganizer organizer, int pid, int uid) { 150 mOrganizer = organizer; 151 mOrganizerPid = pid; 152 mOrganizerUid = uid; 153 try { 154 mOrganizer.asBinder().linkToDeath(this, 0 /*flags*/); 155 } catch (RemoteException e) { 156 Slog.e(TAG, "TaskFragmentOrganizer failed to register death recipient"); 157 } 158 } 159 160 @Override binderDied()161 public void binderDied() { 162 synchronized (mGlobalLock) { 163 removeOrganizer(mOrganizer); 164 } 165 } 166 167 /** 168 * @return {@code true} if taskFragment is organized and not sent the appeared event before. 169 */ addTaskFragment(TaskFragment taskFragment)170 boolean addTaskFragment(TaskFragment taskFragment) { 171 if (taskFragment.mTaskFragmentAppearedSent) { 172 return false; 173 } 174 if (mOrganizedTaskFragments.contains(taskFragment)) { 175 return false; 176 } 177 mOrganizedTaskFragments.add(taskFragment); 178 return true; 179 } 180 removeTaskFragment(TaskFragment taskFragment)181 void removeTaskFragment(TaskFragment taskFragment) { 182 mOrganizedTaskFragments.remove(taskFragment); 183 } 184 dispose()185 void dispose() { 186 for (int i = mOrganizedTaskFragments.size() - 1; i >= 0; i--) { 187 // Cleanup the TaskFragmentOrganizer from all TaskFragments it organized before 188 // removing the windows to prevent it from adding any additional TaskFragment 189 // pending event. 190 final TaskFragment taskFragment = mOrganizedTaskFragments.get(i); 191 taskFragment.onTaskFragmentOrganizerRemoved(); 192 } 193 194 // Defer to avoid unnecessary layout when there are multiple TaskFragments removal. 195 mAtmService.deferWindowLayout(); 196 try { 197 while (!mOrganizedTaskFragments.isEmpty()) { 198 final TaskFragment taskFragment = mOrganizedTaskFragments.remove(0); 199 taskFragment.removeImmediately(); 200 } 201 } finally { 202 mAtmService.continueWindowLayout(); 203 } 204 205 for (int i = mDeferredTransitions.size() - 1; i >= 0; i--) { 206 // Cleanup any running transaction to unblock the current transition. 207 onTransactionFinished(mDeferredTransitions.keyAt(i)); 208 } 209 mOrganizer.asBinder().unlinkToDeath(this, 0 /* flags */); 210 } 211 212 @NonNull prepareTaskFragmentAppeared(@onNull TaskFragment tf)213 TaskFragmentTransaction.Change prepareTaskFragmentAppeared(@NonNull TaskFragment tf) { 214 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment appeared name=%s", tf.getName()); 215 final TaskFragmentInfo info = tf.getTaskFragmentInfo(); 216 final int taskId = tf.getTask().mTaskId; 217 tf.mTaskFragmentAppearedSent = true; 218 mLastSentTaskFragmentInfos.put(tf, info); 219 mTaskFragmentTaskIds.put(tf, taskId); 220 return new TaskFragmentTransaction.Change( 221 TYPE_TASK_FRAGMENT_APPEARED) 222 .setTaskFragmentToken(tf.getFragmentToken()) 223 .setTaskFragmentInfo(info) 224 .setTaskId(taskId); 225 } 226 227 @NonNull prepareTaskFragmentVanished(@onNull TaskFragment tf)228 TaskFragmentTransaction.Change prepareTaskFragmentVanished(@NonNull TaskFragment tf) { 229 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment vanished name=%s", tf.getName()); 230 tf.mTaskFragmentAppearedSent = false; 231 mLastSentTaskFragmentInfos.remove(tf); 232 233 // Cleanup TaskFragmentParentConfig if this is the last TaskFragment in the Task. 234 final int taskId; 235 if (mTaskFragmentTaskIds.containsKey(tf)) { 236 taskId = mTaskFragmentTaskIds.remove(tf); 237 if (!mTaskFragmentTaskIds.containsValue(taskId)) { 238 // No more TaskFragment in the Task. 239 mLastSentTaskFragmentParentInfos.remove(taskId); 240 } 241 } else { 242 // This can happen if the appeared wasn't sent before remove. 243 taskId = INVALID_TASK_ID; 244 } 245 246 return new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_VANISHED) 247 .setTaskFragmentToken(tf.getFragmentToken()) 248 .setTaskFragmentInfo(tf.getTaskFragmentInfo()) 249 .setTaskId(taskId); 250 } 251 252 @Nullable prepareTaskFragmentInfoChanged( @onNull TaskFragment tf)253 TaskFragmentTransaction.Change prepareTaskFragmentInfoChanged( 254 @NonNull TaskFragment tf) { 255 // Check if the info is different from the last reported info. 256 final TaskFragmentInfo info = tf.getTaskFragmentInfo(); 257 final TaskFragmentInfo lastInfo = mLastSentTaskFragmentInfos.get(tf); 258 if (info.equalsForTaskFragmentOrganizer(lastInfo) && configurationsAreEqualForOrganizer( 259 info.getConfiguration(), lastInfo.getConfiguration())) { 260 return null; 261 } 262 263 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s", 264 tf.getName()); 265 mLastSentTaskFragmentInfos.put(tf, info); 266 return new TaskFragmentTransaction.Change( 267 TYPE_TASK_FRAGMENT_INFO_CHANGED) 268 .setTaskFragmentToken(tf.getFragmentToken()) 269 .setTaskFragmentInfo(info) 270 .setTaskId(tf.getTask().mTaskId); 271 } 272 273 @Nullable prepareTaskFragmentParentInfoChanged(@onNull Task task)274 TaskFragmentTransaction.Change prepareTaskFragmentParentInfoChanged(@NonNull Task task) { 275 final int taskId = task.mTaskId; 276 // Check if the parent info is different from the last reported parent info. 277 final TaskFragmentParentInfo parentInfo = task.getTaskFragmentParentInfo(); 278 final TaskFragmentParentInfo lastParentInfo = mLastSentTaskFragmentParentInfos 279 .get(taskId); 280 final Configuration lastParentConfig = lastParentInfo != null 281 ? lastParentInfo.getConfiguration() : null; 282 if (parentInfo.equalsForTaskFragmentOrganizer(lastParentInfo) 283 && configurationsAreEqualForOrganizer(parentInfo.getConfiguration(), 284 lastParentConfig)) { 285 return null; 286 } 287 288 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, 289 "TaskFragment parent info changed name=%s parentTaskId=%d", 290 task.getName(), taskId); 291 mLastSentTaskFragmentParentInfos.put(taskId, new TaskFragmentParentInfo(parentInfo)); 292 return new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED) 293 .setTaskId(taskId) 294 .setTaskFragmentParentInfo(parentInfo); 295 } 296 297 @NonNull prepareTaskFragmentError( @ullable IBinder errorCallbackToken, @Nullable TaskFragment taskFragment, int opType, @NonNull Throwable exception)298 TaskFragmentTransaction.Change prepareTaskFragmentError( 299 @Nullable IBinder errorCallbackToken, @Nullable TaskFragment taskFragment, 300 int opType, @NonNull Throwable exception) { 301 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, 302 "Sending TaskFragment error exception=%s", exception.toString()); 303 final TaskFragmentInfo info = 304 taskFragment != null ? taskFragment.getTaskFragmentInfo() : null; 305 final Bundle errorBundle = putErrorInfoInBundle(exception, info, opType); 306 return new TaskFragmentTransaction.Change(TYPE_TASK_FRAGMENT_ERROR) 307 .setErrorCallbackToken(errorCallbackToken) 308 .setErrorBundle(errorBundle); 309 } 310 311 @Nullable prepareActivityReparentedToTask( @onNull ActivityRecord activity)312 TaskFragmentTransaction.Change prepareActivityReparentedToTask( 313 @NonNull ActivityRecord activity) { 314 if (activity.finishing) { 315 Slog.d(TAG, "Reparent activity=" + activity.token + " is finishing"); 316 return null; 317 } 318 final Task task = activity.getTask(); 319 if (task == null || task.effectiveUid != mOrganizerUid) { 320 Slog.d(TAG, "Reparent activity=" + activity.token 321 + " is not in a task belong to the organizer app."); 322 return null; 323 } 324 if (task.isAllowedToEmbedActivity(activity, mOrganizerUid) != EMBEDDING_ALLOWED 325 || !task.isAllowedToEmbedActivityInTrustedMode(activity, mOrganizerUid)) { 326 Slog.d(TAG, "Reparent activity=" + activity.token 327 + " is not allowed to be embedded in trusted mode."); 328 return null; 329 } 330 331 final IBinder activityToken; 332 if (activity.getPid() == mOrganizerPid) { 333 // We only pass the actual token if the activity belongs to the organizer process. 334 activityToken = activity.token; 335 } else { 336 // For security, we can't pass the actual token if the activity belongs to a 337 // different process. In this case, we will pass a temporary token that organizer 338 // can use to reparent through WindowContainerTransaction. 339 activityToken = new Binder("TemporaryActivityToken"); 340 mTemporaryActivityTokens.put(activityToken, activity); 341 final Runnable timeout = () -> { 342 synchronized (mGlobalLock) { 343 mTemporaryActivityTokens.remove(activityToken); 344 } 345 }; 346 mAtmService.mWindowManager.mH.postDelayed(timeout, 347 TEMPORARY_ACTIVITY_TOKEN_TIMEOUT_MS); 348 } 349 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Activity=%s reparent to taskId=%d", 350 activity.token, task.mTaskId); 351 return new TaskFragmentTransaction.Change(TYPE_ACTIVITY_REPARENTED_TO_TASK) 352 .setTaskId(task.mTaskId) 353 .setActivityIntent(trimIntent(activity.intent)) 354 .setActivityToken(activityToken); 355 } 356 dispatchTransaction(@onNull TaskFragmentTransaction transaction)357 void dispatchTransaction(@NonNull TaskFragmentTransaction transaction) { 358 if (transaction.isEmpty()) { 359 return; 360 } 361 try { 362 mOrganizer.onTransactionReady(transaction); 363 } catch (RemoteException e) { 364 Slog.d(TAG, "Exception sending TaskFragmentTransaction", e); 365 return; 366 } 367 onTransactionStarted(transaction.getTransactionToken()); 368 } 369 370 /** Called when the transaction is sent to the organizer. */ onTransactionStarted(@onNull IBinder transactionToken)371 void onTransactionStarted(@NonNull IBinder transactionToken) { 372 if (!mWindowOrganizerController.getTransitionController().isCollecting()) { 373 return; 374 } 375 final int transitionId = mWindowOrganizerController.getTransitionController() 376 .getCollectingTransitionId(); 377 ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, 378 "Defer transition id=%d for TaskFragmentTransaction=%s", transitionId, 379 transactionToken); 380 mDeferredTransitions.put(transactionToken, transitionId); 381 mWindowOrganizerController.getTransitionController().deferTransitionReady(); 382 } 383 384 /** Called when the transaction is finished. */ onTransactionFinished(@onNull IBinder transactionToken)385 void onTransactionFinished(@NonNull IBinder transactionToken) { 386 if (!mDeferredTransitions.containsKey(transactionToken)) { 387 return; 388 } 389 final int transitionId = mDeferredTransitions.remove(transactionToken); 390 if (!mWindowOrganizerController.getTransitionController().isCollecting() 391 || mWindowOrganizerController.getTransitionController() 392 .getCollectingTransitionId() != transitionId) { 393 // This can happen when the transition is timeout or abort. 394 ProtoLog.w(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, 395 "Deferred transition id=%d has been continued before the" 396 + " TaskFragmentTransaction=%s is finished", 397 transitionId, transactionToken); 398 return; 399 } 400 ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, 401 "Continue transition id=%d for TaskFragmentTransaction=%s", transitionId, 402 transactionToken); 403 mWindowOrganizerController.getTransitionController().continueTransitionReady(); 404 } 405 } 406 407 @Nullable getReparentActivityFromTemporaryToken( @ullable ITaskFragmentOrganizer organizer, @Nullable IBinder activityToken)408 ActivityRecord getReparentActivityFromTemporaryToken( 409 @Nullable ITaskFragmentOrganizer organizer, @Nullable IBinder activityToken) { 410 if (organizer == null || activityToken == null) { 411 return null; 412 } 413 final TaskFragmentOrganizerState state = mTaskFragmentOrganizerState.get( 414 organizer.asBinder()); 415 return state != null 416 ? state.mTemporaryActivityTokens.remove(activityToken) 417 : null; 418 } 419 420 @Override registerOrganizer(@onNull ITaskFragmentOrganizer organizer)421 public void registerOrganizer(@NonNull ITaskFragmentOrganizer organizer) { 422 final int pid = Binder.getCallingPid(); 423 final int uid = Binder.getCallingUid(); 424 synchronized (mGlobalLock) { 425 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, 426 "Register task fragment organizer=%s uid=%d pid=%d", 427 organizer.asBinder(), uid, pid); 428 if (isOrganizerRegistered(organizer)) { 429 throw new IllegalStateException( 430 "Replacing existing organizer currently unsupported"); 431 } 432 mTaskFragmentOrganizerState.put(organizer.asBinder(), 433 new TaskFragmentOrganizerState(organizer, pid, uid)); 434 mPendingTaskFragmentEvents.put(organizer.asBinder(), new ArrayList<>()); 435 } 436 } 437 438 @Override unregisterOrganizer(@onNull ITaskFragmentOrganizer organizer)439 public void unregisterOrganizer(@NonNull ITaskFragmentOrganizer organizer) { 440 final int pid = Binder.getCallingPid(); 441 final long uid = Binder.getCallingUid(); 442 final long origId = Binder.clearCallingIdentity(); 443 try { 444 synchronized (mGlobalLock) { 445 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, 446 "Unregister task fragment organizer=%s uid=%d pid=%d", 447 organizer.asBinder(), uid, pid); 448 removeOrganizer(organizer); 449 } 450 } finally { 451 Binder.restoreCallingIdentity(origId); 452 } 453 } 454 455 @Override registerRemoteAnimations(@onNull ITaskFragmentOrganizer organizer, @NonNull RemoteAnimationDefinition definition)456 public void registerRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer, 457 @NonNull RemoteAnimationDefinition definition) { 458 final int pid = Binder.getCallingPid(); 459 final int uid = Binder.getCallingUid(); 460 synchronized (mGlobalLock) { 461 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, 462 "Register remote animations for organizer=%s uid=%d pid=%d", 463 organizer.asBinder(), uid, pid); 464 final TaskFragmentOrganizerState organizerState = 465 mTaskFragmentOrganizerState.get(organizer.asBinder()); 466 if (organizerState == null) { 467 throw new IllegalStateException("The organizer hasn't been registered."); 468 } 469 if (organizerState.mRemoteAnimationDefinition != null) { 470 throw new IllegalStateException( 471 "The organizer has already registered remote animations=" 472 + organizerState.mRemoteAnimationDefinition); 473 } 474 475 definition.setCallingPidUid(pid, uid); 476 organizerState.mRemoteAnimationDefinition = definition; 477 } 478 } 479 480 @Override unregisterRemoteAnimations(@onNull ITaskFragmentOrganizer organizer)481 public void unregisterRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer) { 482 final int pid = Binder.getCallingPid(); 483 final long uid = Binder.getCallingUid(); 484 synchronized (mGlobalLock) { 485 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, 486 "Unregister remote animations for organizer=%s uid=%d pid=%d", 487 organizer.asBinder(), uid, pid); 488 final TaskFragmentOrganizerState organizerState = 489 mTaskFragmentOrganizerState.get(organizer.asBinder()); 490 if (organizerState == null) { 491 Slog.e(TAG, "The organizer hasn't been registered."); 492 return; 493 } 494 495 organizerState.mRemoteAnimationDefinition = null; 496 } 497 } 498 499 @Override onTransactionHandled(@onNull IBinder transactionToken, @NonNull WindowContainerTransaction wct, @WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently)500 public void onTransactionHandled(@NonNull IBinder transactionToken, 501 @NonNull WindowContainerTransaction wct, 502 @WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) { 503 // Keep the calling identity to avoid unsecure change. 504 synchronized (mGlobalLock) { 505 if (isValidTransaction(wct)) { 506 applyTransaction(wct, transitionType, shouldApplyIndependently); 507 } 508 // Even if the transaction is empty, we still need to invoke #onTransactionFinished 509 // unless the organizer has been unregistered. 510 final ITaskFragmentOrganizer organizer = wct.getTaskFragmentOrganizer(); 511 final TaskFragmentOrganizerState state = organizer != null 512 ? mTaskFragmentOrganizerState.get(organizer.asBinder()) 513 : null; 514 if (state != null) { 515 state.onTransactionFinished(transactionToken); 516 } 517 } 518 } 519 520 @Override applyTransaction(@onNull WindowContainerTransaction wct, @WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently)521 public void applyTransaction(@NonNull WindowContainerTransaction wct, 522 @WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) { 523 // Keep the calling identity to avoid unsecure change. 524 synchronized (mGlobalLock) { 525 if (!isValidTransaction(wct)) { 526 return; 527 } 528 mWindowOrganizerController.applyTaskFragmentTransactionLocked(wct, transitionType, 529 shouldApplyIndependently); 530 } 531 } 532 533 /** 534 * Gets the {@link RemoteAnimationDefinition} set on the given organizer if exists. Returns 535 * {@code null} if it doesn't. 536 */ 537 @Nullable getRemoteAnimationDefinition( @onNull ITaskFragmentOrganizer organizer)538 public RemoteAnimationDefinition getRemoteAnimationDefinition( 539 @NonNull ITaskFragmentOrganizer organizer) { 540 synchronized (mGlobalLock) { 541 final TaskFragmentOrganizerState organizerState = 542 mTaskFragmentOrganizerState.get(organizer.asBinder()); 543 if (organizerState == null) { 544 Slog.e(TAG, "TaskFragmentOrganizer has been unregistered or died when trying" 545 + " to play animation on its organized windows."); 546 return null; 547 } 548 return organizerState.mRemoteAnimationDefinition; 549 } 550 } 551 getTaskFragmentOrganizerUid(@onNull ITaskFragmentOrganizer organizer)552 int getTaskFragmentOrganizerUid(@NonNull ITaskFragmentOrganizer organizer) { 553 final TaskFragmentOrganizerState state = validateAndGetState(organizer); 554 return state.mOrganizerUid; 555 } 556 onTaskFragmentAppeared(@onNull ITaskFragmentOrganizer organizer, @NonNull TaskFragment taskFragment)557 void onTaskFragmentAppeared(@NonNull ITaskFragmentOrganizer organizer, 558 @NonNull TaskFragment taskFragment) { 559 if (taskFragment.mTaskFragmentVanishedSent) { 560 return; 561 } 562 if (taskFragment.getTask() == null) { 563 Slog.w(TAG, "onTaskFragmentAppeared failed because it is not attached tf=" 564 + taskFragment); 565 return; 566 } 567 final TaskFragmentOrganizerState state = validateAndGetState(organizer); 568 if (!state.addTaskFragment(taskFragment)) { 569 return; 570 } 571 PendingTaskFragmentEvent pendingEvent = getPendingTaskFragmentEvent(taskFragment, 572 PendingTaskFragmentEvent.EVENT_APPEARED); 573 if (pendingEvent == null) { 574 addPendingEvent(new PendingTaskFragmentEvent.Builder( 575 PendingTaskFragmentEvent.EVENT_APPEARED, organizer) 576 .setTaskFragment(taskFragment) 577 .build()); 578 } 579 } 580 onTaskFragmentInfoChanged(@onNull ITaskFragmentOrganizer organizer, @NonNull TaskFragment taskFragment)581 void onTaskFragmentInfoChanged(@NonNull ITaskFragmentOrganizer organizer, 582 @NonNull TaskFragment taskFragment) { 583 if (taskFragment.mTaskFragmentVanishedSent) { 584 return; 585 } 586 validateAndGetState(organizer); 587 if (!taskFragment.mTaskFragmentAppearedSent) { 588 // Skip if TaskFragment still not appeared. 589 return; 590 } 591 PendingTaskFragmentEvent pendingEvent = getLastPendingLifecycleEvent(taskFragment); 592 if (pendingEvent == null) { 593 pendingEvent = new PendingTaskFragmentEvent.Builder( 594 PendingTaskFragmentEvent.EVENT_INFO_CHANGED, organizer) 595 .setTaskFragment(taskFragment) 596 .build(); 597 } else { 598 // Remove and add for re-ordering. 599 removePendingEvent(pendingEvent); 600 // Reset the defer time when TaskFragment is changed, so that it can check again if 601 // the event should be sent to the organizer, for example the TaskFragment may become 602 // empty. 603 pendingEvent.mDeferTime = 0; 604 } 605 addPendingEvent(pendingEvent); 606 } 607 onTaskFragmentVanished(@onNull ITaskFragmentOrganizer organizer, @NonNull TaskFragment taskFragment)608 void onTaskFragmentVanished(@NonNull ITaskFragmentOrganizer organizer, 609 @NonNull TaskFragment taskFragment) { 610 if (taskFragment.mTaskFragmentVanishedSent) { 611 return; 612 } 613 taskFragment.mTaskFragmentVanishedSent = true; 614 final TaskFragmentOrganizerState state = validateAndGetState(organizer); 615 final List<PendingTaskFragmentEvent> pendingEvents = mPendingTaskFragmentEvents 616 .get(organizer.asBinder()); 617 // Remove any pending events since this TaskFragment is being removed. 618 for (int i = pendingEvents.size() - 1; i >= 0; i--) { 619 final PendingTaskFragmentEvent event = pendingEvents.get(i); 620 if (taskFragment == event.mTaskFragment) { 621 pendingEvents.remove(i); 622 } 623 } 624 addPendingEvent(new PendingTaskFragmentEvent.Builder( 625 PendingTaskFragmentEvent.EVENT_VANISHED, organizer) 626 .setTaskFragment(taskFragment) 627 .build()); 628 state.removeTaskFragment(taskFragment); 629 // Make sure the vanished event will be dispatched if there are no other changes. 630 mAtmService.mWindowManager.mWindowPlacerLocked.requestTraversal(); 631 } 632 onTaskFragmentError(@onNull ITaskFragmentOrganizer organizer, @Nullable IBinder errorCallbackToken, @Nullable TaskFragment taskFragment, int opType, @NonNull Throwable exception)633 void onTaskFragmentError(@NonNull ITaskFragmentOrganizer organizer, 634 @Nullable IBinder errorCallbackToken, @Nullable TaskFragment taskFragment, 635 int opType, @NonNull Throwable exception) { 636 if (taskFragment != null && taskFragment.mTaskFragmentVanishedSent) { 637 return; 638 } 639 validateAndGetState(organizer); 640 Slog.w(TAG, "onTaskFragmentError ", exception); 641 addPendingEvent(new PendingTaskFragmentEvent.Builder( 642 PendingTaskFragmentEvent.EVENT_ERROR, organizer) 643 .setErrorCallbackToken(errorCallbackToken) 644 .setTaskFragment(taskFragment) 645 .setException(exception) 646 .setOpType(opType) 647 .build()); 648 // Make sure the error event will be dispatched if there are no other changes. 649 mAtmService.mWindowManager.mWindowPlacerLocked.requestTraversal(); 650 } 651 onActivityReparentedToTask(@onNull ActivityRecord activity)652 void onActivityReparentedToTask(@NonNull ActivityRecord activity) { 653 final ITaskFragmentOrganizer organizer; 654 if (activity.mLastTaskFragmentOrganizerBeforePip != null) { 655 // If the activity is previously embedded in an organized TaskFragment. 656 organizer = activity.mLastTaskFragmentOrganizerBeforePip; 657 } else { 658 // Find the topmost TaskFragmentOrganizer. 659 final Task task = activity.getTask(); 660 final TaskFragment[] organizedTf = new TaskFragment[1]; 661 task.forAllLeafTaskFragments(tf -> { 662 if (tf.isOrganizedTaskFragment()) { 663 organizedTf[0] = tf; 664 return true; 665 } 666 return false; 667 }); 668 if (organizedTf[0] == null) { 669 return; 670 } 671 organizer = organizedTf[0].getTaskFragmentOrganizer(); 672 } 673 if (!isOrganizerRegistered(organizer)) { 674 Slog.w(TAG, "The last TaskFragmentOrganizer no longer exists"); 675 return; 676 } 677 addPendingEvent(new PendingTaskFragmentEvent.Builder( 678 PendingTaskFragmentEvent.EVENT_ACTIVITY_REPARENTED_TO_TASK, organizer) 679 .setActivity(activity) 680 .build()); 681 } 682 onTaskFragmentParentInfoChanged(@onNull ITaskFragmentOrganizer organizer, @NonNull Task task)683 void onTaskFragmentParentInfoChanged(@NonNull ITaskFragmentOrganizer organizer, 684 @NonNull Task task) { 685 validateAndGetState(organizer); 686 final PendingTaskFragmentEvent pendingEvent = getLastPendingParentInfoChangedEvent( 687 organizer, task); 688 if (pendingEvent == null) { 689 addPendingEvent(new PendingTaskFragmentEvent.Builder( 690 PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED, organizer) 691 .setTask(task) 692 .build()); 693 } 694 } 695 696 @Nullable getLastPendingParentInfoChangedEvent( @onNull ITaskFragmentOrganizer organizer, @NonNull Task task)697 private PendingTaskFragmentEvent getLastPendingParentInfoChangedEvent( 698 @NonNull ITaskFragmentOrganizer organizer, @NonNull Task task) { 699 final List<PendingTaskFragmentEvent> events = mPendingTaskFragmentEvents 700 .get(organizer.asBinder()); 701 for (int i = events.size() - 1; i >= 0; i--) { 702 final PendingTaskFragmentEvent event = events.get(i); 703 if (task == event.mTask 704 && event.mEventType == PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED) { 705 return event; 706 } 707 } 708 return null; 709 } 710 addPendingEvent(@onNull PendingTaskFragmentEvent event)711 private void addPendingEvent(@NonNull PendingTaskFragmentEvent event) { 712 mPendingTaskFragmentEvents.get(event.mTaskFragmentOrg.asBinder()).add(event); 713 } 714 removePendingEvent(@onNull PendingTaskFragmentEvent event)715 private void removePendingEvent(@NonNull PendingTaskFragmentEvent event) { 716 mPendingTaskFragmentEvents.get(event.mTaskFragmentOrg.asBinder()).remove(event); 717 } 718 isOrganizerRegistered(@onNull ITaskFragmentOrganizer organizer)719 private boolean isOrganizerRegistered(@NonNull ITaskFragmentOrganizer organizer) { 720 return mTaskFragmentOrganizerState.containsKey(organizer.asBinder()); 721 } 722 removeOrganizer(@onNull ITaskFragmentOrganizer organizer)723 private void removeOrganizer(@NonNull ITaskFragmentOrganizer organizer) { 724 final TaskFragmentOrganizerState state = mTaskFragmentOrganizerState.get( 725 organizer.asBinder()); 726 if (state == null) { 727 Slog.w(TAG, "The organizer has already been removed."); 728 return; 729 } 730 // Remove any pending event of this organizer first because state.dispose() may trigger 731 // event dispatch as result of surface placement. 732 mPendingTaskFragmentEvents.remove(organizer.asBinder()); 733 // remove all of the children of the organized TaskFragment 734 state.dispose(); 735 mTaskFragmentOrganizerState.remove(organizer.asBinder()); 736 } 737 738 /** 739 * Makes sure that the organizer has been correctly registered to prevent any Sidecar 740 * implementation from organizing {@link TaskFragment} without registering first. In such case, 741 * we wouldn't register {@link DeathRecipient} for the organizer, and might not remove the 742 * {@link TaskFragment} after the organizer process died. 743 */ 744 @NonNull validateAndGetState( @onNull ITaskFragmentOrganizer organizer)745 private TaskFragmentOrganizerState validateAndGetState( 746 @NonNull ITaskFragmentOrganizer organizer) { 747 final TaskFragmentOrganizerState state = 748 mTaskFragmentOrganizerState.get(organizer.asBinder()); 749 if (state == null) { 750 throw new IllegalArgumentException( 751 "TaskFragmentOrganizer has not been registered. Organizer=" + organizer); 752 } 753 return state; 754 } 755 isValidTransaction(@onNull WindowContainerTransaction t)756 boolean isValidTransaction(@NonNull WindowContainerTransaction t) { 757 if (t.isEmpty()) { 758 return false; 759 } 760 final ITaskFragmentOrganizer organizer = t.getTaskFragmentOrganizer(); 761 if (t.getTaskFragmentOrganizer() == null || !isOrganizerRegistered(organizer)) { 762 // Transaction from an unregistered organizer should not be applied. This can happen 763 // when the organizer process died before the transaction is applied. 764 Slog.e(TAG, "Caller organizer=" + organizer + " is no longer registered"); 765 return false; 766 } 767 return true; 768 } 769 770 /** 771 * A class to store {@link ITaskFragmentOrganizer} and its organized 772 * {@link TaskFragment TaskFragments} with different pending event request. 773 */ 774 private static class PendingTaskFragmentEvent { 775 static final int EVENT_APPEARED = 0; 776 static final int EVENT_VANISHED = 1; 777 static final int EVENT_INFO_CHANGED = 2; 778 static final int EVENT_PARENT_INFO_CHANGED = 3; 779 static final int EVENT_ERROR = 4; 780 static final int EVENT_ACTIVITY_REPARENTED_TO_TASK = 5; 781 782 @IntDef(prefix = "EVENT_", value = { 783 EVENT_APPEARED, 784 EVENT_VANISHED, 785 EVENT_INFO_CHANGED, 786 EVENT_PARENT_INFO_CHANGED, 787 EVENT_ERROR, 788 EVENT_ACTIVITY_REPARENTED_TO_TASK 789 }) 790 @Retention(RetentionPolicy.SOURCE) 791 public @interface EventType {} 792 793 @EventType 794 private final int mEventType; 795 private final ITaskFragmentOrganizer mTaskFragmentOrg; 796 @Nullable 797 private final TaskFragment mTaskFragment; 798 @Nullable 799 private final IBinder mErrorCallbackToken; 800 @Nullable 801 private final Throwable mException; 802 @Nullable 803 private final ActivityRecord mActivity; 804 @Nullable 805 private final Task mTask; 806 // Set when the event is deferred due to the host task is invisible. The defer time will 807 // be the last active time of the host task. 808 private long mDeferTime; 809 private int mOpType; 810 PendingTaskFragmentEvent(@ventType int eventType, ITaskFragmentOrganizer taskFragmentOrg, @Nullable TaskFragment taskFragment, @Nullable IBinder errorCallbackToken, @Nullable Throwable exception, @Nullable ActivityRecord activity, @Nullable Task task, int opType)811 private PendingTaskFragmentEvent(@EventType int eventType, 812 ITaskFragmentOrganizer taskFragmentOrg, 813 @Nullable TaskFragment taskFragment, 814 @Nullable IBinder errorCallbackToken, 815 @Nullable Throwable exception, 816 @Nullable ActivityRecord activity, 817 @Nullable Task task, 818 int opType) { 819 mEventType = eventType; 820 mTaskFragmentOrg = taskFragmentOrg; 821 mTaskFragment = taskFragment; 822 mErrorCallbackToken = errorCallbackToken; 823 mException = exception; 824 mActivity = activity; 825 mTask = task; 826 mOpType = opType; 827 } 828 829 /** 830 * @return {@code true} if the pending event is related with taskFragment created, vanished 831 * and information changed. 832 */ isLifecycleEvent()833 boolean isLifecycleEvent() { 834 switch (mEventType) { 835 case EVENT_APPEARED: 836 case EVENT_VANISHED: 837 case EVENT_INFO_CHANGED: 838 case EVENT_PARENT_INFO_CHANGED: 839 return true; 840 default: 841 return false; 842 } 843 } 844 845 private static class Builder { 846 @EventType 847 private final int mEventType; 848 private final ITaskFragmentOrganizer mTaskFragmentOrg; 849 @Nullable 850 private TaskFragment mTaskFragment; 851 @Nullable 852 private IBinder mErrorCallbackToken; 853 @Nullable 854 private Throwable mException; 855 @Nullable 856 private ActivityRecord mActivity; 857 @Nullable 858 private Task mTask; 859 private int mOpType; 860 Builder(@ventType int eventType, @NonNull ITaskFragmentOrganizer taskFragmentOrg)861 Builder(@EventType int eventType, @NonNull ITaskFragmentOrganizer taskFragmentOrg) { 862 mEventType = eventType; 863 mTaskFragmentOrg = requireNonNull(taskFragmentOrg); 864 } 865 setTaskFragment(@ullable TaskFragment taskFragment)866 Builder setTaskFragment(@Nullable TaskFragment taskFragment) { 867 mTaskFragment = taskFragment; 868 return this; 869 } 870 setErrorCallbackToken(@ullable IBinder errorCallbackToken)871 Builder setErrorCallbackToken(@Nullable IBinder errorCallbackToken) { 872 mErrorCallbackToken = errorCallbackToken; 873 return this; 874 } 875 setException(@onNull Throwable exception)876 Builder setException(@NonNull Throwable exception) { 877 mException = requireNonNull(exception); 878 return this; 879 } 880 setActivity(@onNull ActivityRecord activity)881 Builder setActivity(@NonNull ActivityRecord activity) { 882 mActivity = requireNonNull(activity); 883 return this; 884 } 885 setTask(@onNull Task task)886 Builder setTask(@NonNull Task task) { 887 mTask = requireNonNull(task); 888 return this; 889 } 890 setOpType(int opType)891 Builder setOpType(int opType) { 892 mOpType = opType; 893 return this; 894 } 895 build()896 PendingTaskFragmentEvent build() { 897 return new PendingTaskFragmentEvent(mEventType, mTaskFragmentOrg, mTaskFragment, 898 mErrorCallbackToken, mException, mActivity, mTask, mOpType); 899 } 900 } 901 } 902 903 @Nullable getLastPendingLifecycleEvent(@onNull TaskFragment tf)904 private PendingTaskFragmentEvent getLastPendingLifecycleEvent(@NonNull TaskFragment tf) { 905 final ITaskFragmentOrganizer organizer = tf.getTaskFragmentOrganizer(); 906 final List<PendingTaskFragmentEvent> events = mPendingTaskFragmentEvents 907 .get(organizer.asBinder()); 908 for (int i = events.size() - 1; i >= 0; i--) { 909 final PendingTaskFragmentEvent event = events.get(i); 910 if (tf == event.mTaskFragment && event.isLifecycleEvent()) { 911 return event; 912 } 913 } 914 return null; 915 } 916 917 @Nullable getPendingTaskFragmentEvent(@onNull TaskFragment taskFragment, int type)918 private PendingTaskFragmentEvent getPendingTaskFragmentEvent(@NonNull TaskFragment taskFragment, 919 int type) { 920 final ITaskFragmentOrganizer organizer = taskFragment.getTaskFragmentOrganizer(); 921 final List<PendingTaskFragmentEvent> events = mPendingTaskFragmentEvents 922 .get(organizer.asBinder()); 923 for (int i = events.size() - 1; i >= 0; i--) { 924 final PendingTaskFragmentEvent event = events.get(i); 925 if (taskFragment == event.mTaskFragment && type == event.mEventType) { 926 return event; 927 } 928 } 929 return null; 930 } 931 dispatchPendingEvents()932 void dispatchPendingEvents() { 933 if (mAtmService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred() 934 || mPendingTaskFragmentEvents.isEmpty()) { 935 return; 936 } 937 final int organizerNum = mPendingTaskFragmentEvents.size(); 938 for (int i = 0; i < organizerNum; i++) { 939 final TaskFragmentOrganizerState state = 940 mTaskFragmentOrganizerState.get(mPendingTaskFragmentEvents.keyAt(i)); 941 dispatchPendingEvents(state, mPendingTaskFragmentEvents.valueAt(i)); 942 } 943 } 944 dispatchPendingEvents(@onNull TaskFragmentOrganizerState state, @NonNull List<PendingTaskFragmentEvent> pendingEvents)945 private void dispatchPendingEvents(@NonNull TaskFragmentOrganizerState state, 946 @NonNull List<PendingTaskFragmentEvent> pendingEvents) { 947 if (pendingEvents.isEmpty()) { 948 return; 949 } 950 if (shouldDeferPendingEvents(state, pendingEvents)) { 951 return; 952 } 953 mTmpTaskSet.clear(); 954 final int numEvents = pendingEvents.size(); 955 final TaskFragmentTransaction transaction = new TaskFragmentTransaction(); 956 for (int i = 0; i < numEvents; i++) { 957 final PendingTaskFragmentEvent event = pendingEvents.get(i); 958 if (event.mEventType == PendingTaskFragmentEvent.EVENT_APPEARED 959 || event.mEventType == PendingTaskFragmentEvent.EVENT_INFO_CHANGED) { 960 final Task task = event.mTaskFragment.getTask(); 961 if (mTmpTaskSet.add(task)) { 962 // Make sure the organizer know about the Task config. 963 transaction.addChange(prepareChange(new PendingTaskFragmentEvent.Builder( 964 PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED, state.mOrganizer) 965 .setTask(task) 966 .build())); 967 } 968 } 969 transaction.addChange(prepareChange(event)); 970 } 971 mTmpTaskSet.clear(); 972 state.dispatchTransaction(transaction); 973 pendingEvents.clear(); 974 } 975 976 /** 977 * Whether or not to defer sending the events to the organizer to avoid waking the app process 978 * when it is in background. We want to either send all events or none to avoid inconsistency. 979 */ shouldDeferPendingEvents(@onNull TaskFragmentOrganizerState state, @NonNull List<PendingTaskFragmentEvent> pendingEvents)980 private boolean shouldDeferPendingEvents(@NonNull TaskFragmentOrganizerState state, 981 @NonNull List<PendingTaskFragmentEvent> pendingEvents) { 982 final ArrayList<Task> visibleTasks = new ArrayList<>(); 983 final ArrayList<Task> invisibleTasks = new ArrayList<>(); 984 for (int i = 0, n = pendingEvents.size(); i < n; i++) { 985 final PendingTaskFragmentEvent event = pendingEvents.get(i); 986 if (event.mEventType != PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED 987 && event.mEventType != PendingTaskFragmentEvent.EVENT_INFO_CHANGED 988 && event.mEventType != PendingTaskFragmentEvent.EVENT_APPEARED) { 989 // Send events for any other types. 990 return false; 991 } 992 993 // Check if we should send the event given the Task visibility and events. 994 final Task task; 995 if (event.mEventType == PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED) { 996 task = event.mTask; 997 } else { 998 task = event.mTaskFragment.getTask(); 999 } 1000 if (task.lastActiveTime > event.mDeferTime 1001 && isTaskVisible(task, visibleTasks, invisibleTasks)) { 1002 // Send events when the app has at least one visible Task. 1003 return false; 1004 } else if (shouldSendEventWhenTaskInvisible(task, state, event)) { 1005 // Sent events even if the Task is invisible. 1006 return false; 1007 } 1008 1009 // Defer sending events to the organizer until the host task is active (visible) again. 1010 event.mDeferTime = task.lastActiveTime; 1011 } 1012 // Defer for invisible Task. 1013 return true; 1014 } 1015 isTaskVisible(@onNull Task task, @NonNull ArrayList<Task> knownVisibleTasks, @NonNull ArrayList<Task> knownInvisibleTasks)1016 private static boolean isTaskVisible(@NonNull Task task, 1017 @NonNull ArrayList<Task> knownVisibleTasks, 1018 @NonNull ArrayList<Task> knownInvisibleTasks) { 1019 if (knownVisibleTasks.contains(task)) { 1020 return true; 1021 } 1022 if (knownInvisibleTasks.contains(task)) { 1023 return false; 1024 } 1025 if (task.shouldBeVisible(null /* starting */)) { 1026 knownVisibleTasks.add(task); 1027 return true; 1028 } else { 1029 knownInvisibleTasks.add(task); 1030 return false; 1031 } 1032 } 1033 shouldSendEventWhenTaskInvisible(@onNull Task task, @NonNull TaskFragmentOrganizerState state, @NonNull PendingTaskFragmentEvent event)1034 private boolean shouldSendEventWhenTaskInvisible(@NonNull Task task, 1035 @NonNull TaskFragmentOrganizerState state, 1036 @NonNull PendingTaskFragmentEvent event) { 1037 final TaskFragmentParentInfo lastParentInfo = state.mLastSentTaskFragmentParentInfos 1038 .get(task.mTaskId); 1039 if (lastParentInfo == null || lastParentInfo.isVisible()) { 1040 // When the Task was visible, or when there was no Task info changed sent (in which case 1041 // the organizer will consider it as visible by default), always send the event to 1042 // update the Task visibility. 1043 return true; 1044 } 1045 if (event.mEventType == PendingTaskFragmentEvent.EVENT_INFO_CHANGED) { 1046 // Send info changed if the TaskFragment is becoming empty/non-empty so the 1047 // organizer can choose whether or not to remove the TaskFragment. 1048 final TaskFragmentInfo lastInfo = state.mLastSentTaskFragmentInfos 1049 .get(event.mTaskFragment); 1050 final boolean isEmpty = event.mTaskFragment.getNonFinishingActivityCount() == 0; 1051 return lastInfo == null || lastInfo.isEmpty() != isEmpty; 1052 } 1053 return false; 1054 } 1055 dispatchPendingInfoChangedEvent(@onNull TaskFragment taskFragment)1056 void dispatchPendingInfoChangedEvent(@NonNull TaskFragment taskFragment) { 1057 final PendingTaskFragmentEvent event = getPendingTaskFragmentEvent(taskFragment, 1058 PendingTaskFragmentEvent.EVENT_INFO_CHANGED); 1059 if (event == null) { 1060 return; 1061 } 1062 1063 final ITaskFragmentOrganizer organizer = taskFragment.getTaskFragmentOrganizer(); 1064 final TaskFragmentOrganizerState state = validateAndGetState(organizer); 1065 final TaskFragmentTransaction transaction = new TaskFragmentTransaction(); 1066 // Make sure the organizer know about the Task config. 1067 transaction.addChange(prepareChange(new PendingTaskFragmentEvent.Builder( 1068 PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED, organizer) 1069 .setTask(taskFragment.getTask()) 1070 .build())); 1071 transaction.addChange(prepareChange(event)); 1072 state.dispatchTransaction(transaction); 1073 mPendingTaskFragmentEvents.get(organizer.asBinder()).remove(event); 1074 } 1075 1076 @Nullable prepareChange( @onNull PendingTaskFragmentEvent event)1077 private TaskFragmentTransaction.Change prepareChange( 1078 @NonNull PendingTaskFragmentEvent event) { 1079 final ITaskFragmentOrganizer taskFragmentOrg = event.mTaskFragmentOrg; 1080 final TaskFragment taskFragment = event.mTaskFragment; 1081 final TaskFragmentOrganizerState state = 1082 mTaskFragmentOrganizerState.get(taskFragmentOrg.asBinder()); 1083 if (state == null) { 1084 return null; 1085 } 1086 switch (event.mEventType) { 1087 case PendingTaskFragmentEvent.EVENT_APPEARED: 1088 return state.prepareTaskFragmentAppeared(taskFragment); 1089 case PendingTaskFragmentEvent.EVENT_VANISHED: 1090 return state.prepareTaskFragmentVanished(taskFragment); 1091 case PendingTaskFragmentEvent.EVENT_INFO_CHANGED: 1092 return state.prepareTaskFragmentInfoChanged(taskFragment); 1093 case PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED: 1094 return state.prepareTaskFragmentParentInfoChanged(event.mTask); 1095 case PendingTaskFragmentEvent.EVENT_ERROR: 1096 return state.prepareTaskFragmentError(event.mErrorCallbackToken, taskFragment, 1097 event.mOpType, event.mException); 1098 case PendingTaskFragmentEvent.EVENT_ACTIVITY_REPARENTED_TO_TASK: 1099 return state.prepareActivityReparentedToTask(event.mActivity); 1100 default: 1101 throw new IllegalArgumentException("Unknown TaskFragmentEvent=" + event.mEventType); 1102 } 1103 } 1104 1105 // TODO(b/204399167): change to push the embedded state to the client side 1106 @Override isActivityEmbedded(IBinder activityToken)1107 public boolean isActivityEmbedded(IBinder activityToken) { 1108 synchronized (mGlobalLock) { 1109 final ActivityRecord activity = ActivityRecord.forTokenLocked(activityToken); 1110 if (activity == null) { 1111 return false; 1112 } 1113 final TaskFragment taskFragment = activity.getOrganizedTaskFragment(); 1114 return taskFragment != null && taskFragment.isEmbeddedWithBoundsOverride(); 1115 } 1116 } 1117 1118 /** 1119 * Trims the given Intent to only those that are needed to for embedding rules. This helps to 1120 * make it safer for cross-uid embedding even if we only send the Intent for trusted embedding. 1121 */ trimIntent(@onNull Intent intent)1122 private static Intent trimIntent(@NonNull Intent intent) { 1123 return new Intent() 1124 .setComponent(intent.getComponent()) 1125 .setPackage(intent.getPackage()) 1126 .setAction(intent.getAction()); 1127 } 1128 } 1129