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