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