• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.MANAGE_ACTIVITY_TASKS;
20 import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY;
21 import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
22 import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
23 import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
24 import static android.app.PendingIntent.FLAG_IMMUTABLE;
25 import static android.app.PendingIntent.FLAG_ONE_SHOT;
26 import static android.app.admin.DevicePolicyManager.EXTRA_RESTRICTION;
27 import static android.app.admin.DevicePolicyManager.POLICY_SUSPEND_PACKAGES;
28 import static android.content.Context.KEYGUARD_SERVICE;
29 import static android.content.Intent.ACTION_MAIN;
30 import static android.content.Intent.CATEGORY_HOME;
31 import static android.content.Intent.CATEGORY_SECONDARY_HOME;
32 import static android.content.Intent.EXTRA_INTENT;
33 import static android.content.Intent.EXTRA_PACKAGE_NAME;
34 import static android.content.Intent.EXTRA_TASK_ID;
35 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
36 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
37 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
38 import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
39 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
40 
41 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
42 
43 import android.annotation.Nullable;
44 import android.app.ActivityOptions;
45 import android.app.KeyguardManager;
46 import android.app.TaskInfo;
47 import android.app.admin.DevicePolicyManagerInternal;
48 import android.content.ComponentName;
49 import android.content.Context;
50 import android.content.IIntentSender;
51 import android.content.Intent;
52 import android.content.IntentSender;
53 import android.content.pm.ActivityInfo;
54 import android.content.pm.PackageManagerInternal;
55 import android.content.pm.ResolveInfo;
56 import android.content.pm.SuspendDialogInfo;
57 import android.content.pm.UserInfo;
58 import android.content.pm.UserPackage;
59 import android.os.Bundle;
60 import android.os.IBinder;
61 import android.os.RemoteException;
62 import android.os.UserHandle;
63 import android.os.UserManager;
64 import android.util.Pair;
65 import android.util.Slog;
66 import android.util.SparseArray;
67 
68 import com.android.internal.annotations.VisibleForTesting;
69 import com.android.internal.app.BlockedAppActivity;
70 import com.android.internal.app.HarmfulAppWarningActivity;
71 import com.android.internal.app.SuspendedAppActivity;
72 import com.android.internal.app.UnlaunchableAppActivity;
73 import com.android.server.LocalServices;
74 import com.android.server.am.ActivityManagerService;
75 import com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptResult;
76 
77 /**
78  * A class that contains activity intercepting logic for {@link ActivityStarter#execute()}
79  * It's initialized via setStates and interception occurs via the intercept method.
80  *
81  * Note that this class is instantiated when {@link ActivityManagerService} gets created so there
82  * is no guarantee that other system services are already present.
83  */
84 class ActivityStartInterceptor {
85     private static final String TAG = "ActivityStartInterceptor";
86 
87     private final ActivityTaskManagerService mService;
88     private final ActivityTaskSupervisor mSupervisor;
89     private final Context mServiceContext;
90 
91     // UserManager cannot be final as it's not ready when this class is instantiated during boot
92     private UserManager mUserManager;
93 
94     /*
95      * Per-intent states loaded from ActivityStarter than shouldn't be changed by any
96      * interception routines.
97      */
98     private int mRealCallingPid;
99     private int mRealCallingUid;
100     private int mUserId;
101     private int mStartFlags;
102     private String mCallingPackage;
103     private @Nullable String mCallingFeatureId;
104 
105     /*
106      * Per-intent states that were load from ActivityStarter and are subject to modifications
107      * by the interception routines. After calling {@link #intercept} the caller should assign
108      * these values back to {@link ActivityStarter#startActivityLocked}'s local variables if
109      * {@link #intercept} returns true.
110      */
111     Intent mIntent;
112     int mCallingPid;
113     int mCallingUid;
114     ResolveInfo mRInfo;
115     ActivityInfo mAInfo;
116     String mResolvedType;
117     Task mInTask;
118     TaskFragment mInTaskFragment;
119     ActivityOptions mActivityOptions;
120 
121     /*
122      * Note that this is just a hint of what the launch display area will be as it is
123      * based only on the information at the early pre-interception stage of starting the
124      * intent. The real launch display area calculated later may be different from this one.
125      */
126     TaskDisplayArea mPresumableLaunchDisplayArea;
127 
128     /**
129      * Whether the component is specified originally in the given Intent.
130      */
131     boolean mComponentSpecified;
132 
ActivityStartInterceptor( ActivityTaskManagerService service, ActivityTaskSupervisor supervisor)133     ActivityStartInterceptor(
134             ActivityTaskManagerService service, ActivityTaskSupervisor supervisor) {
135         this(service, supervisor, service.mContext);
136     }
137 
138     @VisibleForTesting
ActivityStartInterceptor(ActivityTaskManagerService service, ActivityTaskSupervisor supervisor, Context context)139     ActivityStartInterceptor(ActivityTaskManagerService service, ActivityTaskSupervisor supervisor,
140             Context context) {
141         mService = service;
142         mSupervisor = supervisor;
143         mServiceContext = context;
144     }
145 
146     /**
147      * Effectively initialize the class before intercepting the start intent. The values set in this
148      * method should not be changed during intercept.
149      */
setStates(int userId, int realCallingPid, int realCallingUid, int startFlags, String callingPackage, @Nullable String callingFeatureId)150     void setStates(int userId, int realCallingPid, int realCallingUid, int startFlags,
151             String callingPackage, @Nullable String callingFeatureId) {
152         mRealCallingPid = realCallingPid;
153         mRealCallingUid = realCallingUid;
154         mUserId = userId;
155         mStartFlags = startFlags;
156         mCallingPackage = callingPackage;
157         mCallingFeatureId = callingFeatureId;
158     }
159 
createIntentSenderForOriginalIntent(int callingUid, int flags)160     private IntentSender createIntentSenderForOriginalIntent(int callingUid, int flags) {
161         ActivityOptions activityOptions = deferCrossProfileAppsAnimationIfNecessary();
162         activityOptions.setPendingIntentCreatorBackgroundActivityStartMode(
163                 MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
164         final TaskFragment taskFragment = getLaunchTaskFragment();
165         // If the original intent is going to be embedded, try to forward the embedding TaskFragment
166         // and its task id to embed back the original intent.
167         if (taskFragment != null) {
168             activityOptions.setLaunchTaskFragmentToken(taskFragment.getFragmentToken());
169         }
170         final IIntentSender target = mService.getIntentSenderLocked(
171                 INTENT_SENDER_ACTIVITY, mCallingPackage, mCallingFeatureId, callingUid, mUserId,
172                 null /*token*/, null /*resultCode*/, 0 /*requestCode*/,
173                 new Intent[] { mIntent }, new String[] { mResolvedType },
174                 flags, activityOptions.toBundle());
175         return new IntentSender(target);
176     }
177 
178 
179     /**
180      * A helper function to obtain the targeted {@link TaskFragment} during
181      * {@link #intercept(Intent, ResolveInfo, ActivityInfo, String, Task, TaskFragment, int, int,
182      * ActivityOptions, TaskDisplayArea)} if any.
183      */
184     @Nullable
getLaunchTaskFragment()185     private TaskFragment getLaunchTaskFragment() {
186         if (mInTaskFragment != null) {
187             return mInTaskFragment;
188         }
189         if (mActivityOptions == null) {
190             return null;
191         }
192         final IBinder taskFragToken = mActivityOptions.getLaunchTaskFragmentToken();
193         if (taskFragToken == null) {
194             return null;
195         }
196         return TaskFragment.fromTaskFragmentToken(taskFragToken, mService);
197     }
198 
199     // TODO: consolidate this method with the one below since this is used for test only.
intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType, Task inTask, TaskFragment inTaskFragment, int callingPid, int callingUid, ActivityOptions activityOptions, TaskDisplayArea presumableLaunchDisplayArea)200     boolean intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType,
201             Task inTask, TaskFragment inTaskFragment, int callingPid, int callingUid,
202             ActivityOptions activityOptions, TaskDisplayArea presumableLaunchDisplayArea) {
203         return intercept(intent, rInfo, aInfo, resolvedType, inTask, inTaskFragment, callingPid,
204                 callingUid, activityOptions, presumableLaunchDisplayArea, false);
205     }
206 
207     /**
208      * Intercept the launch intent based on various signals. If an interception happened the
209      * internal variables get assigned and need to be read explicitly by the caller.
210      *
211      * @return true if an interception occurred
212      */
intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType, Task inTask, TaskFragment inTaskFragment, int callingPid, int callingUid, ActivityOptions activityOptions, TaskDisplayArea presumableLaunchDisplayArea, boolean componentSpecified)213     boolean intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType,
214             Task inTask, TaskFragment inTaskFragment, int callingPid, int callingUid,
215             ActivityOptions activityOptions, TaskDisplayArea presumableLaunchDisplayArea,
216             boolean componentSpecified) {
217         mUserManager = UserManager.get(mServiceContext);
218 
219         mIntent = intent;
220         mCallingPid = callingPid;
221         mCallingUid = callingUid;
222         mRInfo = rInfo;
223         mAInfo = aInfo;
224         mResolvedType = resolvedType;
225         mInTask = inTask;
226         mInTaskFragment = inTaskFragment;
227         mActivityOptions = activityOptions;
228         mPresumableLaunchDisplayArea = presumableLaunchDisplayArea;
229         mComponentSpecified = componentSpecified;
230 
231         if (interceptQuietProfileIfNeeded()) {
232             // If work profile is turned off, skip the work challenge since the profile can only
233             // be unlocked when profile's user is running.
234             return true;
235         }
236         if (interceptSuspendedPackageIfNeeded()) {
237             // Skip the rest of interceptions as the package is suspended by device admin so
238             // no user action can undo this.
239             return true;
240         }
241         if (interceptLockTaskModeViolationPackageIfNeeded()) {
242             return true;
243         }
244         if (interceptHarmfulAppIfNeeded()) {
245             // If the app has a "harmful app" warning associated with it, we should ask to uninstall
246             // before issuing the work challenge.
247             return true;
248         }
249         if (interceptLockedProfileIfNeeded()) {
250             return true;
251         }
252         if (interceptHomeIfNeeded()) {
253             // Replace primary home intents directed at displays that do not support primary home
254             // but support secondary home with the relevant secondary home activity. Or the home
255             // intent is not in the correct format.
256             return true;
257         }
258 
259         final SparseArray<ActivityInterceptorCallback> callbacks =
260                 mService.getActivityInterceptorCallbacks();
261         final ActivityInterceptorCallback.ActivityInterceptorInfo interceptorInfo =
262                 getInterceptorInfo(null /* clearOptionsAnimation */);
263 
264         for (int i = 0; i < callbacks.size(); i++) {
265             final ActivityInterceptorCallback callback = callbacks.valueAt(i);
266             final ActivityInterceptResult interceptResult = callback.onInterceptActivityLaunch(
267                     interceptorInfo);
268             if (interceptResult == null) {
269                 continue;
270             }
271             mIntent = interceptResult.getIntent();
272             mActivityOptions = interceptResult.getActivityOptions();
273             mCallingPid = mRealCallingPid;
274             mCallingUid = mRealCallingUid;
275             // When an activity launch is intercepted, Intent#prepareToLeaveProcess is not called
276             // since the interception happens in the system_server. So if any activity is calling
277             // a trampoline activity, the keys do not get collected. Since all the interceptors
278             // are present in the system_server, add the creator token before launching the
279             // intercepted intent.
280             mService.mAmInternal.addCreatorToken(mIntent, mCallingPackage);
281             if (interceptResult.isActivityResolved()) {
282                 return true;
283             }
284             mRInfo = mSupervisor.resolveIntent(mIntent, null, mUserId, 0,
285                     mRealCallingUid, mRealCallingPid);
286             mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags,
287                     null /*profilerInfo*/);
288             return true;
289         }
290         return false;
291     }
292 
hasCrossProfileAnimation()293     private boolean hasCrossProfileAnimation() {
294         return mActivityOptions != null
295                 && mActivityOptions.getAnimationType() == ANIM_OPEN_CROSS_PROFILE_APPS;
296     }
297 
298     /**
299      * If the activity option is the {@link ActivityOptions#ANIM_OPEN_CROSS_PROFILE_APPS} one,
300      * defer the animation until the original intent is started.
301      *
302      * @return the activity option used to start the original intent.
303      */
deferCrossProfileAppsAnimationIfNecessary()304     private ActivityOptions deferCrossProfileAppsAnimationIfNecessary() {
305         if (hasCrossProfileAnimation()) {
306             mActivityOptions = null;
307             return ActivityOptions.makeOpenCrossProfileAppsAnimation();
308         }
309         return ActivityOptions.makeBasic();
310     }
311 
interceptQuietProfileIfNeeded()312     private boolean interceptQuietProfileIfNeeded() {
313         // Do not intercept if the user has not turned off the profile
314         if (!mUserManager.isQuietModeEnabled(UserHandle.of(mUserId))) {
315             return false;
316         }
317         Slog.i(TAG, "Intent : " + mIntent + " intercepted for user: " + mUserId
318                 + " because quiet mode is enabled.");
319 
320         IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
321                 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT);
322 
323         mIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId, target, mRInfo);
324         mCallingPid = mRealCallingPid;
325         mCallingUid = mRealCallingUid;
326         mResolvedType = null;
327 
328         final UserInfo parent = mUserManager.getProfileParent(mUserId);
329         mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0,
330                 mRealCallingUid, mRealCallingPid);
331         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
332         return true;
333     }
334 
interceptSuspendedByAdminPackage()335     private boolean interceptSuspendedByAdminPackage() {
336         DevicePolicyManagerInternal devicePolicyManager = LocalServices
337                 .getService(DevicePolicyManagerInternal.class);
338         if (devicePolicyManager == null) {
339             return false;
340         }
341         mIntent = devicePolicyManager.createShowAdminSupportIntent(mUserId, true);
342         mIntent.putExtra(EXTRA_RESTRICTION, POLICY_SUSPEND_PACKAGES);
343 
344         mCallingPid = mRealCallingPid;
345         mCallingUid = mRealCallingUid;
346         mResolvedType = null;
347 
348         final UserInfo parent = mUserManager.getProfileParent(mUserId);
349         if (parent != null) {
350             mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0,
351                     mRealCallingUid, mRealCallingPid);
352         } else {
353             mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0,
354                     mRealCallingUid, mRealCallingPid);
355         }
356         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
357         return true;
358     }
359 
interceptSuspendedPackageIfNeeded()360     private boolean interceptSuspendedPackageIfNeeded() {
361         // Do not intercept if the package is not suspended
362         if (!isPackageSuspended()) {
363             return false;
364         }
365         final PackageManagerInternal pmi = mService.getPackageManagerInternalLocked();
366         if (pmi == null) {
367             return false;
368         }
369         final String suspendedPackage = mAInfo.applicationInfo.packageName;
370         final UserPackage suspender = pmi.getSuspendingPackage(suspendedPackage, mUserId);
371         if (suspender != null && PLATFORM_PACKAGE_NAME.equals(suspender.packageName)) {
372             return interceptSuspendedByAdminPackage();
373         }
374         final SuspendDialogInfo dialogInfo = pmi.getSuspendedDialogInfo(suspendedPackage,
375                 suspender, mUserId);
376         final Bundle crossProfileOptions = hasCrossProfileAnimation()
377                 ? ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle()
378                 : null;
379         final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
380                 FLAG_IMMUTABLE);
381         mIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(suspendedPackage,
382                 suspender, dialogInfo, crossProfileOptions, target, mUserId);
383         mCallingPid = mRealCallingPid;
384         mCallingUid = mRealCallingUid;
385         mResolvedType = null;
386         mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0,
387                 mRealCallingUid, mRealCallingPid);
388         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
389         return true;
390     }
391 
interceptLockTaskModeViolationPackageIfNeeded()392     private boolean interceptLockTaskModeViolationPackageIfNeeded() {
393         if (mAInfo == null || mAInfo.applicationInfo == null) {
394             return false;
395         }
396         LockTaskController controller = mService.getLockTaskController();
397         String packageName = mAInfo.applicationInfo.packageName;
398         int lockTaskLaunchMode = ActivityRecord.getLockTaskLaunchMode(mAInfo, mActivityOptions);
399         if (controller.isActivityAllowed(mUserId, packageName, lockTaskLaunchMode)) {
400             return false;
401         }
402         mIntent = BlockedAppActivity.createIntent(mUserId, mAInfo.applicationInfo.packageName);
403         mCallingPid = mRealCallingPid;
404         mCallingUid = mRealCallingUid;
405         mResolvedType = null;
406         mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0,
407                 mRealCallingUid, mRealCallingPid);
408         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
409         return true;
410     }
411 
interceptLockedProfileIfNeeded()412     private boolean interceptLockedProfileIfNeeded() {
413         final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mAInfo, mUserId);
414         if (interceptingIntent == null) {
415             return false;
416         }
417         mIntent = interceptingIntent;
418         mCallingPid = mRealCallingPid;
419         mCallingUid = mRealCallingUid;
420         mResolvedType = null;
421         final TaskFragment taskFragment = getLaunchTaskFragment();
422         // If we are intercepting and there was a task, convert it into an extra for the
423         // ConfirmCredentials intent and unassign it, as otherwise the task will move to
424         // front even if ConfirmCredentials is cancelled.
425         if (mInTask != null) {
426             mIntent.putExtra(EXTRA_TASK_ID, mInTask.mTaskId);
427             mInTask = null;
428         } else if (taskFragment != null) {
429             // If the original intent is started to an embedded TaskFragment, append its parent task
430             // id to extra. It is to embed back the original intent to the TaskFragment with the
431             // same task.
432             final Task parentTask = taskFragment.getTask();
433             if (parentTask != null) {
434                 mIntent.putExtra(EXTRA_TASK_ID, parentTask.mTaskId);
435             }
436         }
437         if (mActivityOptions == null) {
438             mActivityOptions = ActivityOptions.makeBasic();
439         }
440 
441         final UserInfo parent = mUserManager.getProfileParent(mUserId);
442         mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0,
443                 mRealCallingUid, mRealCallingPid);
444         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
445         return true;
446     }
447 
448     /**
449      * Creates an intent to intercept the current activity start with Confirm Credentials if needed.
450      *
451      * @return The intercepting intent if needed.
452      */
interceptWithConfirmCredentialsIfNeeded(ActivityInfo aInfo, int userId)453     private Intent interceptWithConfirmCredentialsIfNeeded(ActivityInfo aInfo, int userId) {
454         if (!mService.mAmInternal.shouldConfirmCredentials(userId)) {
455             return null;
456         }
457         if ((aInfo.flags & ActivityInfo.FLAG_SHOW_WHEN_LOCKED) != 0
458                 && (mUserManager.isUserUnlocked(userId) || aInfo.directBootAware)) {
459             return null;
460         }
461         final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
462                 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE);
463         final KeyguardManager km = (KeyguardManager) mServiceContext
464                 .getSystemService(KEYGUARD_SERVICE);
465         final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, userId,
466                 true /* disallowBiometricsIfPolicyExists */);
467         if (newIntent == null) {
468             return null;
469         }
470         newIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
471                 FLAG_ACTIVITY_TASK_ON_HOME);
472         newIntent.putExtra(EXTRA_PACKAGE_NAME, aInfo.packageName);
473         newIntent.putExtra(EXTRA_INTENT, target);
474         return newIntent;
475     }
476 
interceptHarmfulAppIfNeeded()477     private boolean interceptHarmfulAppIfNeeded() {
478         CharSequence harmfulAppWarning;
479         try {
480             harmfulAppWarning = mService.getPackageManager()
481                     .getHarmfulAppWarning(mAInfo.packageName, mUserId);
482         } catch (RemoteException | IllegalArgumentException ex) {
483             return false;
484         }
485 
486         if (harmfulAppWarning == null) {
487             return false;
488         }
489 
490         final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
491                 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE);
492 
493         mIntent = HarmfulAppWarningActivity.createHarmfulAppWarningIntent(mServiceContext,
494                 mAInfo.packageName, target, harmfulAppWarning);
495 
496         mCallingPid = mRealCallingPid;
497         mCallingUid = mRealCallingUid;
498         mResolvedType = null;
499 
500         mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0,
501                 mRealCallingUid, mRealCallingPid);
502         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
503         return true;
504     }
505 
interceptHomeIfNeeded()506     private boolean interceptHomeIfNeeded() {
507         if (mPresumableLaunchDisplayArea == null || mService.mRootWindowContainer == null) {
508             return false;
509         }
510 
511         boolean intercepted = false;
512         if (!ACTION_MAIN.equals(mIntent.getAction()) || (!mIntent.hasCategory(CATEGORY_HOME)
513                 && !mIntent.hasCategory(CATEGORY_SECONDARY_HOME))) {
514             // not a home intent
515             return false;
516         }
517 
518         if (mComponentSpecified) {
519             Slog.w(TAG, "Starting home with component specified, uid=" + mCallingUid);
520             if (mService.isCallerRecents(mCallingUid)
521                     || ActivityTaskManagerService.checkPermission(MANAGE_ACTIVITY_TASKS,
522                     mCallingPid, mCallingUid) == PERMISSION_GRANTED) {
523                 // Allow home component specified from trusted callers.
524                 return false;
525             }
526 
527             final ComponentName homeComponent = mIntent.getComponent();
528             final Intent homeIntent = mService.getHomeIntent();
529             final ActivityInfo aInfo = mService.mRootWindowContainer.resolveHomeActivity(
530                     mUserId, homeIntent);
531             if (!aInfo.getComponentName().equals(homeComponent)) {
532                 // Do nothing if the intent is not for the default home component.
533                 return false;
534             }
535         }
536 
537         if (!ActivityRecord.isHomeIntent(mIntent) || mComponentSpecified) {
538             // This is not a standard home intent, make it so if possible.
539             normalizeHomeIntent();
540             intercepted = true;
541         }
542 
543         intercepted |= replaceToSecondaryHomeIntentIfNeeded();
544         if (intercepted) {
545             mCallingPid = mRealCallingPid;
546             mCallingUid = mRealCallingUid;
547             mResolvedType = null;
548 
549             mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, /* flags= */ 0,
550                     mRealCallingUid, mRealCallingPid);
551             mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, /*profilerInfo=*/
552                     null);
553         }
554         return intercepted;
555     }
556 
normalizeHomeIntent()557     private void normalizeHomeIntent() {
558         Slog.w(TAG, "The home Intent is not correctly formatted");
559         if (mIntent.getCategories().size() > 1) {
560             Slog.d(TAG, "Purge home intent categories");
561             boolean isSecondaryHome = false;
562             final Object[] categories = mIntent.getCategories().toArray();
563             for (int i = categories.length - 1; i >= 0; i--) {
564                 final String category = (String) categories[i];
565                 if (CATEGORY_SECONDARY_HOME.equals(category)) {
566                     isSecondaryHome = true;
567                 }
568                 mIntent.removeCategory(category);
569             }
570             mIntent.addCategory(isSecondaryHome ? CATEGORY_SECONDARY_HOME : CATEGORY_HOME);
571         }
572         if (mIntent.getType() != null || mIntent.getData() != null) {
573             Slog.d(TAG, "Purge home intent data/type");
574             mIntent.setType(null);
575         }
576         if (mComponentSpecified) {
577             Slog.d(TAG, "Purge home intent component, " + mIntent.getComponent());
578             mIntent.setComponent(null);
579         }
580         mIntent.addFlags(FLAG_ACTIVITY_NEW_TASK);
581     }
582 
replaceToSecondaryHomeIntentIfNeeded()583     private boolean replaceToSecondaryHomeIntentIfNeeded() {
584         if (!mIntent.hasCategory(Intent.CATEGORY_HOME)) {
585             // Already a secondary home intent, leave it alone.
586             return false;
587         }
588         if (mService.mRootWindowContainer.shouldPlacePrimaryHomeOnDisplay(
589                 mPresumableLaunchDisplayArea.getDisplayId())) {
590             // Primary home can be launched to the display area.
591             return false;
592         }
593         if (!mService.mRootWindowContainer.shouldPlaceSecondaryHomeOnDisplayArea(
594                 mPresumableLaunchDisplayArea)) {
595             // Secondary home cannot be launched on the display area.
596             return false;
597         }
598 
599         // At this point we have a primary home intent for a display that does not support primary
600         // home activity but it supports secondary home one. So replace it with secondary home.
601         Pair<ActivityInfo, Intent> info = mService.mRootWindowContainer
602                 .resolveSecondaryHomeActivity(mUserId, mPresumableLaunchDisplayArea);
603         mIntent = info.second;
604         // The new task flag is needed because the home activity should already be in the root task
605         // and should not be moved to the caller's task. Also, activities cannot change their type,
606         // e.g. a standard activity cannot become a home activity.
607         mIntent.addFlags(FLAG_ACTIVITY_NEW_TASK);
608         return true;
609     }
610 
isPackageSuspended()611     private boolean isPackageSuspended() {
612         return mAInfo != null && mAInfo.applicationInfo != null
613                 && (mAInfo.applicationInfo.flags & FLAG_SUSPENDED) != 0;
614     }
615 
616     /**
617      * Called when an activity is successfully launched.
618      */
onActivityLaunched(TaskInfo taskInfo, ActivityRecord r)619     void onActivityLaunched(TaskInfo taskInfo, ActivityRecord r) {
620         final SparseArray<ActivityInterceptorCallback> callbacks =
621                 mService.getActivityInterceptorCallbacks();
622         final ActivityInterceptorCallback.ActivityInterceptorInfo info = getInterceptorInfo(() -> {
623             synchronized (mService.mGlobalLock) {
624                 r.clearOptionsAnimationForSiblings();
625             }
626         });
627         for (int i = 0; i < callbacks.size(); i++) {
628             final ActivityInterceptorCallback callback = callbacks.valueAt(i);
629             callback.onActivityLaunched(taskInfo, r.info, info);
630         }
631     }
632 
getInterceptorInfo( @ullable Runnable clearOptionsAnimation)633     private ActivityInterceptorCallback.ActivityInterceptorInfo getInterceptorInfo(
634             @Nullable Runnable clearOptionsAnimation) {
635         return new ActivityInterceptorCallback.ActivityInterceptorInfo.Builder(mCallingUid,
636                 mCallingPid, mRealCallingUid, mRealCallingPid, mUserId, mIntent, mRInfo, mAInfo)
637                 .setResolvedType(mResolvedType)
638                 .setCallingPackage(mCallingPackage)
639                 .setCallingFeatureId(mCallingFeatureId)
640                 .setCheckedOptions(mActivityOptions)
641                 .setClearOptionsAnimationRunnable(clearOptionsAnimation)
642                 .build();
643     }
644 
645 }
646