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