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 17package com.android.server.am; 18 19import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY; 20import static android.app.PendingIntent.FLAG_CANCEL_CURRENT; 21import static android.app.PendingIntent.FLAG_IMMUTABLE; 22import static android.app.PendingIntent.FLAG_ONE_SHOT; 23import static android.content.Context.KEYGUARD_SERVICE; 24import static android.content.Intent.EXTRA_INTENT; 25import static android.content.Intent.EXTRA_PACKAGE_NAME; 26import static android.content.Intent.EXTRA_TASK_ID; 27import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; 28import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; 29import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; 30import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED; 31 32import android.app.ActivityManager; 33import android.app.ActivityOptions; 34import android.app.KeyguardManager; 35import android.app.admin.DevicePolicyManagerInternal; 36import android.content.IIntentSender; 37import android.content.Intent; 38import android.content.IntentSender; 39import android.content.pm.ActivityInfo; 40import android.content.pm.ResolveInfo; 41import android.content.pm.UserInfo; 42import android.os.Binder; 43import android.os.UserHandle; 44import android.os.UserManager; 45 46import com.android.internal.app.UnlaunchableAppActivity; 47import com.android.server.LocalServices; 48 49/** 50 * A class that contains activity intercepting logic for {@link ActivityStarter#startActivityLocked} 51 * It's initialized 52 */ 53class ActivityStartInterceptor { 54 55 private final ActivityManagerService mService; 56 private UserManager mUserManager; 57 private final ActivityStackSupervisor mSupervisor; 58 59 /* 60 * Per-intent states loaded from ActivityStarter than shouldn't be changed by any 61 * interception routines. 62 */ 63 private int mRealCallingPid; 64 private int mRealCallingUid; 65 private int mUserId; 66 private int mStartFlags; 67 private String mCallingPackage; 68 69 /* 70 * Per-intent states that were load from ActivityStarter and are subject to modifications 71 * by the interception routines. After calling {@link #intercept} the caller should assign 72 * these values back to {@link ActivityStarter#startActivityLocked}'s local variables. 73 */ 74 Intent mIntent; 75 int mCallingPid; 76 int mCallingUid; 77 ResolveInfo mRInfo; 78 ActivityInfo mAInfo; 79 String mResolvedType; 80 TaskRecord mInTask; 81 ActivityOptions mActivityOptions; 82 83 ActivityStartInterceptor(ActivityManagerService service, ActivityStackSupervisor supervisor) { 84 mService = service; 85 mSupervisor = supervisor; 86 } 87 88 void setStates(int userId, int realCallingPid, int realCallingUid, int startFlags, 89 String callingPackage) { 90 mRealCallingPid = realCallingPid; 91 mRealCallingUid = realCallingUid; 92 mUserId = userId; 93 mStartFlags = startFlags; 94 mCallingPackage = callingPackage; 95 } 96 97 void intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType, 98 TaskRecord inTask, int callingPid, int callingUid, ActivityOptions activityOptions) { 99 mUserManager = UserManager.get(mService.mContext); 100 mIntent = intent; 101 mCallingPid = callingPid; 102 mCallingUid = callingUid; 103 mRInfo = rInfo; 104 mAInfo = aInfo; 105 mResolvedType = resolvedType; 106 mInTask = inTask; 107 mActivityOptions = activityOptions; 108 if (interceptSuspendPackageIfNeed()) { 109 // Skip the rest of interceptions as the package is suspended by device admin so 110 // no user action can undo this. 111 return; 112 } 113 if (interceptQuietProfileIfNeeded()) { 114 // If work profile is turned off, skip the work challenge since the profile can only 115 // be unlocked when profile's user is running. 116 return; 117 } 118 interceptWorkProfileChallengeIfNeeded(); 119 } 120 121 private boolean interceptQuietProfileIfNeeded() { 122 // Do not intercept if the user has not turned off the profile 123 if (!mUserManager.isQuietModeEnabled(UserHandle.of(mUserId))) { 124 return false; 125 } 126 IIntentSender target = mService.getIntentSenderLocked( 127 INTENT_SENDER_ACTIVITY, mCallingPackage, mCallingUid, mUserId, null, null, 0, 128 new Intent[] {mIntent}, new String[] {mResolvedType}, 129 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT, null); 130 131 mIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId, 132 new IntentSender(target)); 133 mCallingPid = mRealCallingPid; 134 mCallingUid = mRealCallingUid; 135 mResolvedType = null; 136 137 final UserInfo parent = mUserManager.getProfileParent(mUserId); 138 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id); 139 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/); 140 return true; 141 } 142 143 private boolean interceptSuspendPackageIfNeed() { 144 // Do not intercept if the admin did not suspend the package 145 if (mAInfo == null || mAInfo.applicationInfo == null || 146 (mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) { 147 return false; 148 } 149 DevicePolicyManagerInternal devicePolicyManager = LocalServices.getService( 150 DevicePolicyManagerInternal.class); 151 if (devicePolicyManager == null) { 152 return false; 153 } 154 mIntent = devicePolicyManager.createPackageSuspendedDialogIntent( 155 mAInfo.packageName, mUserId); 156 mCallingPid = mRealCallingPid; 157 mCallingUid = mRealCallingUid; 158 mResolvedType = null; 159 160 final UserInfo parent = mUserManager.getProfileParent(mUserId); 161 if (parent != null) { 162 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id); 163 } else { 164 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId); 165 } 166 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/); 167 return true; 168 } 169 170 private boolean interceptWorkProfileChallengeIfNeeded() { 171 final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mIntent, 172 mResolvedType, mAInfo, mCallingPackage, mUserId); 173 if (interceptingIntent == null) { 174 return false; 175 } 176 mIntent = interceptingIntent; 177 mCallingPid = mRealCallingPid; 178 mCallingUid = mRealCallingUid; 179 mResolvedType = null; 180 // If we are intercepting and there was a task, convert it into an extra for the 181 // ConfirmCredentials intent and unassign it, as otherwise the task will move to 182 // front even if ConfirmCredentials is cancelled. 183 if (mInTask != null) { 184 mIntent.putExtra(EXTRA_TASK_ID, mInTask.taskId); 185 mInTask = null; 186 } 187 if (mActivityOptions == null) { 188 mActivityOptions = ActivityOptions.makeBasic(); 189 } 190 191 ActivityRecord homeActivityRecord = mSupervisor.getHomeActivity(); 192 if (homeActivityRecord != null && homeActivityRecord.task != null) { 193 // Showing credential confirmation activity in home task to avoid stopping multi-windowed 194 // mode after showing the full-screen credential confirmation activity. 195 mActivityOptions.setLaunchTaskId(homeActivityRecord.task.taskId); 196 } 197 198 final UserInfo parent = mUserManager.getProfileParent(mUserId); 199 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id); 200 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/); 201 return true; 202 } 203 204 /** 205 * Creates an intent to intercept the current activity start with Confirm Credentials if needed. 206 * 207 * @return The intercepting intent if needed. 208 */ 209 private Intent interceptWithConfirmCredentialsIfNeeded(Intent intent, String resolvedType, 210 ActivityInfo aInfo, String callingPackage, int userId) { 211 if (!mService.mUserController.shouldConfirmCredentials(userId)) { 212 return null; 213 } 214 // Allow direct boot aware activity to be displayed before the user is unlocked. 215 if (aInfo.directBootAware && mService.mUserController.isUserRunningLocked(userId, 216 ActivityManager.FLAG_AND_LOCKED)) { 217 return null; 218 } 219 final IIntentSender target = mService.getIntentSenderLocked( 220 INTENT_SENDER_ACTIVITY, callingPackage, 221 Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent }, 222 new String[]{ resolvedType }, 223 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE, null); 224 final KeyguardManager km = (KeyguardManager) mService.mContext 225 .getSystemService(KEYGUARD_SERVICE); 226 final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, userId); 227 if (newIntent == null) { 228 return null; 229 } 230 newIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | 231 FLAG_ACTIVITY_TASK_ON_HOME); 232 newIntent.putExtra(EXTRA_PACKAGE_NAME, aInfo.packageName); 233 newIntent.putExtra(EXTRA_INTENT, new IntentSender(target)); 234 return newIntent; 235 } 236 237} 238