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