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