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