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