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 82 ActivityStartInterceptor(ActivityManagerService service, ActivityStackSupervisor supervisor) { 83 mService = service; 84 mSupervisor = supervisor; 85 } 86 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 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 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 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 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 */ 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