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