1 /* 2 * Copyright (C) 2020 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.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS; 20 import static android.app.Activity.FULLSCREEN_MODE_REQUEST_ENTER; 21 import static android.app.Activity.FULLSCREEN_MODE_REQUEST_EXIT; 22 import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION; 23 import static android.app.ActivityTaskManager.INVALID_TASK_ID; 24 import static android.app.ActivityTaskManager.INVALID_WINDOWING_MODE; 25 import static android.app.FullscreenRequestHandler.REMOTE_CALLBACK_RESULT_KEY; 26 import static android.app.FullscreenRequestHandler.RESULT_APPROVED; 27 import static android.app.FullscreenRequestHandler.RESULT_FAILED_NOT_IN_FULLSCREEN_WITH_HISTORY; 28 import static android.app.FullscreenRequestHandler.RESULT_FAILED_NOT_TOP_FOCUSED; 29 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 30 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 31 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 32 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 33 import static android.content.pm.PackageManager.PERMISSION_DENIED; 34 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 35 import static android.os.Process.INVALID_UID; 36 import static android.os.Process.SYSTEM_UID; 37 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; 38 import static android.service.voice.VoiceInteractionSession.SHOW_SOURCE_APPLICATION; 39 import static android.view.Display.DEFAULT_DISPLAY; 40 import static android.view.Display.INVALID_DISPLAY; 41 import static android.view.WindowManager.TRANSIT_CHANGE; 42 import static android.view.WindowManager.TRANSIT_TO_BACK; 43 import static android.view.WindowManager.TRANSIT_TO_FRONT; 44 45 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; 46 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IMMERSIVE; 47 import static com.android.server.wm.ActivityRecord.State.DESTROYED; 48 import static com.android.server.wm.ActivityRecord.State.DESTROYING; 49 import static com.android.server.wm.ActivityRecord.State.PAUSING; 50 import static com.android.server.wm.ActivityRecord.State.RESTARTING_PROCESS; 51 import static com.android.server.wm.ActivityRecord.State.RESUMED; 52 import static com.android.server.wm.ActivityRecord.State.STOPPING; 53 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL; 54 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; 55 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; 56 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; 57 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE; 58 import static com.android.server.wm.ActivityTaskManagerService.TAG_SWITCH; 59 import static com.android.server.wm.ActivityTaskManagerService.enforceNotIsolatedCaller; 60 import static com.android.window.flags.Flags.allowDisableActivityRecordInputSink; 61 62 import android.Manifest; 63 import android.annotation.ColorInt; 64 import android.annotation.NonNull; 65 import android.annotation.Nullable; 66 import android.app.Activity; 67 import android.app.ActivityManager; 68 import android.app.ActivityTaskManager; 69 import android.app.FullscreenRequestHandler; 70 import android.app.IActivityClientController; 71 import android.app.ICompatCameraControlCallback; 72 import android.app.IRequestFinishCallback; 73 import android.app.PictureInPictureParams; 74 import android.app.PictureInPictureUiState; 75 import android.app.compat.CompatChanges; 76 import android.app.servertransaction.EnterPipRequestedItem; 77 import android.app.servertransaction.PipStateTransactionItem; 78 import android.compat.annotation.ChangeId; 79 import android.content.ComponentName; 80 import android.content.Context; 81 import android.content.Intent; 82 import android.content.pm.ActivityInfo; 83 import android.content.pm.PackageManagerInternal; 84 import android.content.res.Configuration; 85 import android.net.Uri; 86 import android.os.Binder; 87 import android.os.Bundle; 88 import android.os.IBinder; 89 import android.os.IRemoteCallback; 90 import android.os.Parcel; 91 import android.os.PersistableBundle; 92 import android.os.RemoteException; 93 import android.os.SystemClock; 94 import android.os.Trace; 95 import android.os.UserHandle; 96 import android.service.voice.VoiceInteractionManagerInternal; 97 import android.util.Slog; 98 import android.view.RemoteAnimationDefinition; 99 import android.window.SizeConfigurationBuckets; 100 import android.window.TransitionInfo; 101 102 import com.android.internal.annotations.VisibleForTesting; 103 import com.android.internal.app.AssistUtils; 104 import com.android.internal.policy.IKeyguardDismissCallback; 105 import com.android.internal.protolog.common.ProtoLog; 106 import com.android.server.LocalServices; 107 import com.android.server.Watchdog; 108 import com.android.server.pm.KnownPackages; 109 import com.android.server.pm.pkg.AndroidPackage; 110 import com.android.server.uri.GrantUri; 111 import com.android.server.uri.NeededUriGrants; 112 import com.android.server.utils.quota.Categorizer; 113 import com.android.server.utils.quota.Category; 114 import com.android.server.utils.quota.CountQuotaTracker; 115 import com.android.server.vr.VrManagerInternal; 116 117 /** 118 * Server side implementation for the client activity to interact with system. 119 * 120 * @see android.app.ActivityClient 121 */ 122 class ActivityClientController extends IActivityClientController.Stub { 123 private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityClientController" : TAG_ATM; 124 125 private final ActivityTaskManagerService mService; 126 private final WindowManagerGlobalLock mGlobalLock; 127 private final ActivityTaskSupervisor mTaskSupervisor; 128 private final Context mContext; 129 130 // Prevent malicious app abusing the Activity#setPictureInPictureParams API 131 @VisibleForTesting CountQuotaTracker mSetPipAspectRatioQuotaTracker; 132 // Limit to 60 times / minute 133 private static final int SET_PIP_ASPECT_RATIO_LIMIT = 60; 134 // The timeWindowMs here can not be smaller than QuotaTracker#MIN_WINDOW_SIZE_MS 135 private static final long SET_PIP_ASPECT_RATIO_TIME_WINDOW_MS = 60_000; 136 137 /** Wrapper around VoiceInteractionServiceManager. */ 138 private AssistUtils mAssistUtils; 139 140 /** 141 * Grants access to the launching app's identity if the app opted-in to sharing its identity 142 * by launching this activity with an instance of {@link android.app.ActivityOptions} on which 143 * {@link android.app.ActivityOptions#setShareIdentityEnabled(boolean)} was invoked with a 144 * value of {@code true}, or if the launched activity's uid is the same as the launching 145 * app's. When this change is enabled and one of these requirements is met, the activity 146 * can access the launching app's uid and package name with {@link 147 * android.app.Activity#getLaunchedFromUid()} and {@link 148 * android.app.Activity#getLaunchedFromPackage()}, respectively. 149 */ 150 @ChangeId 151 public static final long ACCESS_SHARED_IDENTITY = 259743961L; 152 ActivityClientController(ActivityTaskManagerService service)153 ActivityClientController(ActivityTaskManagerService service) { 154 mService = service; 155 mGlobalLock = service.mGlobalLock; 156 mTaskSupervisor = service.mTaskSupervisor; 157 mContext = service.mContext; 158 } 159 onSystemReady()160 void onSystemReady() { 161 mAssistUtils = new AssistUtils(mContext); 162 } 163 164 @Override onTransact(int code, Parcel data, Parcel reply, int flags)165 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 166 throws RemoteException { 167 try { 168 return super.onTransact(code, data, reply, flags); 169 } catch (RuntimeException e) { 170 throw ActivityTaskManagerService.logAndRethrowRuntimeExceptionOnTransact( 171 "ActivityClientController", e); 172 } 173 } 174 175 @Override activityIdle(IBinder token, Configuration config, boolean stopProfiling)176 public void activityIdle(IBinder token, Configuration config, boolean stopProfiling) { 177 final long origId = Binder.clearCallingIdentity(); 178 try { 179 synchronized (mGlobalLock) { 180 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityIdle"); 181 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 182 if (r == null) { 183 return; 184 } 185 mTaskSupervisor.activityIdleInternal(r, false /* fromTimeout */, 186 false /* processPausingActivities */, config); 187 if (stopProfiling && r.hasProcess()) { 188 r.app.clearProfilerIfNeeded(); 189 } 190 } 191 } finally { 192 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 193 Binder.restoreCallingIdentity(origId); 194 } 195 } 196 197 @Override activityResumed(IBinder token, boolean handleSplashScreenExit)198 public void activityResumed(IBinder token, boolean handleSplashScreenExit) { 199 final long origId = Binder.clearCallingIdentity(); 200 synchronized (mGlobalLock) { 201 ActivityRecord.activityResumedLocked(token, handleSplashScreenExit); 202 } 203 Binder.restoreCallingIdentity(origId); 204 } 205 206 @Override activityRefreshed(IBinder token)207 public void activityRefreshed(IBinder token) { 208 final long origId = Binder.clearCallingIdentity(); 209 synchronized (mGlobalLock) { 210 ActivityRecord.activityRefreshedLocked(token); 211 } 212 Binder.restoreCallingIdentity(origId); 213 } 214 215 @Override activityTopResumedStateLost()216 public void activityTopResumedStateLost() { 217 final long origId = Binder.clearCallingIdentity(); 218 synchronized (mGlobalLock) { 219 mTaskSupervisor.handleTopResumedStateReleased(false /* timeout */); 220 } 221 Binder.restoreCallingIdentity(origId); 222 } 223 224 @Override activityPaused(IBinder token)225 public void activityPaused(IBinder token) { 226 final long origId = Binder.clearCallingIdentity(); 227 synchronized (mGlobalLock) { 228 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityPaused"); 229 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 230 if (r != null) { 231 r.activityPaused(false); 232 } 233 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 234 } 235 Binder.restoreCallingIdentity(origId); 236 } 237 238 @Override activityStopped(IBinder token, Bundle icicle, PersistableBundle persistentState, CharSequence description)239 public void activityStopped(IBinder token, Bundle icicle, PersistableBundle persistentState, 240 CharSequence description) { 241 if (DEBUG_ALL) Slog.v(TAG, "Activity stopped: token=" + token); 242 243 // Refuse possible leaked file descriptors. 244 if (icicle != null && icicle.hasFileDescriptors()) { 245 throw new IllegalArgumentException("File descriptors passed in Bundle"); 246 } 247 248 final long origId = Binder.clearCallingIdentity(); 249 250 String restartingName = null; 251 int restartingUid = 0; 252 final ActivityRecord r; 253 synchronized (mGlobalLock) { 254 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityStopped"); 255 r = ActivityRecord.isInRootTaskLocked(token); 256 if (r != null) { 257 if (!r.isState(STOPPING, RESTARTING_PROCESS) 258 && mTaskSupervisor.hasScheduledRestartTimeouts(r)) { 259 // Recover the restarting state which was replaced by other lifecycle changes. 260 r.setState(RESTARTING_PROCESS, "continue-restart"); 261 } 262 if (r.attachedToProcess() && r.isState(RESTARTING_PROCESS)) { 263 // The activity was requested to restart from 264 // {@link #restartActivityProcessIfVisible}. 265 restartingName = r.app.mName; 266 restartingUid = r.app.mUid; 267 } 268 r.activityStopped(icicle, persistentState, description); 269 } 270 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 271 } 272 273 if (restartingName != null) { 274 // In order to let the foreground activity can be restarted with its saved state from 275 // {@link android.app.Activity#onSaveInstanceState}, the kill operation is postponed 276 // until the activity reports stopped with the state. And the activity record will be 277 // kept because the record state is restarting, then the activity will be restarted 278 // immediately if it is still the top one. 279 mTaskSupervisor.removeRestartTimeouts(r); 280 mService.mAmInternal.killProcess(restartingName, restartingUid, 281 "restartActivityProcess"); 282 } 283 mService.mAmInternal.trimApplications(); 284 285 Binder.restoreCallingIdentity(origId); 286 } 287 288 @Override activityDestroyed(IBinder token)289 public void activityDestroyed(IBinder token) { 290 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "ACTIVITY DESTROYED: " + token); 291 final long origId = Binder.clearCallingIdentity(); 292 synchronized (mGlobalLock) { 293 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityDestroyed"); 294 try { 295 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 296 if (r != null) { 297 r.destroyed("activityDestroyed"); 298 } 299 } finally { 300 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 301 Binder.restoreCallingIdentity(origId); 302 } 303 } 304 } 305 306 @Override activityLocalRelaunch(IBinder token)307 public void activityLocalRelaunch(IBinder token) { 308 final long origId = Binder.clearCallingIdentity(); 309 synchronized (mGlobalLock) { 310 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 311 if (r != null) { 312 r.startRelaunching(); 313 } 314 } 315 Binder.restoreCallingIdentity(origId); 316 } 317 318 @Override activityRelaunched(IBinder token)319 public void activityRelaunched(IBinder token) { 320 final long origId = Binder.clearCallingIdentity(); 321 synchronized (mGlobalLock) { 322 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 323 if (r != null) { 324 r.finishRelaunching(); 325 } 326 } 327 Binder.restoreCallingIdentity(origId); 328 } 329 330 @Override reportSizeConfigurations(IBinder token, SizeConfigurationBuckets sizeConfigurations)331 public void reportSizeConfigurations(IBinder token, 332 SizeConfigurationBuckets sizeConfigurations) { 333 ProtoLog.v(WM_DEBUG_CONFIGURATION, "Report configuration: %s %s", 334 token, sizeConfigurations); 335 synchronized (mGlobalLock) { 336 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 337 if (r != null) { 338 r.setSizeConfigurations(sizeConfigurations); 339 } 340 } 341 } 342 343 /** 344 * Attempts to move a task backwards in z-order (the order of activities within the task is 345 * unchanged). 346 * 347 * There are several possible results of this call: 348 * - if the task is locked, then we will show the lock toast. 349 * - if there is a task behind the provided task, then that task is made visible and resumed as 350 * this task is moved to the back. 351 * - otherwise, if there are no other tasks in the root task: 352 * - if this task is in the pinned mode, then we remove the task completely, which will 353 * have the effect of moving the task to the top or bottom of the fullscreen root task 354 * (depending on whether it is visible). 355 * - otherwise, we simply return home and hide this task. 356 * 357 * @param token A reference to the activity we wish to move. 358 * @param nonRoot If false then this only works if the activity is the root 359 * of a task; if true it will work for any activity in a task. 360 * @return Returns true if the move completed, false if not. 361 */ 362 @Override moveActivityTaskToBack(IBinder token, boolean nonRoot)363 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) { 364 enforceNotIsolatedCaller("moveActivityTaskToBack"); 365 final long origId = Binder.clearCallingIdentity(); 366 try { 367 synchronized (mGlobalLock) { 368 final int taskId = ActivityRecord.getTaskForActivityLocked(token, !nonRoot); 369 final Task task = mService.mRootWindowContainer.anyTaskForId(taskId); 370 if (task != null) { 371 return ActivityRecord.getRootTask(token).moveTaskToBack(task); 372 } 373 } 374 } finally { 375 Binder.restoreCallingIdentity(origId); 376 } 377 return false; 378 } 379 380 @Override shouldUpRecreateTask(IBinder token, String destAffinity)381 public boolean shouldUpRecreateTask(IBinder token, String destAffinity) { 382 synchronized (mGlobalLock) { 383 final ActivityRecord srec = ActivityRecord.forTokenLocked(token); 384 if (srec != null) { 385 return srec.getRootTask().shouldUpRecreateTaskLocked(srec, destAffinity); 386 } 387 } 388 return false; 389 } 390 391 @Override navigateUpTo(IBinder token, Intent destIntent, String resolvedType, int resultCode, Intent resultData)392 public boolean navigateUpTo(IBinder token, Intent destIntent, String resolvedType, 393 int resultCode, Intent resultData) { 394 final ActivityRecord r; 395 synchronized (mGlobalLock) { 396 r = ActivityRecord.isInRootTaskLocked(token); 397 if (r == null) { 398 return false; 399 } 400 } 401 402 // Carefully collect grants without holding lock. 403 final NeededUriGrants destGrants = mService.collectGrants(destIntent, r); 404 final NeededUriGrants resultGrants = mService.collectGrants(resultData, r.resultTo); 405 406 synchronized (mGlobalLock) { 407 return r.getRootTask().navigateUpTo( 408 r, destIntent, resolvedType, destGrants, resultCode, resultData, resultGrants); 409 } 410 } 411 412 @Override releaseActivityInstance(IBinder token)413 public boolean releaseActivityInstance(IBinder token) { 414 final long origId = Binder.clearCallingIdentity(); 415 try { 416 synchronized (mGlobalLock) { 417 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 418 if (r == null || !r.isDestroyable()) { 419 return false; 420 } 421 r.destroyImmediately("app-req"); 422 return r.isState(DESTROYING, DESTROYED); 423 } 424 } finally { 425 Binder.restoreCallingIdentity(origId); 426 } 427 } 428 429 /** 430 * This is the internal entry point for handling Activity.finish(). 431 * 432 * @param token The Binder token referencing the Activity we want to finish. 433 * @param resultCode Result code, if any, from this Activity. 434 * @param resultData Result data (Intent), if any, from this Activity. 435 * @param finishTask Whether to finish the task associated with this Activity. 436 * @return Returns true if the activity successfully finished, or false if it is still running. 437 */ 438 @Override finishActivity(IBinder token, int resultCode, Intent resultData, int finishTask)439 public boolean finishActivity(IBinder token, int resultCode, Intent resultData, 440 int finishTask) { 441 // Refuse possible leaked file descriptors. 442 if (resultData != null && resultData.hasFileDescriptors()) { 443 throw new IllegalArgumentException("File descriptors passed in Intent"); 444 } 445 446 final ActivityRecord r; 447 synchronized (mGlobalLock) { 448 r = ActivityRecord.isInRootTaskLocked(token); 449 if (r == null) { 450 return true; 451 } 452 } 453 454 // Carefully collect grants without holding lock. 455 final NeededUriGrants resultGrants = mService.collectGrants(resultData, r.resultTo); 456 457 synchronized (mGlobalLock) { 458 // Check again in case activity was removed when collecting grants. 459 if (!r.isInHistory()) { 460 return true; 461 } 462 463 // Keep track of the root activity of the task before we finish it. 464 final Task tr = r.getTask(); 465 final ActivityRecord rootR = tr.getRootActivity(); 466 if (rootR == null) { 467 Slog.w(TAG, "Finishing task with all activities already finished"); 468 } 469 // Do not allow task to finish if last task in lockTask mode. Launchable priv-apps can 470 // finish. 471 if (mService.getLockTaskController().activityBlockedFromFinish(r)) { 472 return false; 473 } 474 475 // TODO: There is a dup. of this block of code in ActivityStack.navigateUpToLocked 476 // We should consolidate. 477 if (mService.mController != null) { 478 // Find the first activity that is not finishing. 479 final ActivityRecord next = 480 r.getRootTask().topRunningActivity(token, INVALID_TASK_ID); 481 if (next != null) { 482 // ask watcher if this is allowed 483 boolean resumeOK = true; 484 try { 485 resumeOK = mService.mController.activityResuming(next.packageName); 486 } catch (RemoteException e) { 487 mService.mController = null; 488 Watchdog.getInstance().setActivityController(null); 489 } 490 491 if (!resumeOK) { 492 Slog.i(TAG, "Not finishing activity because controller resumed"); 493 return false; 494 } 495 } 496 } 497 498 // Note down that the process has finished an activity and is in background activity 499 // starts grace period. 500 if (r.app != null) { 501 r.app.setLastActivityFinishTimeIfNeeded(SystemClock.uptimeMillis()); 502 } 503 504 final long origId = Binder.clearCallingIdentity(); 505 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "finishActivity"); 506 try { 507 final boolean res; 508 final boolean finishWithRootActivity = 509 finishTask == Activity.FINISH_TASK_WITH_ROOT_ACTIVITY; 510 mTaskSupervisor.getBackgroundActivityLaunchController() 511 .onActivityRequestedFinishing(r); 512 if (finishTask == Activity.FINISH_TASK_WITH_ACTIVITY 513 || (finishWithRootActivity && r == rootR)) { 514 // If requested, remove the task that is associated to this activity only if it 515 // was the root activity in the task. The result code and data is ignored 516 // because we don't support returning them across task boundaries. Also, to 517 // keep backwards compatibility we remove the task from recents when finishing 518 // task with root activity. 519 mTaskSupervisor.removeTask(tr, false /*killProcess*/, 520 finishWithRootActivity, "finish-activity", r.getUid(), r.getPid(), 521 r.info.name); 522 res = true; 523 // Explicitly dismissing the activity so reset its relaunch flag. 524 r.mRelaunchReason = RELAUNCH_REASON_NONE; 525 } else { 526 r.finishIfPossible(resultCode, resultData, resultGrants, "app-request", 527 true /* oomAdj */); 528 res = r.finishing; 529 if (!res) { 530 Slog.i(TAG, "Failed to finish by app-request"); 531 } 532 } 533 return res; 534 } finally { 535 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 536 Binder.restoreCallingIdentity(origId); 537 } 538 } 539 } 540 541 @Override finishActivityAffinity(IBinder token)542 public boolean finishActivityAffinity(IBinder token) { 543 final long origId = Binder.clearCallingIdentity(); 544 try { 545 synchronized (mGlobalLock) { 546 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 547 if (r == null) { 548 return false; 549 } 550 551 // Do not allow task to finish if last task in lockTask mode. Launchable priv-apps 552 // can finish. 553 if (mService.getLockTaskController().activityBlockedFromFinish(r)) { 554 return false; 555 } 556 557 r.getTask().forAllActivities(activity -> r.finishIfSameAffinity(activity), 558 r /* boundary */, true /* includeBoundary */, 559 true /* traverseTopToBottom */); 560 return true; 561 } 562 } finally { 563 Binder.restoreCallingIdentity(origId); 564 } 565 } 566 567 @Override finishSubActivity(IBinder token, String resultWho, int requestCode)568 public void finishSubActivity(IBinder token, String resultWho, int requestCode) { 569 final long origId = Binder.clearCallingIdentity(); 570 try { 571 synchronized (mGlobalLock) { 572 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 573 if (r == null) return; 574 575 // TODO: This should probably only loop over the task since you need to be in the 576 // same task to return results. 577 r.getRootTask().forAllActivities(activity -> { 578 activity.finishIfSubActivity(r /* parent */, resultWho, requestCode); 579 }, true /* traverseTopToBottom */); 580 581 mService.updateOomAdj(); 582 } 583 } finally { 584 Binder.restoreCallingIdentity(origId); 585 } 586 } 587 588 @Override setForceSendResultForMediaProjection(IBinder token)589 public void setForceSendResultForMediaProjection(IBinder token) { 590 // Require that this is invoked only during MediaProjection setup. 591 mService.mAmInternal.enforceCallingPermission( 592 Manifest.permission.MANAGE_MEDIA_PROJECTION, 593 "setForceSendResultForMediaProjection"); 594 595 final ActivityRecord r; 596 synchronized (mGlobalLock) { 597 r = ActivityRecord.isInRootTaskLocked(token); 598 if (r == null || !r.isInHistory()) { 599 return; 600 } 601 r.setForceSendResultForMediaProjection(); 602 } 603 } 604 605 @Override isTopOfTask(IBinder token)606 public boolean isTopOfTask(IBinder token) { 607 synchronized (mGlobalLock) { 608 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 609 return r != null && r.getTask().getTopNonFinishingActivity() == r; 610 } 611 } 612 613 @Override willActivityBeVisible(IBinder token)614 public boolean willActivityBeVisible(IBinder token) { 615 synchronized (mGlobalLock) { 616 final Task rootTask = ActivityRecord.getRootTask(token); 617 return rootTask != null && rootTask.willActivityBeVisible(token); 618 } 619 } 620 621 @Override getDisplayId(IBinder activityToken)622 public int getDisplayId(IBinder activityToken) { 623 synchronized (mGlobalLock) { 624 final Task rootTask = ActivityRecord.getRootTask(activityToken); 625 if (rootTask != null) { 626 final int displayId = rootTask.getDisplayId(); 627 return displayId != INVALID_DISPLAY ? displayId : DEFAULT_DISPLAY; 628 } 629 return DEFAULT_DISPLAY; 630 } 631 } 632 633 @Override getTaskForActivity(IBinder token, boolean onlyRoot)634 public int getTaskForActivity(IBinder token, boolean onlyRoot) { 635 synchronized (mGlobalLock) { 636 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 637 if (r == null) { 638 return INVALID_TASK_ID; 639 } 640 final Task task = r.getTask(); 641 if (onlyRoot) { 642 return task.getRootActivity() == r ? task.mTaskId : INVALID_TASK_ID; 643 } 644 return task.mTaskId; 645 } 646 } 647 648 /** 649 * Returns the {@link Configuration} of the task which hosts the Activity, or {@code null} if 650 * the task {@link Configuration} cannot be obtained. 651 */ 652 @Override 653 @Nullable getTaskConfiguration(IBinder activityToken)654 public Configuration getTaskConfiguration(IBinder activityToken) { 655 synchronized (mGlobalLock) { 656 final ActivityRecord ar = ActivityRecord.isInAnyTask(activityToken); 657 if (ar == null) { 658 return null; 659 } 660 return ar.getTask().getConfiguration(); 661 } 662 } 663 664 @Override 665 @Nullable getActivityTokenBelow(IBinder activityToken)666 public IBinder getActivityTokenBelow(IBinder activityToken) { 667 final long ident = Binder.clearCallingIdentity(); 668 try { 669 synchronized (mGlobalLock) { 670 final ActivityRecord ar = ActivityRecord.isInAnyTask(activityToken); 671 if (ar == null) { 672 return null; 673 } 674 // Exclude finishing activity. 675 final ActivityRecord below = ar.getTask().getActivity((r) -> !r.finishing, 676 ar, false /*includeBoundary*/, true /*traverseTopToBottom*/); 677 if (below != null && below.getUid() == ar.getUid()) { 678 return below.token; 679 } 680 } 681 } finally { 682 Binder.restoreCallingIdentity(ident); 683 } 684 return null; 685 } 686 687 @Override getCallingActivity(IBinder token)688 public ComponentName getCallingActivity(IBinder token) { 689 synchronized (mGlobalLock) { 690 final ActivityRecord r = getCallingRecord(token); 691 return r != null ? r.intent.getComponent() : null; 692 } 693 } 694 695 @Override getCallingPackage(IBinder token)696 public String getCallingPackage(IBinder token) { 697 synchronized (mGlobalLock) { 698 final ActivityRecord r = getCallingRecord(token); 699 return r != null ? r.info.packageName : null; 700 } 701 } 702 getCallingRecord(IBinder token)703 private static ActivityRecord getCallingRecord(IBinder token) { 704 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 705 return r != null ? r.resultTo : null; 706 } 707 708 @Override getLaunchedFromUid(IBinder token)709 public int getLaunchedFromUid(IBinder token) { 710 return getUid(token, /* callerToken */ null, /* isActivityCallerCall */ false); 711 } 712 713 @Override getLaunchedFromPackage(IBinder token)714 public String getLaunchedFromPackage(IBinder token) { 715 return getPackage(token, /* callerToken */ null, /* isActivityCallerCall */ false); 716 } 717 718 @Override getActivityCallerUid(IBinder activityToken, IBinder callerToken)719 public int getActivityCallerUid(IBinder activityToken, IBinder callerToken) { 720 return getUid(activityToken, callerToken, /* isActivityCallerCall */ true); 721 } 722 723 @Override getActivityCallerPackage(IBinder activityToken, IBinder callerToken)724 public String getActivityCallerPackage(IBinder activityToken, IBinder callerToken) { 725 return getPackage(activityToken, callerToken, /* isActivityCallerCall */ true); 726 } 727 getUid(IBinder activityToken, IBinder callerToken, boolean isActivityCallerCall)728 private int getUid(IBinder activityToken, IBinder callerToken, boolean isActivityCallerCall) { 729 final int uid = Binder.getCallingUid(); 730 final boolean isInternalCaller = isInternalCallerGetLaunchedFrom(uid); 731 synchronized (mGlobalLock) { 732 final ActivityRecord r = ActivityRecord.forTokenLocked(activityToken); 733 if (r != null && (isInternalCaller || canGetLaunchedFromLocked(uid, r, callerToken, 734 isActivityCallerCall)) && isValidCaller(r, callerToken, isActivityCallerCall)) { 735 return isActivityCallerCall ? r.getCallerUid(callerToken) : r.launchedFromUid; 736 } 737 } 738 return INVALID_UID; 739 } 740 getPackage(IBinder activityToken, IBinder callerToken, boolean isActivityCallerCall)741 private String getPackage(IBinder activityToken, IBinder callerToken, 742 boolean isActivityCallerCall) { 743 final int uid = Binder.getCallingUid(); 744 final boolean isInternalCaller = isInternalCallerGetLaunchedFrom(uid); 745 synchronized (mGlobalLock) { 746 final ActivityRecord r = ActivityRecord.forTokenLocked(activityToken); 747 if (r != null && (isInternalCaller || canGetLaunchedFromLocked(uid, r, callerToken, 748 isActivityCallerCall)) && isValidCaller(r, callerToken, isActivityCallerCall)) { 749 return isActivityCallerCall 750 ? r.getCallerPackage(callerToken) : r.launchedFromPackage; 751 } 752 } 753 return null; 754 } 755 isValidCaller(ActivityRecord r, IBinder callerToken, boolean isActivityCallerCall)756 private boolean isValidCaller(ActivityRecord r, IBinder callerToken, 757 boolean isActivityCallerCall) { 758 return isActivityCallerCall ? r.hasCaller(callerToken) : callerToken == null; 759 } 760 761 /** 762 * @param uri This uri must NOT contain an embedded userId. 763 * @param userId The userId in which the uri is to be resolved. 764 */ 765 @Override checkActivityCallerContentUriPermission(IBinder activityToken, IBinder callerToken, Uri uri, int modeFlags, int userId)766 public int checkActivityCallerContentUriPermission(IBinder activityToken, IBinder callerToken, 767 Uri uri, int modeFlags, int userId) { 768 // 1. Check if we have access to the URI - > throw if we don't 769 GrantUri grantUri = new GrantUri(userId, uri, modeFlags); 770 if (!mService.mUgmInternal.checkUriPermission(grantUri, Binder.getCallingUid(), modeFlags, 771 /* isFullAccessForContentUri */ true)) { 772 throw new SecurityException("You don't have access to the content URI, hence can't" 773 + " check if the caller has access to it: " + uri); 774 } 775 776 // 2. Get the permission result for the caller 777 synchronized (mGlobalLock) { 778 final ActivityRecord r = ActivityRecord.forTokenLocked(activityToken); 779 if (r != null) { 780 boolean granted = r.checkContentUriPermission(callerToken, grantUri, modeFlags); 781 return granted ? PERMISSION_GRANTED : PERMISSION_DENIED; 782 } 783 } 784 return PERMISSION_DENIED; 785 } 786 787 /** Whether the call to one of the getLaunchedFrom APIs is performed by an internal caller. */ isInternalCallerGetLaunchedFrom(int uid)788 private boolean isInternalCallerGetLaunchedFrom(int uid) { 789 if (UserHandle.getAppId(uid) == SYSTEM_UID) { 790 return true; 791 } 792 final PackageManagerInternal pm = mService.mWindowManager.mPmInternal; 793 final AndroidPackage callingPkg = pm.getPackage(uid); 794 if (callingPkg == null) { 795 return false; 796 } 797 if (callingPkg.isSignedWithPlatformKey()) { 798 return true; 799 } 800 final String[] installerNames = pm.getKnownPackageNames( 801 KnownPackages.PACKAGE_INSTALLER, UserHandle.getUserId(uid)); 802 return installerNames.length > 0 && callingPkg.getPackageName().equals(installerNames[0]); 803 } 804 805 /** 806 * Returns whether the specified {@code uid} can access the launching app's identity by 807 * verifying whether the provided {@code ActivityRecord r} has opted in to sharing its 808 * identity or if the uid of the activity matches that of the launching app. 809 */ canGetLaunchedFromLocked(int uid, ActivityRecord r, IBinder callerToken, boolean isActivityCallerCall)810 private static boolean canGetLaunchedFromLocked(int uid, ActivityRecord r, 811 IBinder callerToken, boolean isActivityCallerCall) { 812 if (CompatChanges.isChangeEnabled(ACCESS_SHARED_IDENTITY, uid)) { 813 boolean isShareIdentityEnabled = isActivityCallerCall 814 ? r.isCallerShareIdentityEnabled(callerToken) : r.mShareIdentity; 815 int callerUid = isActivityCallerCall ? r.getCallerUid(callerToken) : r.launchedFromUid; 816 return isShareIdentityEnabled || callerUid == uid; 817 } 818 return false; 819 } 820 821 @Override setRequestedOrientation(IBinder token, int requestedOrientation)822 public void setRequestedOrientation(IBinder token, int requestedOrientation) { 823 final long origId = Binder.clearCallingIdentity(); 824 try { 825 synchronized (mGlobalLock) { 826 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 827 if (r != null) { 828 EventLogTags.writeWmSetRequestedOrientation(requestedOrientation, 829 r.shortComponentName); 830 r.setRequestedOrientation(requestedOrientation); 831 } 832 } 833 } finally { 834 Binder.restoreCallingIdentity(origId); 835 } 836 } 837 838 @Override getRequestedOrientation(IBinder token)839 public int getRequestedOrientation(IBinder token) { 840 synchronized (mGlobalLock) { 841 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 842 return r != null 843 ? r.getOverrideOrientation() 844 : ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 845 } 846 } 847 848 @Override convertFromTranslucent(IBinder token)849 public boolean convertFromTranslucent(IBinder token) { 850 final long origId = Binder.clearCallingIdentity(); 851 try { 852 synchronized (mGlobalLock) { 853 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 854 if (r == null) { 855 return false; 856 } 857 // Create a transition if the activity is playing in case the below activity didn't 858 // commit invisible. That's because if any activity below this one has changed its 859 // visibility while playing transition, there won't able to commit visibility until 860 // the running transition finish. 861 final Transition transition = r.mTransitionController.isShellTransitionsEnabled() 862 && !r.mTransitionController.isCollecting() 863 ? r.mTransitionController.createTransition(TRANSIT_TO_BACK) : null; 864 final boolean changed = r.setOccludesParent(true); 865 if (transition != null) { 866 if (changed) { 867 // Always set as scene transition because it expects to be a jump-cut. 868 transition.setOverrideAnimation(TransitionInfo.AnimationOptions 869 .makeSceneTransitionAnimOptions(), null, null); 870 r.mTransitionController.requestStartTransition(transition, 871 null /*startTask */, null /* remoteTransition */, 872 null /* displayChange */); 873 r.mTransitionController.setReady(r.getDisplayContent()); 874 } else { 875 transition.abort(); 876 } 877 } 878 return changed; 879 } 880 } finally { 881 Binder.restoreCallingIdentity(origId); 882 } 883 } 884 885 @Override convertToTranslucent(IBinder token, Bundle options)886 public boolean convertToTranslucent(IBinder token, Bundle options) { 887 final SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(options); 888 final long origId = Binder.clearCallingIdentity(); 889 try { 890 synchronized (mGlobalLock) { 891 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 892 if (r == null) { 893 return false; 894 } 895 final ActivityRecord under = r.getTask().getActivityBelow(r); 896 if (under != null) { 897 under.returningOptions = safeOptions != null ? safeOptions.getOptions(r) : null; 898 } 899 // Create a transition to make sure the activity change is collected. 900 final Transition transition = r.mTransitionController.isShellTransitionsEnabled() 901 && !r.mTransitionController.isCollecting() 902 ? r.mTransitionController.createTransition(TRANSIT_TO_FRONT) : null; 903 final boolean changed = r.setOccludesParent(false); 904 if (transition != null) { 905 if (changed) { 906 r.mTransitionController.requestStartTransition(transition, 907 null /*startTask */, null /* remoteTransition */, 908 null /* displayChange */); 909 r.mTransitionController.setReady(r.getDisplayContent()); 910 if (under != null && under.returningOptions != null 911 && under.returningOptions.getAnimationType() 912 == ANIM_SCENE_TRANSITION) { 913 // Pass along the scene-transition animation-type 914 transition.setOverrideAnimation(TransitionInfo.AnimationOptions 915 .makeSceneTransitionAnimOptions(), null, null); 916 } 917 } else { 918 transition.abort(); 919 } 920 } 921 return changed; 922 } 923 } finally { 924 Binder.restoreCallingIdentity(origId); 925 } 926 } 927 928 @Override isImmersive(IBinder token)929 public boolean isImmersive(IBinder token) { 930 synchronized (mGlobalLock) { 931 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 932 if (r == null) { 933 throw new IllegalArgumentException(); 934 } 935 return r.immersive; 936 } 937 } 938 939 @Override setImmersive(IBinder token, boolean immersive)940 public void setImmersive(IBinder token, boolean immersive) { 941 synchronized (mGlobalLock) { 942 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 943 if (r == null) { 944 throw new IllegalArgumentException(); 945 } 946 r.immersive = immersive; 947 948 // Update associated state if we're frontmost. 949 if (r.isFocusedActivityOnDisplay()) { 950 ProtoLog.d(WM_DEBUG_IMMERSIVE, "Frontmost changed immersion: %s", r); 951 mService.applyUpdateLockStateLocked(r); 952 } 953 } 954 } 955 956 @Override enterPictureInPictureMode(IBinder token, final PictureInPictureParams params)957 public boolean enterPictureInPictureMode(IBinder token, final PictureInPictureParams params) { 958 final long origId = Binder.clearCallingIdentity(); 959 try { 960 ensureSetPipAspectRatioQuotaTracker(); 961 synchronized (mGlobalLock) { 962 final ActivityRecord r = ensureValidPictureInPictureActivityParams( 963 "enterPictureInPictureMode", token, params); 964 return mService.enterPictureInPictureMode(r, params, true /* fromClient */); 965 } 966 } finally { 967 Binder.restoreCallingIdentity(origId); 968 } 969 } 970 971 @Override setPictureInPictureParams(IBinder token, final PictureInPictureParams params)972 public void setPictureInPictureParams(IBinder token, final PictureInPictureParams params) { 973 final long origId = Binder.clearCallingIdentity(); 974 try { 975 ensureSetPipAspectRatioQuotaTracker(); 976 synchronized (mGlobalLock) { 977 final ActivityRecord r = ensureValidPictureInPictureActivityParams( 978 "setPictureInPictureParams", token, params); 979 r.setPictureInPictureParams(params); 980 } 981 } finally { 982 Binder.restoreCallingIdentity(origId); 983 } 984 } 985 986 @Override setShouldDockBigOverlays(IBinder token, boolean shouldDockBigOverlays)987 public void setShouldDockBigOverlays(IBinder token, boolean shouldDockBigOverlays) { 988 final long origId = Binder.clearCallingIdentity(); 989 try { 990 synchronized (mGlobalLock) { 991 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 992 r.setShouldDockBigOverlays(shouldDockBigOverlays); 993 } 994 } finally { 995 Binder.restoreCallingIdentity(origId); 996 } 997 } 998 999 /** 1000 * Splash screen view is attached to activity. 1001 */ 1002 @Override splashScreenAttached(IBinder token)1003 public void splashScreenAttached(IBinder token) { 1004 final long origId = Binder.clearCallingIdentity(); 1005 synchronized (mGlobalLock) { 1006 ActivityRecord.splashScreenAttachedLocked(token); 1007 } 1008 Binder.restoreCallingIdentity(origId); 1009 } 1010 1011 @Override requestCompatCameraControl(IBinder token, boolean showControl, boolean transformationApplied, ICompatCameraControlCallback callback)1012 public void requestCompatCameraControl(IBinder token, boolean showControl, 1013 boolean transformationApplied, ICompatCameraControlCallback callback) { 1014 final long origId = Binder.clearCallingIdentity(); 1015 try { 1016 synchronized (mGlobalLock) { 1017 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1018 if (r != null) { 1019 r.updateCameraCompatState(showControl, transformationApplied, callback); 1020 } 1021 } 1022 } finally { 1023 Binder.restoreCallingIdentity(origId); 1024 } 1025 } 1026 1027 /** 1028 * Initialize the {@link #mSetPipAspectRatioQuotaTracker} if applicable, which should happen 1029 * out of {@link #mGlobalLock} to avoid deadlock (AM lock is used in QuotaTrack ctor). 1030 */ ensureSetPipAspectRatioQuotaTracker()1031 private void ensureSetPipAspectRatioQuotaTracker() { 1032 if (mSetPipAspectRatioQuotaTracker == null) { 1033 mSetPipAspectRatioQuotaTracker = new CountQuotaTracker(mContext, 1034 Categorizer.SINGLE_CATEGORIZER); 1035 mSetPipAspectRatioQuotaTracker.setCountLimit(Category.SINGLE_CATEGORY, 1036 SET_PIP_ASPECT_RATIO_LIMIT, SET_PIP_ASPECT_RATIO_TIME_WINDOW_MS); 1037 } 1038 } 1039 1040 /** 1041 * Checks the state of the system and the activity associated with the given {@param token} to 1042 * verify that picture-in-picture is supported for that activity. 1043 * 1044 * @return the activity record for the given {@param token} if all the checks pass. 1045 */ ensureValidPictureInPictureActivityParams(String caller, IBinder token, PictureInPictureParams params)1046 private ActivityRecord ensureValidPictureInPictureActivityParams(String caller, 1047 IBinder token, PictureInPictureParams params) { 1048 if (!mService.mSupportsPictureInPicture) { 1049 throw new IllegalStateException(caller 1050 + ": Device doesn't support picture-in-picture mode."); 1051 } 1052 1053 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 1054 if (r == null) { 1055 throw new IllegalStateException(caller 1056 + ": Can't find activity for token=" + token); 1057 } 1058 1059 if (!r.supportsPictureInPicture()) { 1060 throw new IllegalStateException(caller 1061 + ": Current activity does not support picture-in-picture."); 1062 } 1063 1064 // Rate limit how frequent an app can request aspect ratio change via 1065 // Activity#setPictureInPictureParams 1066 final int userId = UserHandle.getCallingUserId(); 1067 if (r.pictureInPictureArgs.hasSetAspectRatio() 1068 && params.hasSetAspectRatio() 1069 && !r.pictureInPictureArgs.getAspectRatio().equals( 1070 params.getAspectRatio()) 1071 && !mSetPipAspectRatioQuotaTracker.noteEvent( 1072 userId, r.packageName, "setPipAspectRatio")) { 1073 throw new IllegalStateException(caller 1074 + ": Too many PiP aspect ratio change requests from " + r.packageName); 1075 } 1076 1077 final float minAspectRatio = mContext.getResources().getFloat( 1078 com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio); 1079 final float maxAspectRatio = mContext.getResources().getFloat( 1080 com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio); 1081 1082 if (params.hasSetAspectRatio() 1083 && !mService.mWindowManager.isValidPictureInPictureAspectRatio( 1084 r.mDisplayContent, params.getAspectRatioFloat())) { 1085 throw new IllegalArgumentException(String.format(caller 1086 + ": Aspect ratio is too extreme (must be between %f and %f).", 1087 minAspectRatio, maxAspectRatio)); 1088 } 1089 1090 if (mService.mSupportsExpandedPictureInPicture && params.hasSetExpandedAspectRatio() 1091 && !mService.mWindowManager.isValidExpandedPictureInPictureAspectRatio( 1092 r.mDisplayContent, params.getExpandedAspectRatioFloat())) { 1093 throw new IllegalArgumentException(String.format(caller 1094 + ": Expanded aspect ratio is not extreme enough (must not be between" 1095 + " %f and %f).", 1096 minAspectRatio, maxAspectRatio)); 1097 } 1098 1099 // Truncate the number of actions if necessary. 1100 params.truncateActions(ActivityTaskManager.getMaxNumPictureInPictureActions(mContext)); 1101 return r; 1102 } 1103 1104 /** 1105 * Requests that an activity should enter picture-in-picture mode if possible. This method may 1106 * be used by the implementation of non-phone form factors. 1107 * 1108 * @return false if the activity cannot enter PIP mode. 1109 */ requestPictureInPictureMode(@onNull ActivityRecord r)1110 boolean requestPictureInPictureMode(@NonNull ActivityRecord r) { 1111 if (r.inPinnedWindowingMode()) { 1112 return false; 1113 } 1114 1115 final boolean canEnterPictureInPicture = r.checkEnterPictureInPictureState( 1116 "requestPictureInPictureMode", /* beforeStopping */ false); 1117 if (!canEnterPictureInPicture) { 1118 return false; 1119 } 1120 1121 if (r.pictureInPictureArgs.isAutoEnterEnabled()) { 1122 return mService.enterPictureInPictureMode(r, r.pictureInPictureArgs, 1123 false /* fromClient */); 1124 } 1125 1126 try { 1127 mService.getLifecycleManager().scheduleTransactionItem(r.app.getThread(), 1128 EnterPipRequestedItem.obtain(r.token)); 1129 return true; 1130 } catch (Exception e) { 1131 Slog.w(TAG, "Failed to send enter pip requested item: " 1132 + r.intent.getComponent(), e); 1133 return false; 1134 } 1135 } 1136 1137 /** 1138 * Alert the client that the Picture-in-Picture state has changed. 1139 */ onPictureInPictureUiStateChanged(@onNull ActivityRecord r, PictureInPictureUiState pipState)1140 void onPictureInPictureUiStateChanged(@NonNull ActivityRecord r, 1141 PictureInPictureUiState pipState) { 1142 try { 1143 mService.getLifecycleManager().scheduleTransactionItem(r.app.getThread(), 1144 PipStateTransactionItem.obtain(r.token, pipState)); 1145 } catch (Exception e) { 1146 Slog.w(TAG, "Failed to send pip state transaction item: " 1147 + r.intent.getComponent(), e); 1148 } 1149 } 1150 1151 @Override toggleFreeformWindowingMode(IBinder token)1152 public void toggleFreeformWindowingMode(IBinder token) { 1153 final long ident = Binder.clearCallingIdentity(); 1154 try { 1155 synchronized (mGlobalLock) { 1156 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 1157 if (r == null) { 1158 throw new IllegalArgumentException( 1159 "toggleFreeformWindowingMode: No activity record matching token=" 1160 + token); 1161 } 1162 1163 final Task rootTask = r.getRootTask(); 1164 if (rootTask == null) { 1165 throw new IllegalStateException("toggleFreeformWindowingMode: the activity " 1166 + "doesn't have a root task"); 1167 } 1168 1169 if (!rootTask.inFreeformWindowingMode() 1170 && rootTask.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) { 1171 throw new IllegalStateException("toggleFreeformWindowingMode: You can only " 1172 + "toggle between fullscreen and freeform."); 1173 } 1174 1175 if (rootTask.inFreeformWindowingMode()) { 1176 rootTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 1177 rootTask.setBounds(null); 1178 } else if (!r.supportsFreeform()) { 1179 throw new IllegalStateException( 1180 "This activity is currently not freeform-enabled"); 1181 } else if (rootTask.getParent().inFreeformWindowingMode()) { 1182 // If the window is on a freeform display, set it to undefined. It will be 1183 // resolved to freeform and it can adjust windowing mode when the display mode 1184 // changes in runtime. 1185 rootTask.setWindowingMode(WINDOWING_MODE_UNDEFINED); 1186 } else { 1187 rootTask.setWindowingMode(WINDOWING_MODE_FREEFORM); 1188 } 1189 } 1190 } finally { 1191 Binder.restoreCallingIdentity(ident); 1192 } 1193 } 1194 validateMultiwindowFullscreenRequestLocked( Task topFocusedRootTask, int fullscreenRequest, ActivityRecord requesterActivity)1195 private @FullscreenRequestHandler.RequestResult int validateMultiwindowFullscreenRequestLocked( 1196 Task topFocusedRootTask, int fullscreenRequest, ActivityRecord requesterActivity) { 1197 if (requesterActivity.getWindowingMode() == WINDOWING_MODE_PINNED) { 1198 return RESULT_APPROVED; 1199 } 1200 // If this is not coming from the currently top-most activity, reject the request. 1201 if (requesterActivity != topFocusedRootTask.getTopMostActivity()) { 1202 return RESULT_FAILED_NOT_TOP_FOCUSED; 1203 } 1204 if (fullscreenRequest == FULLSCREEN_MODE_REQUEST_EXIT) { 1205 if (topFocusedRootTask.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) { 1206 return RESULT_FAILED_NOT_IN_FULLSCREEN_WITH_HISTORY; 1207 } 1208 if (topFocusedRootTask.mMultiWindowRestoreWindowingMode == INVALID_WINDOWING_MODE) { 1209 return RESULT_FAILED_NOT_IN_FULLSCREEN_WITH_HISTORY; 1210 } 1211 } 1212 return RESULT_APPROVED; 1213 } 1214 1215 @Override requestMultiwindowFullscreen(IBinder callingActivity, int fullscreenRequest, IRemoteCallback callback)1216 public void requestMultiwindowFullscreen(IBinder callingActivity, int fullscreenRequest, 1217 IRemoteCallback callback) { 1218 final long ident = Binder.clearCallingIdentity(); 1219 try { 1220 synchronized (mGlobalLock) { 1221 requestMultiwindowFullscreenLocked(callingActivity, fullscreenRequest, callback); 1222 } 1223 } finally { 1224 Binder.restoreCallingIdentity(ident); 1225 } 1226 } 1227 requestMultiwindowFullscreenLocked(IBinder callingActivity, int fullscreenRequest, IRemoteCallback callback)1228 private void requestMultiwindowFullscreenLocked(IBinder callingActivity, int fullscreenRequest, 1229 IRemoteCallback callback) { 1230 final ActivityRecord r = ActivityRecord.forTokenLocked(callingActivity); 1231 if (r == null) { 1232 return; 1233 } 1234 1235 // If the shell transition is not enabled, just execute and done. 1236 final TransitionController controller = r.mTransitionController; 1237 if (!controller.isShellTransitionsEnabled()) { 1238 final @FullscreenRequestHandler.RequestResult int validateResult; 1239 final Task topFocusedRootTask; 1240 topFocusedRootTask = mService.getTopDisplayFocusedRootTask(); 1241 validateResult = validateMultiwindowFullscreenRequestLocked(topFocusedRootTask, 1242 fullscreenRequest, r); 1243 reportMultiwindowFullscreenRequestValidatingResult(callback, validateResult); 1244 if (validateResult == RESULT_APPROVED) { 1245 executeMultiWindowFullscreenRequest(fullscreenRequest, topFocusedRootTask); 1246 } 1247 return; 1248 } 1249 // Initiate the transition. 1250 final Transition transition = new Transition(TRANSIT_CHANGE, 0 /* flags */, controller, 1251 mService.mWindowManager.mSyncEngine); 1252 r.mTransitionController.startCollectOrQueue(transition, 1253 (deferred) -> { 1254 executeFullscreenRequestTransition(fullscreenRequest, callback, r, 1255 transition, deferred); 1256 }); 1257 } 1258 executeFullscreenRequestTransition(int fullscreenRequest, IRemoteCallback callback, ActivityRecord r, Transition transition, boolean queued)1259 private void executeFullscreenRequestTransition(int fullscreenRequest, IRemoteCallback callback, 1260 ActivityRecord r, Transition transition, boolean queued) { 1261 final @FullscreenRequestHandler.RequestResult int validateResult; 1262 final Task topFocusedRootTask; 1263 topFocusedRootTask = mService.getTopDisplayFocusedRootTask(); 1264 validateResult = validateMultiwindowFullscreenRequestLocked(topFocusedRootTask, 1265 fullscreenRequest, r); 1266 reportMultiwindowFullscreenRequestValidatingResult(callback, validateResult); 1267 if (validateResult != RESULT_APPROVED) { 1268 transition.abort(); 1269 return; 1270 } 1271 final Task requestingTask = r.getTask(); 1272 transition.collect(requestingTask); 1273 executeMultiWindowFullscreenRequest(fullscreenRequest, requestingTask); 1274 r.mTransitionController.requestStartTransition(transition, requestingTask, 1275 null /* remoteTransition */, null /* displayChange */); 1276 transition.setReady(requestingTask, true); 1277 } 1278 reportMultiwindowFullscreenRequestValidatingResult(IRemoteCallback callback, @FullscreenRequestHandler.RequestResult int result)1279 private static void reportMultiwindowFullscreenRequestValidatingResult(IRemoteCallback callback, 1280 @FullscreenRequestHandler.RequestResult int result) { 1281 if (callback == null) { 1282 return; 1283 } 1284 Bundle res = new Bundle(); 1285 res.putInt(REMOTE_CALLBACK_RESULT_KEY, result); 1286 try { 1287 callback.sendResult(res); 1288 } catch (RemoteException e) { 1289 Slog.w(TAG, "client throws an exception back to the server, ignore it"); 1290 } 1291 } 1292 executeMultiWindowFullscreenRequest(int fullscreenRequest, Task requester)1293 private static void executeMultiWindowFullscreenRequest(int fullscreenRequest, Task requester) { 1294 final int targetWindowingMode; 1295 if (fullscreenRequest == FULLSCREEN_MODE_REQUEST_ENTER) { 1296 final int restoreWindowingMode = requester.getRequestedOverrideWindowingMode(); 1297 targetWindowingMode = WINDOWING_MODE_FULLSCREEN; 1298 requester.setWindowingMode(targetWindowingMode); 1299 // The restore windowing mode must be set after the windowing mode is set since 1300 // Task#setWindowingMode resets the restore windowing mode to WINDOWING_MODE_INVALID. 1301 requester.mMultiWindowRestoreWindowingMode = restoreWindowingMode; 1302 requester.mMultiWindowRestoreParent = 1303 requester.getParent().mRemoteToken.toWindowContainerToken(); 1304 } else { 1305 targetWindowingMode = requester.mMultiWindowRestoreWindowingMode; 1306 requester.restoreWindowingMode(); 1307 } 1308 if (targetWindowingMode == WINDOWING_MODE_FULLSCREEN) { 1309 requester.setBounds(null); 1310 } 1311 } 1312 1313 @Override startLockTaskModeByToken(IBinder token)1314 public void startLockTaskModeByToken(IBinder token) { 1315 synchronized (mGlobalLock) { 1316 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 1317 if (r != null) { 1318 mService.startLockTaskMode(r.getTask(), false /* isSystemCaller */); 1319 } 1320 } 1321 } 1322 1323 @Override stopLockTaskModeByToken(IBinder token)1324 public void stopLockTaskModeByToken(IBinder token) { 1325 mService.stopLockTaskModeInternal(token, false /* isSystemCaller */); 1326 } 1327 1328 @Override showLockTaskEscapeMessage(IBinder token)1329 public void showLockTaskEscapeMessage(IBinder token) { 1330 synchronized (mGlobalLock) { 1331 if (ActivityRecord.forTokenLocked(token) != null) { 1332 mService.getLockTaskController().showLockTaskToast(); 1333 } 1334 } 1335 } 1336 1337 @Override setTaskDescription(IBinder token, ActivityManager.TaskDescription td)1338 public void setTaskDescription(IBinder token, ActivityManager.TaskDescription td) { 1339 synchronized (mGlobalLock) { 1340 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1341 if (r != null) { 1342 r.setTaskDescription(td); 1343 } 1344 } 1345 } 1346 1347 @Override showAssistFromActivity(IBinder token, Bundle args)1348 public boolean showAssistFromActivity(IBinder token, Bundle args) { 1349 final long ident = Binder.clearCallingIdentity(); 1350 try { 1351 final String callingAttributionTag; 1352 synchronized (mGlobalLock) { 1353 final ActivityRecord caller = ActivityRecord.forTokenLocked(token); 1354 final Task topRootTask = mService.getTopDisplayFocusedRootTask(); 1355 final ActivityRecord top = topRootTask != null 1356 ? topRootTask.getTopNonFinishingActivity() : null; 1357 if (top != caller) { 1358 Slog.w(TAG, "showAssistFromActivity failed: caller " + caller 1359 + " is not current top " + top); 1360 return false; 1361 } 1362 if (!top.nowVisible) { 1363 Slog.w(TAG, "showAssistFromActivity failed: caller " + caller 1364 + " is not visible"); 1365 return false; 1366 } 1367 callingAttributionTag = top.launchedFromFeatureId; 1368 } 1369 return mAssistUtils.showSessionForActiveService(args, SHOW_SOURCE_APPLICATION, 1370 callingAttributionTag, null /* showCallback */, token); 1371 } finally { 1372 Binder.restoreCallingIdentity(ident); 1373 } 1374 } 1375 1376 @Override isRootVoiceInteraction(IBinder token)1377 public boolean isRootVoiceInteraction(IBinder token) { 1378 synchronized (mGlobalLock) { 1379 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1380 return r != null && r.rootVoiceInteraction; 1381 } 1382 } 1383 1384 @Override startLocalVoiceInteraction(IBinder callingActivity, Bundle options)1385 public void startLocalVoiceInteraction(IBinder callingActivity, Bundle options) { 1386 Slog.i(TAG, "Activity tried to startLocalVoiceInteraction"); 1387 final String callingAttributionTag; 1388 synchronized (mGlobalLock) { 1389 final Task topRootTask = mService.getTopDisplayFocusedRootTask(); 1390 final ActivityRecord activity = topRootTask != null 1391 ? topRootTask.getTopNonFinishingActivity() : null; 1392 if (ActivityRecord.forTokenLocked(callingActivity) != activity) { 1393 throw new SecurityException("Only focused activity can call startVoiceInteraction"); 1394 } 1395 if (mService.mRunningVoice != null || activity.getTask().voiceSession != null 1396 || activity.voiceSession != null) { 1397 Slog.w(TAG, "Already in a voice interaction, cannot start new voice interaction"); 1398 return; 1399 } 1400 if (activity.pendingVoiceInteractionStart) { 1401 Slog.w(TAG, "Pending start of voice interaction already."); 1402 return; 1403 } 1404 activity.pendingVoiceInteractionStart = true; 1405 callingAttributionTag = activity.launchedFromFeatureId; 1406 } 1407 LocalServices.getService(VoiceInteractionManagerInternal.class) 1408 .startLocalVoiceInteraction(callingActivity, callingAttributionTag, options); 1409 } 1410 1411 @Override stopLocalVoiceInteraction(IBinder callingActivity)1412 public void stopLocalVoiceInteraction(IBinder callingActivity) { 1413 LocalServices.getService(VoiceInteractionManagerInternal.class) 1414 .stopLocalVoiceInteraction(callingActivity); 1415 } 1416 1417 @Override setShowWhenLocked(IBinder token, boolean showWhenLocked)1418 public void setShowWhenLocked(IBinder token, boolean showWhenLocked) { 1419 final long origId = Binder.clearCallingIdentity(); 1420 try { 1421 synchronized (mGlobalLock) { 1422 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1423 if (r != null) { 1424 r.setShowWhenLocked(showWhenLocked); 1425 } 1426 } 1427 } finally { 1428 Binder.restoreCallingIdentity(origId); 1429 } 1430 } 1431 1432 @Override setInheritShowWhenLocked(IBinder token, boolean inheritShowWhenLocked)1433 public void setInheritShowWhenLocked(IBinder token, boolean inheritShowWhenLocked) { 1434 final long origId = Binder.clearCallingIdentity(); 1435 try { 1436 synchronized (mGlobalLock) { 1437 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1438 if (r != null) { 1439 r.setInheritShowWhenLocked(inheritShowWhenLocked); 1440 } 1441 } 1442 } finally { 1443 Binder.restoreCallingIdentity(origId); 1444 } 1445 } 1446 1447 @Override setTurnScreenOn(IBinder token, boolean turnScreenOn)1448 public void setTurnScreenOn(IBinder token, boolean turnScreenOn) { 1449 final long origId = Binder.clearCallingIdentity(); 1450 try { 1451 synchronized (mGlobalLock) { 1452 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1453 if (r != null) { 1454 r.setTurnScreenOn(turnScreenOn); 1455 } 1456 } 1457 } finally { 1458 Binder.restoreCallingIdentity(origId); 1459 } 1460 } 1461 setAllowCrossUidActivitySwitchFromBelow(IBinder token, boolean allowed)1462 public void setAllowCrossUidActivitySwitchFromBelow(IBinder token, boolean allowed) { 1463 final long origId = Binder.clearCallingIdentity(); 1464 try { 1465 synchronized (mGlobalLock) { 1466 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1467 if (r != null) { 1468 r.setAllowCrossUidActivitySwitchFromBelow(allowed); 1469 } 1470 } 1471 } finally { 1472 Binder.restoreCallingIdentity(origId); 1473 } 1474 } 1475 1476 @Override reportActivityFullyDrawn(IBinder token, boolean restoredFromBundle)1477 public void reportActivityFullyDrawn(IBinder token, boolean restoredFromBundle) { 1478 final long origId = Binder.clearCallingIdentity(); 1479 try { 1480 synchronized (mGlobalLock) { 1481 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1482 if (r != null) { 1483 mTaskSupervisor.getActivityMetricsLogger().notifyFullyDrawn(r, 1484 restoredFromBundle); 1485 } 1486 } 1487 } finally { 1488 Binder.restoreCallingIdentity(origId); 1489 } 1490 } 1491 1492 @Override overrideActivityTransition(IBinder token, boolean open, int enterAnim, int exitAnim, int backgroundColor)1493 public void overrideActivityTransition(IBinder token, boolean open, int enterAnim, int exitAnim, 1494 int backgroundColor) { 1495 final long origId = Binder.clearCallingIdentity(); 1496 synchronized (mGlobalLock) { 1497 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1498 if (r != null) { 1499 r.overrideCustomTransition(open, enterAnim, exitAnim, backgroundColor); 1500 } 1501 } 1502 Binder.restoreCallingIdentity(origId); 1503 } 1504 1505 @Override clearOverrideActivityTransition(IBinder token, boolean open)1506 public void clearOverrideActivityTransition(IBinder token, boolean open) { 1507 final long origId = Binder.clearCallingIdentity(); 1508 synchronized (mGlobalLock) { 1509 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1510 if (r != null) { 1511 r.clearCustomTransition(open); 1512 } 1513 } 1514 Binder.restoreCallingIdentity(origId); 1515 } 1516 1517 @Override overridePendingTransition(IBinder token, String packageName, int enterAnim, int exitAnim, @ColorInt int backgroundColor)1518 public void overridePendingTransition(IBinder token, String packageName, 1519 int enterAnim, int exitAnim, @ColorInt int backgroundColor) { 1520 final long origId = Binder.clearCallingIdentity(); 1521 synchronized (mGlobalLock) { 1522 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1523 if (r != null && r.isState(RESUMED, PAUSING)) { 1524 r.mDisplayContent.mAppTransition.overridePendingAppTransition( 1525 packageName, enterAnim, exitAnim, backgroundColor, null, null, 1526 r.mOverrideTaskTransition); 1527 r.mTransitionController.setOverrideAnimation( 1528 TransitionInfo.AnimationOptions.makeCustomAnimOptions(packageName, 1529 enterAnim, exitAnim, backgroundColor, r.mOverrideTaskTransition), 1530 null /* startCallback */, null /* finishCallback */); 1531 } 1532 } 1533 Binder.restoreCallingIdentity(origId); 1534 } 1535 1536 @Override setVrMode(IBinder token, boolean enabled, ComponentName packageName)1537 public int setVrMode(IBinder token, boolean enabled, ComponentName packageName) { 1538 mService.enforceSystemHasVrFeature(); 1539 1540 final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class); 1541 final ActivityRecord r; 1542 synchronized (mGlobalLock) { 1543 r = ActivityRecord.isInRootTaskLocked(token); 1544 } 1545 if (r == null) { 1546 throw new IllegalArgumentException(); 1547 } 1548 1549 final int err; 1550 if ((err = vrService.hasVrPackage(packageName, r.mUserId)) != VrManagerInternal.NO_ERROR) { 1551 return err; 1552 } 1553 1554 // Clear the binder calling uid since this path may call moveToTask(). 1555 final long callingId = Binder.clearCallingIdentity(); 1556 try { 1557 synchronized (mGlobalLock) { 1558 r.requestedVrComponent = (enabled) ? packageName : null; 1559 1560 // Update associated state if this activity is currently focused. 1561 if (r.isFocusedActivityOnDisplay()) { 1562 mService.applyUpdateVrModeLocked(r); 1563 } 1564 return 0; 1565 } 1566 } finally { 1567 Binder.restoreCallingIdentity(callingId); 1568 } 1569 } 1570 1571 @Override setRecentsScreenshotEnabled(IBinder token, boolean enabled)1572 public void setRecentsScreenshotEnabled(IBinder token, boolean enabled) { 1573 final long origId = Binder.clearCallingIdentity(); 1574 try { 1575 synchronized (mGlobalLock) { 1576 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1577 if (r != null) { 1578 r.setRecentsScreenshotEnabled(enabled); 1579 } 1580 } 1581 } finally { 1582 Binder.restoreCallingIdentity(origId); 1583 } 1584 } 1585 restartActivityProcessIfVisible(IBinder token)1586 void restartActivityProcessIfVisible(IBinder token) { 1587 ActivityTaskManagerService.enforceTaskPermission("restartActivityProcess"); 1588 final long callingId = Binder.clearCallingIdentity(); 1589 try { 1590 synchronized (mGlobalLock) { 1591 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1592 if (r != null) { 1593 r.restartProcessIfVisible(); 1594 } 1595 } 1596 } finally { 1597 Binder.restoreCallingIdentity(callingId); 1598 } 1599 } 1600 1601 /** 1602 * Removes the outdated home task snapshot. 1603 * 1604 * @param token The token of the home task, or null if you have the 1605 * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS} 1606 * permission and want us to find the home task token for you. 1607 */ 1608 @Override invalidateHomeTaskSnapshot(IBinder token)1609 public void invalidateHomeTaskSnapshot(IBinder token) { 1610 if (token == null) { 1611 ActivityTaskManagerService.enforceTaskPermission("invalidateHomeTaskSnapshot"); 1612 } 1613 1614 synchronized (mGlobalLock) { 1615 final ActivityRecord r; 1616 if (token == null) { 1617 final Task rootTask = 1618 mService.mRootWindowContainer.getDefaultTaskDisplayArea().getRootHomeTask(); 1619 r = rootTask != null ? rootTask.topRunningActivity() : null; 1620 } else { 1621 r = ActivityRecord.isInRootTaskLocked(token); 1622 } 1623 1624 if (r != null && r.isActivityTypeHome()) { 1625 mService.mWindowManager.mTaskSnapshotController.removeSnapshotCache( 1626 r.getTask().mTaskId); 1627 } 1628 } 1629 } 1630 1631 @Override dismissKeyguard(IBinder token, IKeyguardDismissCallback callback, CharSequence message)1632 public void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback, 1633 CharSequence message) { 1634 if (message != null) { 1635 mService.mAmInternal.enforceCallingPermission( 1636 android.Manifest.permission.SHOW_KEYGUARD_MESSAGE, "dismissKeyguard"); 1637 } 1638 final long callingId = Binder.clearCallingIdentity(); 1639 try { 1640 synchronized (mGlobalLock) { 1641 mService.mKeyguardController.dismissKeyguard(token, callback, message); 1642 } 1643 } finally { 1644 Binder.restoreCallingIdentity(callingId); 1645 } 1646 } 1647 1648 @Override registerRemoteAnimations(IBinder token, RemoteAnimationDefinition definition)1649 public void registerRemoteAnimations(IBinder token, RemoteAnimationDefinition definition) { 1650 mService.mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, 1651 "registerRemoteAnimations"); 1652 definition.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid()); 1653 final long origId = Binder.clearCallingIdentity(); 1654 try { 1655 synchronized (mGlobalLock) { 1656 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1657 if (r != null) { 1658 r.registerRemoteAnimations(definition); 1659 } 1660 } 1661 } finally { 1662 Binder.restoreCallingIdentity(origId); 1663 } 1664 } 1665 1666 @Override unregisterRemoteAnimations(IBinder token)1667 public void unregisterRemoteAnimations(IBinder token) { 1668 mService.mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, 1669 "unregisterRemoteAnimations"); 1670 final long origId = Binder.clearCallingIdentity(); 1671 try { 1672 synchronized (mGlobalLock) { 1673 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1674 if (r != null) { 1675 r.unregisterRemoteAnimations(); 1676 } 1677 } 1678 } finally { 1679 Binder.restoreCallingIdentity(origId); 1680 } 1681 } 1682 1683 /** 1684 * Return {@code true} when the given Activity is a relative Task root. That is, the rest of 1685 * the Activities in the Task should be finished when it finishes. Otherwise, return {@code 1686 * false}. 1687 */ isRelativeTaskRootActivity(ActivityRecord r, ActivityRecord taskRoot)1688 private static boolean isRelativeTaskRootActivity(ActivityRecord r, ActivityRecord taskRoot) { 1689 // Not a relative root if the given Activity is not the root Activity of its TaskFragment. 1690 final TaskFragment taskFragment = r.getTaskFragment(); 1691 if (r != taskFragment.getActivity(ar -> !ar.finishing || ar == r, 1692 false /* traverseTopToBottom */)) { 1693 return false; 1694 } 1695 1696 // The given Activity is the relative Task root if its TaskFragment is a companion 1697 // TaskFragment to the taskRoot (i.e. the taskRoot TF will be finished together). 1698 return taskRoot.getTaskFragment().getCompanionTaskFragment() == taskFragment; 1699 } 1700 isTopActivityInTaskFragment(ActivityRecord activity)1701 private static boolean isTopActivityInTaskFragment(ActivityRecord activity) { 1702 return activity.getTaskFragment().topRunningActivity() == activity; 1703 } 1704 requestCallbackFinish(IRequestFinishCallback callback)1705 private void requestCallbackFinish(IRequestFinishCallback callback) { 1706 try { 1707 callback.requestFinish(); 1708 } catch (RemoteException e) { 1709 Slog.e(TAG, "Failed to invoke request finish callback", e); 1710 } 1711 } 1712 1713 @Override onBackPressed(IBinder token, IRequestFinishCallback callback)1714 public void onBackPressed(IBinder token, IRequestFinishCallback callback) { 1715 final long origId = Binder.clearCallingIdentity(); 1716 try { 1717 synchronized (mGlobalLock) { 1718 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1719 if (r == null) return; 1720 1721 final Task task = r.getTask(); 1722 final ActivityRecord root = task.getRootActivity(false /*ignoreRelinquishIdentity*/, 1723 true /*setToBottomIfNone*/); 1724 if (r == root && mService.mWindowOrganizerController.mTaskOrganizerController 1725 .handleInterceptBackPressedOnTaskRoot(r.getRootTask())) { 1726 // This task is handled by a task organizer that has requested the back 1727 // pressed callback. 1728 return; 1729 } 1730 if (shouldMoveTaskToBack(r, root)) { 1731 moveActivityTaskToBack(token, true /* nonRoot */); 1732 return; 1733 } 1734 } 1735 1736 // The default option for handling the back button is to finish the Activity. 1737 requestCallbackFinish(callback); 1738 } finally { 1739 Binder.restoreCallingIdentity(origId); 1740 } 1741 } 1742 shouldMoveTaskToBack(ActivityRecord r, ActivityRecord rootActivity)1743 static boolean shouldMoveTaskToBack(ActivityRecord r, ActivityRecord rootActivity) { 1744 if (r != rootActivity && !isRelativeTaskRootActivity(r, rootActivity)) { 1745 return false; 1746 } 1747 final boolean isBaseActivity = rootActivity.mActivityComponent.equals( 1748 r.getTask().realActivity); 1749 final Intent baseActivityIntent = isBaseActivity ? rootActivity.intent : null; 1750 1751 // If the activity was launched directly from the home screen, then we should 1752 // refrain from finishing the activity and instead move it to the back to keep it in 1753 // memory. The requirements for this are: 1754 // 1. The activity is the last running activity in the task. 1755 // 2. The current activity is the base activity for the task. 1756 // 3. The activity was launched by the home process, and is one of the main entry 1757 // points for the application. 1758 return baseActivityIntent != null 1759 && isTopActivityInTaskFragment(r) 1760 && rootActivity.isLaunchSourceType(ActivityRecord.LAUNCH_SOURCE_TYPE_HOME) 1761 && ActivityRecord.isMainIntent(baseActivityIntent); 1762 } 1763 1764 @Override enableTaskLocaleOverride(IBinder token)1765 public void enableTaskLocaleOverride(IBinder token) { 1766 if (UserHandle.getAppId(Binder.getCallingUid()) != SYSTEM_UID) { 1767 // Only allow system to align locale. 1768 return; 1769 } 1770 1771 synchronized (mGlobalLock) { 1772 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 1773 if (r != null) { 1774 r.getTask().mAlignActivityLocaleWithTask = true; 1775 } 1776 } 1777 } 1778 1779 /** 1780 * Returns {@code true} if the activity was explicitly requested to be launched in its 1781 * current TaskFragment. 1782 * 1783 * @see ActivityRecord#mRequestedLaunchingTaskFragmentToken 1784 */ isRequestedToLaunchInTaskFragment(IBinder activityToken, IBinder taskFragmentToken)1785 public boolean isRequestedToLaunchInTaskFragment(IBinder activityToken, 1786 IBinder taskFragmentToken) { 1787 synchronized (mGlobalLock) { 1788 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(activityToken); 1789 if (r == null) return false; 1790 1791 return r.mRequestedLaunchingTaskFragmentToken == taskFragmentToken; 1792 } 1793 } 1794 1795 @Override setActivityRecordInputSinkEnabled(IBinder activityToken, boolean enabled)1796 public void setActivityRecordInputSinkEnabled(IBinder activityToken, boolean enabled) { 1797 if (!allowDisableActivityRecordInputSink()) { 1798 return; 1799 } 1800 1801 mService.mAmInternal.enforceCallingPermission( 1802 Manifest.permission.INTERNAL_SYSTEM_WINDOW, "setActivityRecordInputSinkEnabled"); 1803 synchronized (mGlobalLock) { 1804 final ActivityRecord r = ActivityRecord.forTokenLocked(activityToken); 1805 if (r != null) { 1806 r.mActivityRecordInputSinkEnabled = enabled; 1807 } 1808 } 1809 } 1810 } 1811