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