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