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.app.ActivityManager.INTENT_SENDER_ACTIVITY; 20 import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS; 21 import static android.app.PendingIntent.FLAG_CANCEL_CURRENT; 22 import static android.app.PendingIntent.FLAG_IMMUTABLE; 23 import static android.app.PendingIntent.FLAG_ONE_SHOT; 24 import static android.app.admin.DevicePolicyManager.EXTRA_RESTRICTION; 25 import static android.app.admin.DevicePolicyManager.POLICY_SUSPEND_PACKAGES; 26 import static android.content.Context.KEYGUARD_SERVICE; 27 import static android.content.Intent.EXTRA_INTENT; 28 import static android.content.Intent.EXTRA_PACKAGE_NAME; 29 import static android.content.Intent.EXTRA_TASK_ID; 30 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; 31 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; 32 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; 33 import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED; 34 35 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; 36 37 import android.annotation.Nullable; 38 import android.app.ActivityOptions; 39 import android.app.KeyguardManager; 40 import android.app.admin.DevicePolicyManagerInternal; 41 import android.content.Context; 42 import android.content.IIntentSender; 43 import android.content.Intent; 44 import android.content.IntentSender; 45 import android.content.pm.ActivityInfo; 46 import android.content.pm.PackageManagerInternal; 47 import android.content.pm.ResolveInfo; 48 import android.content.pm.SuspendDialogInfo; 49 import android.content.pm.UserInfo; 50 import android.os.Bundle; 51 import android.os.RemoteException; 52 import android.os.UserHandle; 53 import android.os.UserManager; 54 55 import com.android.internal.annotations.VisibleForTesting; 56 import com.android.internal.app.BlockedAppActivity; 57 import com.android.internal.app.HarmfulAppWarningActivity; 58 import com.android.internal.app.SuspendedAppActivity; 59 import com.android.internal.app.UnlaunchableAppActivity; 60 import com.android.server.LocalServices; 61 import com.android.server.am.ActivityManagerService; 62 63 /** 64 * A class that contains activity intercepting logic for {@link ActivityStarter#startActivityLocked} 65 * It's initialized via setStates and interception occurs via the intercept method. 66 * 67 * Note that this class is instantiated when {@link ActivityManagerService} gets created so there 68 * is no guarantee that other system services are already present. 69 */ 70 class ActivityStartInterceptor { 71 72 private final ActivityTaskManagerService mService; 73 private final ActivityTaskSupervisor mSupervisor; 74 private final RootWindowContainer mRootWindowContainer; 75 private final Context mServiceContext; 76 77 // UserManager cannot be final as it's not ready when this class is instantiated during boot 78 private UserManager mUserManager; 79 80 /* 81 * Per-intent states loaded from ActivityStarter than shouldn't be changed by any 82 * interception routines. 83 */ 84 private int mRealCallingPid; 85 private int mRealCallingUid; 86 private int mUserId; 87 private int mStartFlags; 88 private String mCallingPackage; 89 private @Nullable String mCallingFeatureId; 90 91 /* 92 * Per-intent states that were load from ActivityStarter and are subject to modifications 93 * by the interception routines. After calling {@link #intercept} the caller should assign 94 * these values back to {@link ActivityStarter#startActivityLocked}'s local variables if 95 * {@link #intercept} returns true. 96 */ 97 Intent mIntent; 98 int mCallingPid; 99 int mCallingUid; 100 ResolveInfo mRInfo; 101 ActivityInfo mAInfo; 102 String mResolvedType; 103 Task mInTask; 104 ActivityOptions mActivityOptions; 105 ActivityStartInterceptor( ActivityTaskManagerService service, ActivityTaskSupervisor supervisor)106 ActivityStartInterceptor( 107 ActivityTaskManagerService service, ActivityTaskSupervisor supervisor) { 108 this(service, supervisor, service.mRootWindowContainer, service.mContext); 109 } 110 111 @VisibleForTesting ActivityStartInterceptor(ActivityTaskManagerService service, ActivityTaskSupervisor supervisor, RootWindowContainer root, Context context)112 ActivityStartInterceptor(ActivityTaskManagerService service, ActivityTaskSupervisor supervisor, 113 RootWindowContainer root, Context context) { 114 mService = service; 115 mSupervisor = supervisor; 116 mRootWindowContainer = root; 117 mServiceContext = context; 118 } 119 120 /** 121 * Effectively initialize the class before intercepting the start intent. The values set in this 122 * method should not be changed during intercept. 123 */ setStates(int userId, int realCallingPid, int realCallingUid, int startFlags, String callingPackage, @Nullable String callingFeatureId)124 void setStates(int userId, int realCallingPid, int realCallingUid, int startFlags, 125 String callingPackage, @Nullable String callingFeatureId) { 126 mRealCallingPid = realCallingPid; 127 mRealCallingUid = realCallingUid; 128 mUserId = userId; 129 mStartFlags = startFlags; 130 mCallingPackage = callingPackage; 131 mCallingFeatureId = callingFeatureId; 132 } 133 createIntentSenderForOriginalIntent(int callingUid, int flags)134 private IntentSender createIntentSenderForOriginalIntent(int callingUid, int flags) { 135 Bundle activityOptions = deferCrossProfileAppsAnimationIfNecessary(); 136 final IIntentSender target = mService.getIntentSenderLocked( 137 INTENT_SENDER_ACTIVITY, mCallingPackage, mCallingFeatureId, callingUid, mUserId, 138 null /*token*/, null /*resultCode*/, 0 /*requestCode*/, 139 new Intent[] { mIntent }, new String[] { mResolvedType }, 140 flags, activityOptions); 141 return new IntentSender(target); 142 } 143 144 /** 145 * Intercept the launch intent based on various signals. If an interception happened the 146 * internal variables get assigned and need to be read explicitly by the caller. 147 * 148 * @return true if an interception occurred 149 */ intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType, Task inTask, int callingPid, int callingUid, ActivityOptions activityOptions)150 boolean intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType, 151 Task inTask, int callingPid, int callingUid, ActivityOptions activityOptions) { 152 mUserManager = UserManager.get(mServiceContext); 153 154 mIntent = intent; 155 mCallingPid = callingPid; 156 mCallingUid = callingUid; 157 mRInfo = rInfo; 158 mAInfo = aInfo; 159 mResolvedType = resolvedType; 160 mInTask = inTask; 161 mActivityOptions = activityOptions; 162 163 if (interceptQuietProfileIfNeeded()) { 164 // If work profile is turned off, skip the work challenge since the profile can only 165 // be unlocked when profile's user is running. 166 return true; 167 } 168 if (interceptSuspendedPackageIfNeeded()) { 169 // Skip the rest of interceptions as the package is suspended by device admin so 170 // no user action can undo this. 171 return true; 172 } 173 if (interceptLockTaskModeViolationPackageIfNeeded()) { 174 return true; 175 } 176 if (interceptHarmfulAppIfNeeded()) { 177 // If the app has a "harmful app" warning associated with it, we should ask to uninstall 178 // before issuing the work challenge. 179 return true; 180 } 181 return interceptLockedManagedProfileIfNeeded(); 182 } 183 hasCrossProfileAnimation()184 private boolean hasCrossProfileAnimation() { 185 return mActivityOptions != null 186 && mActivityOptions.getAnimationType() == ANIM_OPEN_CROSS_PROFILE_APPS; 187 } 188 189 /** 190 * If the activity option is the {@link ActivityOptions#ANIM_OPEN_CROSS_PROFILE_APPS} one, 191 * defer the animation until the original intent is started. 192 * 193 * @return the activity option used to start the original intent. 194 */ deferCrossProfileAppsAnimationIfNecessary()195 private Bundle deferCrossProfileAppsAnimationIfNecessary() { 196 if (hasCrossProfileAnimation()) { 197 mActivityOptions = null; 198 return ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle(); 199 } 200 return null; 201 } 202 interceptQuietProfileIfNeeded()203 private boolean interceptQuietProfileIfNeeded() { 204 // Do not intercept if the user has not turned off the profile 205 if (!mUserManager.isQuietModeEnabled(UserHandle.of(mUserId))) { 206 return false; 207 } 208 209 IntentSender target = createIntentSenderForOriginalIntent(mCallingUid, 210 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT); 211 212 mIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId, target); 213 mCallingPid = mRealCallingPid; 214 mCallingUid = mRealCallingUid; 215 mResolvedType = null; 216 217 final UserInfo parent = mUserManager.getProfileParent(mUserId); 218 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0, mRealCallingUid); 219 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/); 220 return true; 221 } 222 interceptSuspendedByAdminPackage()223 private boolean interceptSuspendedByAdminPackage() { 224 DevicePolicyManagerInternal devicePolicyManager = LocalServices 225 .getService(DevicePolicyManagerInternal.class); 226 if (devicePolicyManager == null) { 227 return false; 228 } 229 mIntent = devicePolicyManager.createShowAdminSupportIntent(mUserId, true); 230 mIntent.putExtra(EXTRA_RESTRICTION, POLICY_SUSPEND_PACKAGES); 231 232 mCallingPid = mRealCallingPid; 233 mCallingUid = mRealCallingUid; 234 mResolvedType = null; 235 236 final UserInfo parent = mUserManager.getProfileParent(mUserId); 237 if (parent != null) { 238 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0, 239 mRealCallingUid); 240 } else { 241 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, 242 mRealCallingUid); 243 } 244 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/); 245 return true; 246 } 247 interceptSuspendedPackageIfNeeded()248 private boolean interceptSuspendedPackageIfNeeded() { 249 // Do not intercept if the package is not suspended 250 if (mAInfo == null || mAInfo.applicationInfo == null || 251 (mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) { 252 return false; 253 } 254 final PackageManagerInternal pmi = mService.getPackageManagerInternalLocked(); 255 if (pmi == null) { 256 return false; 257 } 258 final String suspendedPackage = mAInfo.applicationInfo.packageName; 259 final String suspendingPackage = pmi.getSuspendingPackage(suspendedPackage, mUserId); 260 if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) { 261 return interceptSuspendedByAdminPackage(); 262 } 263 final SuspendDialogInfo dialogInfo = pmi.getSuspendedDialogInfo(suspendedPackage, 264 suspendingPackage, mUserId); 265 final Bundle crossProfileOptions = hasCrossProfileAnimation() 266 ? ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle() 267 : null; 268 final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid, 269 FLAG_IMMUTABLE); 270 mIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(suspendedPackage, 271 suspendingPackage, dialogInfo, crossProfileOptions, target, mUserId); 272 mCallingPid = mRealCallingPid; 273 mCallingUid = mRealCallingUid; 274 mResolvedType = null; 275 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, mRealCallingUid); 276 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/); 277 return true; 278 } 279 interceptLockTaskModeViolationPackageIfNeeded()280 private boolean interceptLockTaskModeViolationPackageIfNeeded() { 281 if (mAInfo == null || mAInfo.applicationInfo == null) { 282 return false; 283 } 284 LockTaskController controller = mService.getLockTaskController(); 285 String packageName = mAInfo.applicationInfo.packageName; 286 int lockTaskLaunchMode = ActivityRecord.getLockTaskLaunchMode(mAInfo, mActivityOptions); 287 if (controller.isActivityAllowed(mUserId, packageName, lockTaskLaunchMode)) { 288 return false; 289 } 290 mIntent = BlockedAppActivity.createIntent(mUserId, mAInfo.applicationInfo.packageName); 291 mCallingPid = mRealCallingPid; 292 mCallingUid = mRealCallingUid; 293 mResolvedType = null; 294 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, mRealCallingUid); 295 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/); 296 return true; 297 } 298 interceptLockedManagedProfileIfNeeded()299 private boolean interceptLockedManagedProfileIfNeeded() { 300 final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mAInfo, mUserId); 301 if (interceptingIntent == null) { 302 return false; 303 } 304 mIntent = interceptingIntent; 305 mCallingPid = mRealCallingPid; 306 mCallingUid = mRealCallingUid; 307 mResolvedType = null; 308 // If we are intercepting and there was a task, convert it into an extra for the 309 // ConfirmCredentials intent and unassign it, as otherwise the task will move to 310 // front even if ConfirmCredentials is cancelled. 311 if (mInTask != null) { 312 mIntent.putExtra(EXTRA_TASK_ID, mInTask.mTaskId); 313 mInTask = null; 314 } 315 if (mActivityOptions == null) { 316 mActivityOptions = ActivityOptions.makeBasic(); 317 } 318 319 final UserInfo parent = mUserManager.getProfileParent(mUserId); 320 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0, mRealCallingUid); 321 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/); 322 return true; 323 } 324 325 /** 326 * Creates an intent to intercept the current activity start with Confirm Credentials if needed. 327 * 328 * @return The intercepting intent if needed. 329 */ interceptWithConfirmCredentialsIfNeeded(ActivityInfo aInfo, int userId)330 private Intent interceptWithConfirmCredentialsIfNeeded(ActivityInfo aInfo, int userId) { 331 if (!mService.mAmInternal.shouldConfirmCredentials(userId)) { 332 return null; 333 } 334 // TODO(b/28935539): should allow certain activities to bypass work challenge 335 final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid, 336 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE); 337 final KeyguardManager km = (KeyguardManager) mServiceContext 338 .getSystemService(KEYGUARD_SERVICE); 339 final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, userId, 340 true /* disallowBiometricsIfPolicyExists */); 341 if (newIntent == null) { 342 return null; 343 } 344 newIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | 345 FLAG_ACTIVITY_TASK_ON_HOME); 346 newIntent.putExtra(EXTRA_PACKAGE_NAME, aInfo.packageName); 347 newIntent.putExtra(EXTRA_INTENT, target); 348 return newIntent; 349 } 350 interceptHarmfulAppIfNeeded()351 private boolean interceptHarmfulAppIfNeeded() { 352 CharSequence harmfulAppWarning; 353 try { 354 harmfulAppWarning = mService.getPackageManager() 355 .getHarmfulAppWarning(mAInfo.packageName, mUserId); 356 } catch (RemoteException ex) { 357 return false; 358 } 359 360 if (harmfulAppWarning == null) { 361 return false; 362 } 363 364 final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid, 365 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE); 366 367 mIntent = HarmfulAppWarningActivity.createHarmfulAppWarningIntent(mServiceContext, 368 mAInfo.packageName, target, harmfulAppWarning); 369 370 mCallingPid = mRealCallingPid; 371 mCallingUid = mRealCallingUid; 372 mResolvedType = null; 373 374 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, mRealCallingUid); 375 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/); 376 return true; 377 } 378 } 379