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