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.ActivityTaskManager.INVALID_TASK_ID; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 22 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 23 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 24 import static android.os.Process.INVALID_UID; 25 import static android.os.Process.SYSTEM_UID; 26 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; 27 import static android.service.voice.VoiceInteractionSession.SHOW_SOURCE_APPLICATION; 28 import static android.view.Display.DEFAULT_DISPLAY; 29 import static android.view.Display.INVALID_DISPLAY; 30 import static android.view.WindowManager.TRANSIT_TO_BACK; 31 import static android.view.WindowManager.TRANSIT_TO_FRONT; 32 33 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; 34 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IMMERSIVE; 35 import static com.android.server.wm.ActivityRecord.State.DESTROYED; 36 import static com.android.server.wm.ActivityRecord.State.DESTROYING; 37 import static com.android.server.wm.ActivityRecord.State.PAUSING; 38 import static com.android.server.wm.ActivityRecord.State.RESTARTING_PROCESS; 39 import static com.android.server.wm.ActivityRecord.State.RESUMED; 40 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL; 41 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; 42 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; 43 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; 44 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE; 45 import static com.android.server.wm.ActivityTaskManagerService.TAG_SWITCH; 46 import static com.android.server.wm.ActivityTaskManagerService.enforceNotIsolatedCaller; 47 48 import android.Manifest; 49 import android.annotation.ColorInt; 50 import android.annotation.NonNull; 51 import android.annotation.Nullable; 52 import android.app.Activity; 53 import android.app.ActivityManager; 54 import android.app.ActivityTaskManager; 55 import android.app.IActivityClientController; 56 import android.app.ICompatCameraControlCallback; 57 import android.app.IRequestFinishCallback; 58 import android.app.PictureInPictureParams; 59 import android.app.PictureInPictureUiState; 60 import android.app.servertransaction.ClientTransaction; 61 import android.app.servertransaction.EnterPipRequestedItem; 62 import android.app.servertransaction.PipStateTransactionItem; 63 import android.content.ComponentName; 64 import android.content.Context; 65 import android.content.Intent; 66 import android.content.pm.ActivityInfo; 67 import android.content.pm.PackageManagerInternal; 68 import android.content.pm.ParceledListSlice; 69 import android.content.pm.ResolveInfo; 70 import android.content.res.Configuration; 71 import android.os.Binder; 72 import android.os.Bundle; 73 import android.os.IBinder; 74 import android.os.Parcel; 75 import android.os.PersistableBundle; 76 import android.os.RemoteException; 77 import android.os.SystemClock; 78 import android.os.Trace; 79 import android.os.UserHandle; 80 import android.service.voice.VoiceInteractionManagerInternal; 81 import android.util.Slog; 82 import android.view.RemoteAnimationDefinition; 83 import android.window.SizeConfigurationBuckets; 84 import android.window.TransitionInfo; 85 86 import com.android.internal.app.AssistUtils; 87 import com.android.internal.policy.IKeyguardDismissCallback; 88 import com.android.internal.protolog.common.ProtoLog; 89 import com.android.server.LocalServices; 90 import com.android.server.Watchdog; 91 import com.android.server.pm.KnownPackages; 92 import com.android.server.pm.parsing.pkg.AndroidPackage; 93 import com.android.server.uri.NeededUriGrants; 94 import com.android.server.vr.VrManagerInternal; 95 96 /** 97 * Server side implementation for the client activity to interact with system. 98 * 99 * @see android.app.ActivityClient 100 */ 101 class ActivityClientController extends IActivityClientController.Stub { 102 private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityClientController" : TAG_ATM; 103 104 private final ActivityTaskManagerService mService; 105 private final WindowManagerGlobalLock mGlobalLock; 106 private final ActivityTaskSupervisor mTaskSupervisor; 107 private final Context mContext; 108 109 /** Wrapper around VoiceInteractionServiceManager. */ 110 private AssistUtils mAssistUtils; 111 ActivityClientController(ActivityTaskManagerService service)112 ActivityClientController(ActivityTaskManagerService service) { 113 mService = service; 114 mGlobalLock = service.mGlobalLock; 115 mTaskSupervisor = service.mTaskSupervisor; 116 mContext = service.mContext; 117 } 118 onSystemReady()119 void onSystemReady() { 120 mAssistUtils = new AssistUtils(mContext); 121 } 122 123 @Override onTransact(int code, Parcel data, Parcel reply, int flags)124 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 125 throws RemoteException { 126 try { 127 return super.onTransact(code, data, reply, flags); 128 } catch (RuntimeException e) { 129 throw ActivityTaskManagerService.logAndRethrowRuntimeExceptionOnTransact( 130 "ActivityClientController", e); 131 } 132 } 133 134 @Override activityIdle(IBinder token, Configuration config, boolean stopProfiling)135 public void activityIdle(IBinder token, Configuration config, boolean stopProfiling) { 136 final long origId = Binder.clearCallingIdentity(); 137 try { 138 synchronized (mGlobalLock) { 139 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityIdle"); 140 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 141 if (r == null) { 142 return; 143 } 144 mTaskSupervisor.activityIdleInternal(r, false /* fromTimeout */, 145 false /* processPausingActivities */, config); 146 if (stopProfiling && r.hasProcess()) { 147 r.app.clearProfilerIfNeeded(); 148 } 149 } 150 } finally { 151 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 152 Binder.restoreCallingIdentity(origId); 153 } 154 } 155 156 @Override activityResumed(IBinder token, boolean handleSplashScreenExit)157 public void activityResumed(IBinder token, boolean handleSplashScreenExit) { 158 final long origId = Binder.clearCallingIdentity(); 159 synchronized (mGlobalLock) { 160 ActivityRecord.activityResumedLocked(token, handleSplashScreenExit); 161 } 162 Binder.restoreCallingIdentity(origId); 163 } 164 165 @Override activityRefreshed(IBinder token)166 public void activityRefreshed(IBinder token) { 167 final long origId = Binder.clearCallingIdentity(); 168 synchronized (mGlobalLock) { 169 ActivityRecord.activityRefreshedLocked(token); 170 } 171 Binder.restoreCallingIdentity(origId); 172 } 173 174 @Override activityTopResumedStateLost()175 public void activityTopResumedStateLost() { 176 final long origId = Binder.clearCallingIdentity(); 177 synchronized (mGlobalLock) { 178 mTaskSupervisor.handleTopResumedStateReleased(false /* timeout */); 179 } 180 Binder.restoreCallingIdentity(origId); 181 } 182 183 @Override activityPaused(IBinder token)184 public void activityPaused(IBinder token) { 185 final long origId = Binder.clearCallingIdentity(); 186 synchronized (mGlobalLock) { 187 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityPaused"); 188 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 189 if (r != null) { 190 r.activityPaused(false); 191 } 192 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 193 } 194 Binder.restoreCallingIdentity(origId); 195 } 196 197 @Override activityStopped(IBinder token, Bundle icicle, PersistableBundle persistentState, CharSequence description)198 public void activityStopped(IBinder token, Bundle icicle, PersistableBundle persistentState, 199 CharSequence description) { 200 if (DEBUG_ALL) Slog.v(TAG, "Activity stopped: token=" + token); 201 202 // Refuse possible leaked file descriptors. 203 if (icicle != null && icicle.hasFileDescriptors()) { 204 throw new IllegalArgumentException("File descriptors passed in Bundle"); 205 } 206 207 final long origId = Binder.clearCallingIdentity(); 208 209 String restartingName = null; 210 int restartingUid = 0; 211 final ActivityRecord r; 212 synchronized (mGlobalLock) { 213 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityStopped"); 214 r = ActivityRecord.isInRootTaskLocked(token); 215 if (r != null) { 216 if (r.attachedToProcess() && r.isState(RESTARTING_PROCESS)) { 217 // The activity was requested to restart from 218 // {@link #restartActivityProcessIfVisible}. 219 restartingName = r.app.mName; 220 restartingUid = r.app.mUid; 221 } 222 r.activityStopped(icicle, persistentState, description); 223 } 224 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 225 } 226 227 if (restartingName != null) { 228 // In order to let the foreground activity can be restarted with its saved state from 229 // {@link android.app.Activity#onSaveInstanceState}, the kill operation is postponed 230 // until the activity reports stopped with the state. And the activity record will be 231 // kept because the record state is restarting, then the activity will be restarted 232 // immediately if it is still the top one. 233 mTaskSupervisor.removeRestartTimeouts(r); 234 mService.mAmInternal.killProcess(restartingName, restartingUid, 235 "restartActivityProcess"); 236 } 237 mService.mAmInternal.trimApplications(); 238 239 Binder.restoreCallingIdentity(origId); 240 } 241 242 @Override activityDestroyed(IBinder token)243 public void activityDestroyed(IBinder token) { 244 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "ACTIVITY DESTROYED: " + token); 245 final long origId = Binder.clearCallingIdentity(); 246 synchronized (mGlobalLock) { 247 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityDestroyed"); 248 try { 249 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 250 if (r != null) { 251 r.destroyed("activityDestroyed"); 252 } 253 } finally { 254 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 255 Binder.restoreCallingIdentity(origId); 256 } 257 } 258 } 259 260 @Override activityLocalRelaunch(IBinder token)261 public void activityLocalRelaunch(IBinder token) { 262 final long origId = Binder.clearCallingIdentity(); 263 synchronized (mGlobalLock) { 264 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 265 if (r != null) { 266 r.startRelaunching(); 267 } 268 } 269 Binder.restoreCallingIdentity(origId); 270 } 271 272 @Override activityRelaunched(IBinder token)273 public void activityRelaunched(IBinder token) { 274 final long origId = Binder.clearCallingIdentity(); 275 synchronized (mGlobalLock) { 276 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 277 if (r != null) { 278 r.finishRelaunching(); 279 } 280 } 281 Binder.restoreCallingIdentity(origId); 282 } 283 284 @Override reportSizeConfigurations(IBinder token, SizeConfigurationBuckets sizeConfigurations)285 public void reportSizeConfigurations(IBinder token, 286 SizeConfigurationBuckets sizeConfigurations) { 287 ProtoLog.v(WM_DEBUG_CONFIGURATION, "Report configuration: %s %s", 288 token, sizeConfigurations); 289 synchronized (mGlobalLock) { 290 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 291 if (r != null) { 292 r.setSizeConfigurations(sizeConfigurations); 293 } 294 } 295 } 296 297 /** 298 * Attempts to move a task backwards in z-order (the order of activities within the task is 299 * unchanged). 300 * 301 * There are several possible results of this call: 302 * - if the task is locked, then we will show the lock toast. 303 * - if there is a task behind the provided task, then that task is made visible and resumed as 304 * this task is moved to the back. 305 * - otherwise, if there are no other tasks in the root task: 306 * - if this task is in the pinned mode, then we remove the task completely, which will 307 * have the effect of moving the task to the top or bottom of the fullscreen root task 308 * (depending on whether it is visible). 309 * - otherwise, we simply return home and hide this task. 310 * 311 * @param token A reference to the activity we wish to move. 312 * @param nonRoot If false then this only works if the activity is the root 313 * of a task; if true it will work for any activity in a task. 314 * @return Returns true if the move completed, false if not. 315 */ 316 @Override moveActivityTaskToBack(IBinder token, boolean nonRoot)317 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) { 318 enforceNotIsolatedCaller("moveActivityTaskToBack"); 319 final long origId = Binder.clearCallingIdentity(); 320 try { 321 synchronized (mGlobalLock) { 322 final int taskId = ActivityRecord.getTaskForActivityLocked(token, !nonRoot); 323 final Task task = mService.mRootWindowContainer.anyTaskForId(taskId); 324 if (task != null) { 325 return ActivityRecord.getRootTask(token).moveTaskToBack(task); 326 } 327 } 328 } finally { 329 Binder.restoreCallingIdentity(origId); 330 } 331 return false; 332 } 333 334 @Override shouldUpRecreateTask(IBinder token, String destAffinity)335 public boolean shouldUpRecreateTask(IBinder token, String destAffinity) { 336 synchronized (mGlobalLock) { 337 final ActivityRecord srec = ActivityRecord.forTokenLocked(token); 338 if (srec != null) { 339 return srec.getRootTask().shouldUpRecreateTaskLocked(srec, destAffinity); 340 } 341 } 342 return false; 343 } 344 345 @Override navigateUpTo(IBinder token, Intent destIntent, String resolvedType, int resultCode, Intent resultData)346 public boolean navigateUpTo(IBinder token, Intent destIntent, String resolvedType, 347 int resultCode, Intent resultData) { 348 final ActivityRecord r; 349 synchronized (mGlobalLock) { 350 r = ActivityRecord.isInRootTaskLocked(token); 351 if (r == null) { 352 return false; 353 } 354 } 355 356 // Carefully collect grants without holding lock. 357 final NeededUriGrants destGrants = mService.collectGrants(destIntent, r); 358 final NeededUriGrants resultGrants = mService.collectGrants(resultData, r.resultTo); 359 360 synchronized (mGlobalLock) { 361 return r.getRootTask().navigateUpTo( 362 r, destIntent, resolvedType, destGrants, resultCode, resultData, resultGrants); 363 } 364 } 365 366 @Override releaseActivityInstance(IBinder token)367 public boolean releaseActivityInstance(IBinder token) { 368 final long origId = Binder.clearCallingIdentity(); 369 try { 370 synchronized (mGlobalLock) { 371 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 372 if (r == null || !r.isDestroyable()) { 373 return false; 374 } 375 r.destroyImmediately("app-req"); 376 return r.isState(DESTROYING, DESTROYED); 377 } 378 } finally { 379 Binder.restoreCallingIdentity(origId); 380 } 381 } 382 383 /** 384 * This is the internal entry point for handling Activity.finish(). 385 * 386 * @param token The Binder token referencing the Activity we want to finish. 387 * @param resultCode Result code, if any, from this Activity. 388 * @param resultData Result data (Intent), if any, from this Activity. 389 * @param finishTask Whether to finish the task associated with this Activity. 390 * @return Returns true if the activity successfully finished, or false if it is still running. 391 */ 392 @Override finishActivity(IBinder token, int resultCode, Intent resultData, int finishTask)393 public boolean finishActivity(IBinder token, int resultCode, Intent resultData, 394 int finishTask) { 395 // Refuse possible leaked file descriptors. 396 if (resultData != null && resultData.hasFileDescriptors()) { 397 throw new IllegalArgumentException("File descriptors passed in Intent"); 398 } 399 400 final ActivityRecord r; 401 synchronized (mGlobalLock) { 402 r = ActivityRecord.isInRootTaskLocked(token); 403 if (r == null) { 404 return true; 405 } 406 } 407 408 // Carefully collect grants without holding lock. 409 final NeededUriGrants resultGrants = mService.collectGrants(resultData, r.resultTo); 410 411 synchronized (mGlobalLock) { 412 // Check again in case activity was removed when collecting grants. 413 if (!r.isInHistory()) { 414 return true; 415 } 416 417 // Keep track of the root activity of the task before we finish it. 418 final Task tr = r.getTask(); 419 final ActivityRecord rootR = tr.getRootActivity(); 420 if (rootR == null) { 421 Slog.w(TAG, "Finishing task with all activities already finished"); 422 } 423 // Do not allow task to finish if last task in lockTask mode. Launchable priv-apps can 424 // finish. 425 if (mService.getLockTaskController().activityBlockedFromFinish(r)) { 426 return false; 427 } 428 429 // TODO: There is a dup. of this block of code in ActivityStack.navigateUpToLocked 430 // We should consolidate. 431 if (mService.mController != null) { 432 // Find the first activity that is not finishing. 433 final ActivityRecord next = 434 r.getRootTask().topRunningActivity(token, INVALID_TASK_ID); 435 if (next != null) { 436 // ask watcher if this is allowed 437 boolean resumeOK = true; 438 try { 439 resumeOK = mService.mController.activityResuming(next.packageName); 440 } catch (RemoteException e) { 441 mService.mController = null; 442 Watchdog.getInstance().setActivityController(null); 443 } 444 445 if (!resumeOK) { 446 Slog.i(TAG, "Not finishing activity because controller resumed"); 447 return false; 448 } 449 } 450 } 451 452 // Note down that the process has finished an activity and is in background activity 453 // starts grace period. 454 if (r.app != null) { 455 r.app.setLastActivityFinishTimeIfNeeded(SystemClock.uptimeMillis()); 456 } 457 458 final long origId = Binder.clearCallingIdentity(); 459 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "finishActivity"); 460 try { 461 final boolean res; 462 final boolean finishWithRootActivity = 463 finishTask == Activity.FINISH_TASK_WITH_ROOT_ACTIVITY; 464 if (finishTask == Activity.FINISH_TASK_WITH_ACTIVITY 465 || (finishWithRootActivity && r == rootR)) { 466 // If requested, remove the task that is associated to this activity only if it 467 // was the root activity in the task. The result code and data is ignored 468 // because we don't support returning them across task boundaries. Also, to 469 // keep backwards compatibility we remove the task from recents when finishing 470 // task with root activity. 471 mTaskSupervisor.removeTask(tr, false /*killProcess*/, 472 finishWithRootActivity, "finish-activity"); 473 res = true; 474 // Explicitly dismissing the activity so reset its relaunch flag. 475 r.mRelaunchReason = RELAUNCH_REASON_NONE; 476 } else { 477 r.finishIfPossible(resultCode, resultData, resultGrants, "app-request", 478 true /* oomAdj */); 479 res = r.finishing; 480 if (!res) { 481 Slog.i(TAG, "Failed to finish by app-request"); 482 } 483 } 484 return res; 485 } finally { 486 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 487 Binder.restoreCallingIdentity(origId); 488 } 489 } 490 } 491 492 @Override finishActivityAffinity(IBinder token)493 public boolean finishActivityAffinity(IBinder token) { 494 final long origId = Binder.clearCallingIdentity(); 495 try { 496 synchronized (mGlobalLock) { 497 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 498 if (r == null) { 499 return false; 500 } 501 502 // Do not allow task to finish if last task in lockTask mode. Launchable priv-apps 503 // can finish. 504 if (mService.getLockTaskController().activityBlockedFromFinish(r)) { 505 return false; 506 } 507 508 r.getTask().forAllActivities(activity -> r.finishIfSameAffinity(activity), 509 r /* boundary */, true /* includeBoundary */, 510 true /* traverseTopToBottom */); 511 return true; 512 } 513 } finally { 514 Binder.restoreCallingIdentity(origId); 515 } 516 } 517 518 @Override finishSubActivity(IBinder token, String resultWho, int requestCode)519 public void finishSubActivity(IBinder token, String resultWho, int requestCode) { 520 final long origId = Binder.clearCallingIdentity(); 521 try { 522 synchronized (mGlobalLock) { 523 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 524 if (r == null) return; 525 526 // TODO: This should probably only loop over the task since you need to be in the 527 // same task to return results. 528 r.getRootTask().forAllActivities(activity -> { 529 activity.finishIfSubActivity(r /* parent */, resultWho, requestCode); 530 }, true /* traverseTopToBottom */); 531 532 mService.updateOomAdj(); 533 } 534 } finally { 535 Binder.restoreCallingIdentity(origId); 536 } 537 } 538 539 @Override setForceSendResultForMediaProjection(IBinder token)540 public void setForceSendResultForMediaProjection(IBinder token) { 541 // Require that this is invoked only during MediaProjection setup. 542 mService.mAmInternal.enforceCallingPermission( 543 Manifest.permission.MANAGE_MEDIA_PROJECTION, 544 "setForceSendResultForMediaProjection"); 545 546 final ActivityRecord r; 547 synchronized (mGlobalLock) { 548 r = ActivityRecord.isInRootTaskLocked(token); 549 if (r == null || !r.isInHistory()) { 550 return; 551 } 552 r.setForceSendResultForMediaProjection(); 553 } 554 } 555 556 @Override isTopOfTask(IBinder token)557 public boolean isTopOfTask(IBinder token) { 558 synchronized (mGlobalLock) { 559 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 560 return r != null && r.getTask().getTopNonFinishingActivity() == r; 561 } 562 } 563 564 @Override willActivityBeVisible(IBinder token)565 public boolean willActivityBeVisible(IBinder token) { 566 synchronized (mGlobalLock) { 567 final Task rootTask = ActivityRecord.getRootTask(token); 568 return rootTask != null && rootTask.willActivityBeVisible(token); 569 } 570 } 571 572 @Override getDisplayId(IBinder activityToken)573 public int getDisplayId(IBinder activityToken) { 574 synchronized (mGlobalLock) { 575 final Task rootTask = ActivityRecord.getRootTask(activityToken); 576 if (rootTask != null) { 577 final int displayId = rootTask.getDisplayId(); 578 return displayId != INVALID_DISPLAY ? displayId : DEFAULT_DISPLAY; 579 } 580 return DEFAULT_DISPLAY; 581 } 582 } 583 584 @Override getTaskForActivity(IBinder token, boolean onlyRoot)585 public int getTaskForActivity(IBinder token, boolean onlyRoot) { 586 synchronized (mGlobalLock) { 587 return ActivityRecord.getTaskForActivityLocked(token, onlyRoot); 588 } 589 } 590 591 /** 592 * Returns the {@link Configuration} of the task which hosts the Activity, or {@code null} if 593 * the task {@link Configuration} cannot be obtained. 594 */ 595 @Override 596 @Nullable getTaskConfiguration(IBinder activityToken)597 public Configuration getTaskConfiguration(IBinder activityToken) { 598 synchronized (mGlobalLock) { 599 final ActivityRecord ar = ActivityRecord.isInAnyTask(activityToken); 600 if (ar == null) { 601 return null; 602 } 603 return ar.getTask().getConfiguration(); 604 } 605 } 606 607 @Override 608 @Nullable getActivityTokenBelow(IBinder activityToken)609 public IBinder getActivityTokenBelow(IBinder activityToken) { 610 final long ident = Binder.clearCallingIdentity(); 611 try { 612 synchronized (mGlobalLock) { 613 final ActivityRecord ar = ActivityRecord.isInAnyTask(activityToken); 614 if (ar == null) { 615 return null; 616 } 617 // Exclude finishing activity. 618 final ActivityRecord below = ar.getTask().getActivity((r) -> !r.finishing, 619 ar, false /*includeBoundary*/, true /*traverseTopToBottom*/); 620 if (below != null && below.getUid() == ar.getUid()) { 621 return below.token; 622 } 623 } 624 } finally { 625 Binder.restoreCallingIdentity(ident); 626 } 627 return null; 628 } 629 630 @Override getCallingActivity(IBinder token)631 public ComponentName getCallingActivity(IBinder token) { 632 synchronized (mGlobalLock) { 633 final ActivityRecord r = getCallingRecord(token); 634 return r != null ? r.intent.getComponent() : null; 635 } 636 } 637 638 @Override getCallingPackage(IBinder token)639 public String getCallingPackage(IBinder token) { 640 synchronized (mGlobalLock) { 641 final ActivityRecord r = getCallingRecord(token); 642 return r != null ? r.info.packageName : null; 643 } 644 } 645 getCallingRecord(IBinder token)646 private static ActivityRecord getCallingRecord(IBinder token) { 647 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 648 return r != null ? r.resultTo : null; 649 } 650 651 @Override getLaunchedFromUid(IBinder token)652 public int getLaunchedFromUid(IBinder token) { 653 if (!canGetLaunchedFrom()) { 654 return INVALID_UID; 655 } 656 synchronized (mGlobalLock) { 657 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 658 return r != null ? r.launchedFromUid : INVALID_UID; 659 } 660 } 661 662 @Override getLaunchedFromPackage(IBinder token)663 public String getLaunchedFromPackage(IBinder token) { 664 if (!canGetLaunchedFrom()) { 665 return null; 666 } 667 synchronized (mGlobalLock) { 668 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 669 return r != null ? r.launchedFromPackage : null; 670 } 671 } 672 673 /** Whether the caller can get the package or uid that launched its activity. */ canGetLaunchedFrom()674 private boolean canGetLaunchedFrom() { 675 final int uid = Binder.getCallingUid(); 676 if (UserHandle.getAppId(uid) == SYSTEM_UID) { 677 return true; 678 } 679 final PackageManagerInternal pm = mService.mWindowManager.mPmInternal; 680 final AndroidPackage callingPkg = pm.getPackage(uid); 681 if (callingPkg == null) { 682 return false; 683 } 684 if (callingPkg.isSignedWithPlatformKey()) { 685 return true; 686 } 687 final String[] installerNames = pm.getKnownPackageNames( 688 KnownPackages.PACKAGE_INSTALLER, UserHandle.getUserId(uid)); 689 return installerNames.length > 0 && callingPkg.getPackageName().equals(installerNames[0]); 690 } 691 692 @Override setRequestedOrientation(IBinder token, int requestedOrientation)693 public void setRequestedOrientation(IBinder token, int requestedOrientation) { 694 final long origId = Binder.clearCallingIdentity(); 695 try { 696 synchronized (mGlobalLock) { 697 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 698 if (r != null) { 699 EventLogTags.writeWmSetRequestedOrientation(requestedOrientation, 700 r.shortComponentName); 701 r.setRequestedOrientation(requestedOrientation); 702 } 703 } 704 } finally { 705 Binder.restoreCallingIdentity(origId); 706 } 707 } 708 709 @Override getRequestedOrientation(IBinder token)710 public int getRequestedOrientation(IBinder token) { 711 synchronized (mGlobalLock) { 712 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 713 return r != null 714 ? r.getOverrideOrientation() 715 : ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 716 } 717 } 718 719 @Override convertFromTranslucent(IBinder token)720 public boolean convertFromTranslucent(IBinder token) { 721 final long origId = Binder.clearCallingIdentity(); 722 try { 723 synchronized (mGlobalLock) { 724 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 725 // Create a transition if the activity is playing in case the below activity didn't 726 // commit invisible. That's because if any activity below this one has changed its 727 // visibility while playing transition, there won't able to commit visibility until 728 // the running transition finish. 729 final Transition transition = r != null 730 && r.mTransitionController.inPlayingTransition(r) 731 ? r.mTransitionController.createTransition(TRANSIT_TO_BACK) : null; 732 if (transition != null) { 733 r.mTransitionController.requestStartTransition(transition, null /*startTask */, 734 null /* remoteTransition */, null /* displayChange */); 735 } 736 final boolean changed = r != null && r.setOccludesParent(true); 737 if (transition != null) { 738 if (changed) { 739 r.mTransitionController.setReady(r.getDisplayContent()); 740 } else { 741 transition.abort(); 742 } 743 } 744 return changed; 745 } 746 } finally { 747 Binder.restoreCallingIdentity(origId); 748 } 749 } 750 751 @Override convertToTranslucent(IBinder token, Bundle options)752 public boolean convertToTranslucent(IBinder token, Bundle options) { 753 final SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(options); 754 final long origId = Binder.clearCallingIdentity(); 755 try { 756 synchronized (mGlobalLock) { 757 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 758 if (r == null) { 759 return false; 760 } 761 final ActivityRecord under = r.getTask().getActivityBelow(r); 762 if (under != null) { 763 under.returningOptions = safeOptions != null ? safeOptions.getOptions(r) : null; 764 } 765 // Create a transition if the activity is playing in case the current activity 766 // didn't commit invisible. That's because if this activity has changed its 767 // visibility while playing transition, there won't able to commit visibility until 768 // the running transition finish. 769 final Transition transition = r.mTransitionController.inPlayingTransition(r) 770 ? r.mTransitionController.createTransition(TRANSIT_TO_FRONT) : null; 771 if (transition != null) { 772 r.mTransitionController.requestStartTransition(transition, null /*startTask */, 773 null /* remoteTransition */, null /* displayChange */); 774 } 775 final boolean changed = r.setOccludesParent(false); 776 if (transition != null) { 777 if (changed) { 778 r.mTransitionController.setReady(r.getDisplayContent()); 779 } else { 780 transition.abort(); 781 } 782 } 783 return changed; 784 } 785 } finally { 786 Binder.restoreCallingIdentity(origId); 787 } 788 } 789 790 @Override isImmersive(IBinder token)791 public boolean isImmersive(IBinder token) { 792 synchronized (mGlobalLock) { 793 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 794 if (r == null) { 795 throw new IllegalArgumentException(); 796 } 797 return r.immersive; 798 } 799 } 800 801 @Override setImmersive(IBinder token, boolean immersive)802 public void setImmersive(IBinder token, boolean immersive) { 803 synchronized (mGlobalLock) { 804 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 805 if (r == null) { 806 throw new IllegalArgumentException(); 807 } 808 r.immersive = immersive; 809 810 // Update associated state if we're frontmost. 811 if (r.isFocusedActivityOnDisplay()) { 812 ProtoLog.d(WM_DEBUG_IMMERSIVE, "Frontmost changed immersion: %s", r); 813 mService.applyUpdateLockStateLocked(r); 814 } 815 } 816 } 817 818 @Override enterPictureInPictureMode(IBinder token, final PictureInPictureParams params)819 public boolean enterPictureInPictureMode(IBinder token, final PictureInPictureParams params) { 820 final long origId = Binder.clearCallingIdentity(); 821 try { 822 synchronized (mGlobalLock) { 823 final ActivityRecord r = ensureValidPictureInPictureActivityParams( 824 "enterPictureInPictureMode", token, params); 825 return mService.enterPictureInPictureMode(r, params, true /* fromClient */); 826 } 827 } finally { 828 Binder.restoreCallingIdentity(origId); 829 } 830 } 831 832 @Override setPictureInPictureParams(IBinder token, final PictureInPictureParams params)833 public void setPictureInPictureParams(IBinder token, final PictureInPictureParams params) { 834 final long origId = Binder.clearCallingIdentity(); 835 try { 836 synchronized (mGlobalLock) { 837 final ActivityRecord r = ensureValidPictureInPictureActivityParams( 838 "setPictureInPictureParams", token, params); 839 r.setPictureInPictureParams(params); 840 } 841 } finally { 842 Binder.restoreCallingIdentity(origId); 843 } 844 } 845 846 @Override setShouldDockBigOverlays(IBinder token, boolean shouldDockBigOverlays)847 public void setShouldDockBigOverlays(IBinder token, boolean shouldDockBigOverlays) { 848 final long origId = Binder.clearCallingIdentity(); 849 try { 850 synchronized (mGlobalLock) { 851 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 852 r.setShouldDockBigOverlays(shouldDockBigOverlays); 853 } 854 } finally { 855 Binder.restoreCallingIdentity(origId); 856 } 857 } 858 859 /** 860 * Splash screen view is attached to activity. 861 */ 862 @Override splashScreenAttached(IBinder token)863 public void splashScreenAttached(IBinder token) { 864 final long origId = Binder.clearCallingIdentity(); 865 synchronized (mGlobalLock) { 866 ActivityRecord.splashScreenAttachedLocked(token); 867 } 868 Binder.restoreCallingIdentity(origId); 869 } 870 871 @Override requestCompatCameraControl(IBinder token, boolean showControl, boolean transformationApplied, ICompatCameraControlCallback callback)872 public void requestCompatCameraControl(IBinder token, boolean showControl, 873 boolean transformationApplied, ICompatCameraControlCallback callback) { 874 final long origId = Binder.clearCallingIdentity(); 875 try { 876 synchronized (mGlobalLock) { 877 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 878 if (r != null) { 879 r.updateCameraCompatState(showControl, transformationApplied, callback); 880 } 881 } 882 } finally { 883 Binder.restoreCallingIdentity(origId); 884 } 885 } 886 887 /** 888 * Checks the state of the system and the activity associated with the given {@param token} to 889 * verify that picture-in-picture is supported for that activity. 890 * 891 * @return the activity record for the given {@param token} if all the checks pass. 892 */ ensureValidPictureInPictureActivityParams(String caller, IBinder token, PictureInPictureParams params)893 private ActivityRecord ensureValidPictureInPictureActivityParams(String caller, 894 IBinder token, PictureInPictureParams params) { 895 if (!mService.mSupportsPictureInPicture) { 896 throw new IllegalStateException(caller 897 + ": Device doesn't support picture-in-picture mode."); 898 } 899 900 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 901 if (r == null) { 902 throw new IllegalStateException(caller 903 + ": Can't find activity for token=" + token); 904 } 905 906 if (!r.supportsPictureInPicture()) { 907 throw new IllegalStateException(caller 908 + ": Current activity does not support picture-in-picture."); 909 } 910 911 final float minAspectRatio = mContext.getResources().getFloat( 912 com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio); 913 final float maxAspectRatio = mContext.getResources().getFloat( 914 com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio); 915 916 if (params.hasSetAspectRatio() 917 && !mService.mWindowManager.isValidPictureInPictureAspectRatio( 918 r.mDisplayContent, params.getAspectRatioFloat())) { 919 throw new IllegalArgumentException(String.format(caller 920 + ": Aspect ratio is too extreme (must be between %f and %f).", 921 minAspectRatio, maxAspectRatio)); 922 } 923 924 if (mService.mSupportsExpandedPictureInPicture && params.hasSetExpandedAspectRatio() 925 && !mService.mWindowManager.isValidExpandedPictureInPictureAspectRatio( 926 r.mDisplayContent, params.getExpandedAspectRatioFloat())) { 927 throw new IllegalArgumentException(String.format(caller 928 + ": Expanded aspect ratio is not extreme enough (must not be between" 929 + " %f and %f).", 930 minAspectRatio, maxAspectRatio)); 931 } 932 933 // Truncate the number of actions if necessary. 934 params.truncateActions(ActivityTaskManager.getMaxNumPictureInPictureActions(mContext)); 935 return r; 936 } 937 938 /** 939 * Requests that an activity should enter picture-in-picture mode if possible. This method may 940 * be used by the implementation of non-phone form factors. 941 * 942 * @return false if the activity cannot enter PIP mode. 943 */ requestPictureInPictureMode(@onNull ActivityRecord r)944 boolean requestPictureInPictureMode(@NonNull ActivityRecord r) { 945 if (r.inPinnedWindowingMode()) { 946 return false; 947 } 948 949 final boolean canEnterPictureInPicture = r.checkEnterPictureInPictureState( 950 "requestPictureInPictureMode", /* beforeStopping */ false); 951 if (!canEnterPictureInPicture) { 952 return false; 953 } 954 955 if (r.pictureInPictureArgs.isAutoEnterEnabled()) { 956 return mService.enterPictureInPictureMode(r, r.pictureInPictureArgs, 957 false /* fromClient */); 958 } 959 960 try { 961 final ClientTransaction transaction = ClientTransaction.obtain( 962 r.app.getThread(), r.token); 963 transaction.addCallback(EnterPipRequestedItem.obtain()); 964 mService.getLifecycleManager().scheduleTransaction(transaction); 965 return true; 966 } catch (Exception e) { 967 Slog.w(TAG, "Failed to send enter pip requested item: " 968 + r.intent.getComponent(), e); 969 return false; 970 } 971 } 972 973 /** 974 * Alert the client that the Picture-in-Picture state has changed. 975 */ onPictureInPictureStateChanged(@onNull ActivityRecord r, PictureInPictureUiState pipState)976 void onPictureInPictureStateChanged(@NonNull ActivityRecord r, 977 PictureInPictureUiState pipState) { 978 if (!r.inPinnedWindowingMode()) { 979 throw new IllegalStateException("Activity is not in PIP mode"); 980 } 981 982 try { 983 final ClientTransaction transaction = ClientTransaction.obtain( 984 r.app.getThread(), r.token); 985 transaction.addCallback(PipStateTransactionItem.obtain(pipState)); 986 mService.getLifecycleManager().scheduleTransaction(transaction); 987 } catch (Exception e) { 988 Slog.w(TAG, "Failed to send pip state transaction item: " 989 + r.intent.getComponent(), e); 990 } 991 } 992 993 @Override toggleFreeformWindowingMode(IBinder token)994 public void toggleFreeformWindowingMode(IBinder token) { 995 final long ident = Binder.clearCallingIdentity(); 996 try { 997 synchronized (mGlobalLock) { 998 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 999 if (r == null) { 1000 throw new IllegalArgumentException( 1001 "toggleFreeformWindowingMode: No activity record matching token=" 1002 + token); 1003 } 1004 1005 final Task rootTask = r.getRootTask(); 1006 if (rootTask == null) { 1007 throw new IllegalStateException("toggleFreeformWindowingMode: the activity " 1008 + "doesn't have a root task"); 1009 } 1010 1011 if (!rootTask.inFreeformWindowingMode() 1012 && rootTask.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) { 1013 throw new IllegalStateException("toggleFreeformWindowingMode: You can only " 1014 + "toggle between fullscreen and freeform."); 1015 } 1016 1017 if (rootTask.inFreeformWindowingMode()) { 1018 rootTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 1019 rootTask.setBounds(null); 1020 } else if (!r.supportsFreeform()) { 1021 throw new IllegalStateException( 1022 "This activity is currently not freeform-enabled"); 1023 } else if (rootTask.getParent().inFreeformWindowingMode()) { 1024 // If the window is on a freeform display, set it to undefined. It will be 1025 // resolved to freeform and it can adjust windowing mode when the display mode 1026 // changes in runtime. 1027 rootTask.setWindowingMode(WINDOWING_MODE_UNDEFINED); 1028 } else { 1029 rootTask.setWindowingMode(WINDOWING_MODE_FREEFORM); 1030 } 1031 } 1032 } finally { 1033 Binder.restoreCallingIdentity(ident); 1034 } 1035 } 1036 1037 @Override startLockTaskModeByToken(IBinder token)1038 public void startLockTaskModeByToken(IBinder token) { 1039 synchronized (mGlobalLock) { 1040 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 1041 if (r != null) { 1042 mService.startLockTaskMode(r.getTask(), false /* isSystemCaller */); 1043 } 1044 } 1045 } 1046 1047 @Override stopLockTaskModeByToken(IBinder token)1048 public void stopLockTaskModeByToken(IBinder token) { 1049 mService.stopLockTaskModeInternal(token, false /* isSystemCaller */); 1050 } 1051 1052 @Override showLockTaskEscapeMessage(IBinder token)1053 public void showLockTaskEscapeMessage(IBinder token) { 1054 synchronized (mGlobalLock) { 1055 if (ActivityRecord.forTokenLocked(token) != null) { 1056 mService.getLockTaskController().showLockTaskToast(); 1057 } 1058 } 1059 } 1060 1061 @Override setTaskDescription(IBinder token, ActivityManager.TaskDescription td)1062 public void setTaskDescription(IBinder token, ActivityManager.TaskDescription td) { 1063 synchronized (mGlobalLock) { 1064 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1065 if (r != null) { 1066 r.setTaskDescription(td); 1067 } 1068 } 1069 } 1070 1071 @Override showAssistFromActivity(IBinder token, Bundle args)1072 public boolean showAssistFromActivity(IBinder token, Bundle args) { 1073 final long ident = Binder.clearCallingIdentity(); 1074 try { 1075 synchronized (mGlobalLock) { 1076 final ActivityRecord caller = ActivityRecord.forTokenLocked(token); 1077 final Task topRootTask = mService.getTopDisplayFocusedRootTask(); 1078 final ActivityRecord top = topRootTask != null 1079 ? topRootTask.getTopNonFinishingActivity() : null; 1080 if (top != caller) { 1081 Slog.w(TAG, "showAssistFromActivity failed: caller " + caller 1082 + " is not current top " + top); 1083 return false; 1084 } 1085 if (!top.nowVisible) { 1086 Slog.w(TAG, "showAssistFromActivity failed: caller " + caller 1087 + " is not visible"); 1088 return false; 1089 } 1090 } 1091 return mAssistUtils.showSessionForActiveService(args, SHOW_SOURCE_APPLICATION, 1092 null /* showCallback */, token); 1093 } finally { 1094 Binder.restoreCallingIdentity(ident); 1095 } 1096 } 1097 1098 @Override isRootVoiceInteraction(IBinder token)1099 public boolean isRootVoiceInteraction(IBinder token) { 1100 synchronized (mGlobalLock) { 1101 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1102 return r != null && r.rootVoiceInteraction; 1103 } 1104 } 1105 1106 @Override startLocalVoiceInteraction(IBinder callingActivity, Bundle options)1107 public void startLocalVoiceInteraction(IBinder callingActivity, Bundle options) { 1108 Slog.i(TAG, "Activity tried to startLocalVoiceInteraction"); 1109 synchronized (mGlobalLock) { 1110 final Task topRootTask = mService.getTopDisplayFocusedRootTask(); 1111 final ActivityRecord activity = topRootTask != null 1112 ? topRootTask.getTopNonFinishingActivity() : null; 1113 if (ActivityRecord.forTokenLocked(callingActivity) != activity) { 1114 throw new SecurityException("Only focused activity can call startVoiceInteraction"); 1115 } 1116 if (mService.mRunningVoice != null || activity.getTask().voiceSession != null 1117 || activity.voiceSession != null) { 1118 Slog.w(TAG, "Already in a voice interaction, cannot start new voice interaction"); 1119 return; 1120 } 1121 if (activity.pendingVoiceInteractionStart) { 1122 Slog.w(TAG, "Pending start of voice interaction already."); 1123 return; 1124 } 1125 activity.pendingVoiceInteractionStart = true; 1126 } 1127 LocalServices.getService(VoiceInteractionManagerInternal.class) 1128 .startLocalVoiceInteraction(callingActivity, options); 1129 } 1130 1131 @Override stopLocalVoiceInteraction(IBinder callingActivity)1132 public void stopLocalVoiceInteraction(IBinder callingActivity) { 1133 LocalServices.getService(VoiceInteractionManagerInternal.class) 1134 .stopLocalVoiceInteraction(callingActivity); 1135 } 1136 1137 @Override setShowWhenLocked(IBinder token, boolean showWhenLocked)1138 public void setShowWhenLocked(IBinder token, boolean showWhenLocked) { 1139 final long origId = Binder.clearCallingIdentity(); 1140 try { 1141 synchronized (mGlobalLock) { 1142 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1143 if (r != null) { 1144 r.setShowWhenLocked(showWhenLocked); 1145 } 1146 } 1147 } finally { 1148 Binder.restoreCallingIdentity(origId); 1149 } 1150 } 1151 1152 @Override setInheritShowWhenLocked(IBinder token, boolean inheritShowWhenLocked)1153 public void setInheritShowWhenLocked(IBinder token, boolean inheritShowWhenLocked) { 1154 final long origId = Binder.clearCallingIdentity(); 1155 try { 1156 synchronized (mGlobalLock) { 1157 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1158 if (r != null) { 1159 r.setInheritShowWhenLocked(inheritShowWhenLocked); 1160 } 1161 } 1162 } finally { 1163 Binder.restoreCallingIdentity(origId); 1164 } 1165 } 1166 1167 @Override setTurnScreenOn(IBinder token, boolean turnScreenOn)1168 public void setTurnScreenOn(IBinder token, boolean turnScreenOn) { 1169 final long origId = Binder.clearCallingIdentity(); 1170 try { 1171 synchronized (mGlobalLock) { 1172 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1173 if (r != null) { 1174 r.setTurnScreenOn(turnScreenOn); 1175 } 1176 } 1177 } finally { 1178 Binder.restoreCallingIdentity(origId); 1179 } 1180 } 1181 1182 @Override reportActivityFullyDrawn(IBinder token, boolean restoredFromBundle)1183 public void reportActivityFullyDrawn(IBinder token, boolean restoredFromBundle) { 1184 final long origId = Binder.clearCallingIdentity(); 1185 try { 1186 synchronized (mGlobalLock) { 1187 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1188 if (r != null) { 1189 r.reportFullyDrawnLocked(restoredFromBundle); 1190 } 1191 } 1192 } finally { 1193 Binder.restoreCallingIdentity(origId); 1194 } 1195 } 1196 1197 @Override overridePendingTransition(IBinder token, String packageName, int enterAnim, int exitAnim, @ColorInt int backgroundColor)1198 public void overridePendingTransition(IBinder token, String packageName, 1199 int enterAnim, int exitAnim, @ColorInt int backgroundColor) { 1200 final long origId = Binder.clearCallingIdentity(); 1201 synchronized (mGlobalLock) { 1202 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1203 if (r != null && r.isState(RESUMED, PAUSING)) { 1204 r.mDisplayContent.mAppTransition.overridePendingAppTransition( 1205 packageName, enterAnim, exitAnim, backgroundColor, null, null, 1206 r.mOverrideTaskTransition); 1207 r.mTransitionController.setOverrideAnimation( 1208 TransitionInfo.AnimationOptions.makeCustomAnimOptions(packageName, 1209 enterAnim, exitAnim, backgroundColor, r.mOverrideTaskTransition), 1210 null /* startCallback */, null /* finishCallback */); 1211 } 1212 } 1213 Binder.restoreCallingIdentity(origId); 1214 } 1215 1216 @Override setVrMode(IBinder token, boolean enabled, ComponentName packageName)1217 public int setVrMode(IBinder token, boolean enabled, ComponentName packageName) { 1218 mService.enforceSystemHasVrFeature(); 1219 1220 final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class); 1221 final ActivityRecord r; 1222 synchronized (mGlobalLock) { 1223 r = ActivityRecord.isInRootTaskLocked(token); 1224 } 1225 if (r == null) { 1226 throw new IllegalArgumentException(); 1227 } 1228 1229 final int err; 1230 if ((err = vrService.hasVrPackage(packageName, r.mUserId)) != VrManagerInternal.NO_ERROR) { 1231 return err; 1232 } 1233 1234 // Clear the binder calling uid since this path may call moveToTask(). 1235 final long callingId = Binder.clearCallingIdentity(); 1236 try { 1237 synchronized (mGlobalLock) { 1238 r.requestedVrComponent = (enabled) ? packageName : null; 1239 1240 // Update associated state if this activity is currently focused. 1241 if (r.isFocusedActivityOnDisplay()) { 1242 mService.applyUpdateVrModeLocked(r); 1243 } 1244 return 0; 1245 } 1246 } finally { 1247 Binder.restoreCallingIdentity(callingId); 1248 } 1249 } 1250 1251 @Override setRecentsScreenshotEnabled(IBinder token, boolean enabled)1252 public void setRecentsScreenshotEnabled(IBinder token, boolean enabled) { 1253 final long origId = Binder.clearCallingIdentity(); 1254 try { 1255 synchronized (mGlobalLock) { 1256 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1257 if (r != null) { 1258 r.setRecentsScreenshotEnabled(enabled); 1259 } 1260 } 1261 } finally { 1262 Binder.restoreCallingIdentity(origId); 1263 } 1264 } 1265 restartActivityProcessIfVisible(IBinder token)1266 void restartActivityProcessIfVisible(IBinder token) { 1267 ActivityTaskManagerService.enforceTaskPermission("restartActivityProcess"); 1268 final long callingId = Binder.clearCallingIdentity(); 1269 try { 1270 synchronized (mGlobalLock) { 1271 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1272 if (r != null) { 1273 r.restartProcessIfVisible(); 1274 } 1275 } 1276 } finally { 1277 Binder.restoreCallingIdentity(callingId); 1278 } 1279 } 1280 1281 /** 1282 * Removes the outdated home task snapshot. 1283 * 1284 * @param token The token of the home task, or null if you have the 1285 * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS} 1286 * permission and want us to find the home task token for you. 1287 */ 1288 @Override invalidateHomeTaskSnapshot(IBinder token)1289 public void invalidateHomeTaskSnapshot(IBinder token) { 1290 if (token == null) { 1291 ActivityTaskManagerService.enforceTaskPermission("invalidateHomeTaskSnapshot"); 1292 } 1293 1294 synchronized (mGlobalLock) { 1295 final ActivityRecord r; 1296 if (token == null) { 1297 final Task rootTask = 1298 mService.mRootWindowContainer.getDefaultTaskDisplayArea().getRootHomeTask(); 1299 r = rootTask != null ? rootTask.topRunningActivity() : null; 1300 } else { 1301 r = ActivityRecord.isInRootTaskLocked(token); 1302 } 1303 1304 if (r != null && r.isActivityTypeHome()) { 1305 mService.mWindowManager.mTaskSnapshotController.removeSnapshotCache( 1306 r.getTask().mTaskId); 1307 } 1308 } 1309 } 1310 1311 @Override dismissKeyguard(IBinder token, IKeyguardDismissCallback callback, CharSequence message)1312 public void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback, 1313 CharSequence message) { 1314 if (message != null) { 1315 mService.mAmInternal.enforceCallingPermission( 1316 android.Manifest.permission.SHOW_KEYGUARD_MESSAGE, "dismissKeyguard"); 1317 } 1318 final long callingId = Binder.clearCallingIdentity(); 1319 try { 1320 synchronized (mGlobalLock) { 1321 mService.mKeyguardController.dismissKeyguard(token, callback, message); 1322 } 1323 } finally { 1324 Binder.restoreCallingIdentity(callingId); 1325 } 1326 } 1327 1328 @Override registerRemoteAnimations(IBinder token, RemoteAnimationDefinition definition)1329 public void registerRemoteAnimations(IBinder token, RemoteAnimationDefinition definition) { 1330 mService.mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, 1331 "registerRemoteAnimations"); 1332 definition.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid()); 1333 final long origId = Binder.clearCallingIdentity(); 1334 try { 1335 synchronized (mGlobalLock) { 1336 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1337 if (r != null) { 1338 r.registerRemoteAnimations(definition); 1339 } 1340 } 1341 } finally { 1342 Binder.restoreCallingIdentity(origId); 1343 } 1344 } 1345 1346 @Override unregisterRemoteAnimations(IBinder token)1347 public void unregisterRemoteAnimations(IBinder token) { 1348 mService.mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, 1349 "unregisterRemoteAnimations"); 1350 final long origId = Binder.clearCallingIdentity(); 1351 try { 1352 synchronized (mGlobalLock) { 1353 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1354 if (r != null) { 1355 r.unregisterRemoteAnimations(); 1356 } 1357 } 1358 } finally { 1359 Binder.restoreCallingIdentity(origId); 1360 } 1361 } 1362 1363 /** 1364 * Return {@code true} when the given Activity is a relative Task root. That is, the rest of 1365 * the Activities in the Task should be finished when it finishes. Otherwise, return {@code 1366 * false}. 1367 */ isRelativeTaskRootActivity(ActivityRecord r, ActivityRecord taskRoot)1368 private boolean isRelativeTaskRootActivity(ActivityRecord r, ActivityRecord taskRoot) { 1369 // Not a relative root if the given Activity is not the root Activity of its TaskFragment. 1370 final TaskFragment taskFragment = r.getTaskFragment(); 1371 if (r != taskFragment.getActivity(ar -> !ar.finishing || ar == r, 1372 false /* traverseTopToBottom */)) { 1373 return false; 1374 } 1375 1376 // The given Activity is the relative Task root if its TaskFragment is a companion 1377 // TaskFragment to the taskRoot (i.e. the taskRoot TF will be finished together). 1378 return taskRoot.getTaskFragment().getCompanionTaskFragment() == taskFragment; 1379 } 1380 isTopActivityInTaskFragment(ActivityRecord activity)1381 private boolean isTopActivityInTaskFragment(ActivityRecord activity) { 1382 return activity.getTaskFragment().topRunningActivity() == activity; 1383 } 1384 requestCallbackFinish(IRequestFinishCallback callback)1385 private void requestCallbackFinish(IRequestFinishCallback callback) { 1386 try { 1387 callback.requestFinish(); 1388 } catch (RemoteException e) { 1389 Slog.e(TAG, "Failed to invoke request finish callback", e); 1390 } 1391 } 1392 1393 @Override onBackPressed(IBinder token, IRequestFinishCallback callback)1394 public void onBackPressed(IBinder token, IRequestFinishCallback callback) { 1395 final long origId = Binder.clearCallingIdentity(); 1396 try { 1397 final Intent baseActivityIntent; 1398 final boolean launchedFromHome; 1399 final boolean isLastRunningActivity; 1400 synchronized (mGlobalLock) { 1401 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); 1402 if (r == null) return; 1403 1404 final Task task = r.getTask(); 1405 final ActivityRecord root = task.getRootActivity(false /*ignoreRelinquishIdentity*/, 1406 true /*setToBottomIfNone*/); 1407 final boolean isTaskRoot = r == root; 1408 if (isTaskRoot) { 1409 if (mService.mWindowOrganizerController.mTaskOrganizerController 1410 .handleInterceptBackPressedOnTaskRoot(r.getRootTask())) { 1411 // This task is handled by a task organizer that has requested the back 1412 // pressed callback. 1413 return; 1414 } 1415 } else if (!isRelativeTaskRootActivity(r, root)) { 1416 // Finish the Activity if the activity is not the task root or relative root. 1417 requestCallbackFinish(callback); 1418 return; 1419 } 1420 1421 isLastRunningActivity = isTopActivityInTaskFragment(isTaskRoot ? root : r); 1422 1423 final boolean isBaseActivity = root.mActivityComponent.equals(task.realActivity); 1424 baseActivityIntent = isBaseActivity ? root.intent : null; 1425 1426 launchedFromHome = root.isLaunchSourceType(ActivityRecord.LAUNCH_SOURCE_TYPE_HOME); 1427 } 1428 1429 // If the activity is one of the main entry points for the application, then we should 1430 // refrain from finishing the activity and instead move it to the back to keep it in 1431 // memory. The requirements for this are: 1432 // 1. The activity is the last running activity in the task. 1433 // 2. The current activity is the base activity for the task. 1434 // 3. a. If the activity was launched by the home process, we trust that its intent 1435 // was resolved, so we check if the it is a main intent for the application. 1436 // b. Otherwise, we query Package Manager to verify whether the activity is a 1437 // launcher activity for the application. 1438 if (baseActivityIntent != null && isLastRunningActivity 1439 && ((launchedFromHome && ActivityRecord.isMainIntent(baseActivityIntent)) 1440 || isLauncherActivity(baseActivityIntent.getComponent()))) { 1441 moveActivityTaskToBack(token, true /* nonRoot */); 1442 return; 1443 } 1444 1445 // The default option for handling the back button is to finish the Activity. 1446 requestCallbackFinish(callback); 1447 } finally { 1448 Binder.restoreCallingIdentity(origId); 1449 } 1450 } 1451 1452 /** 1453 * Queries PackageManager to see if the given activity is one of the main entry point for the 1454 * application. This should not be called with the WM lock held. 1455 */ 1456 @SuppressWarnings("unchecked") isLauncherActivity(@onNull ComponentName activity)1457 private boolean isLauncherActivity(@NonNull ComponentName activity) { 1458 final Intent queryIntent = new Intent(Intent.ACTION_MAIN); 1459 queryIntent.addCategory(Intent.CATEGORY_LAUNCHER); 1460 queryIntent.setPackage(activity.getPackageName()); 1461 try { 1462 final ParceledListSlice<ResolveInfo> resolved = 1463 mService.getPackageManager().queryIntentActivities( 1464 queryIntent, null, 0, mContext.getUserId()); 1465 if (resolved == null) return false; 1466 for (final ResolveInfo ri : resolved.getList()) { 1467 if (ri.getComponentInfo().getComponentName().equals(activity)) { 1468 return true; 1469 } 1470 } 1471 } catch (RemoteException e) { 1472 Slog.e(TAG, "Failed to query intent activities", e); 1473 } 1474 return false; 1475 } 1476 } 1477