2 * Copyright (C) 2016 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.am;
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.pm.ApplicationInfo.FLAG_SUSPENDED;
31 import android.app.KeyguardManager;
32 import android.app.admin.DevicePolicyManagerInternal;
33 import android.content.IIntentSender;
34 import android.content.Intent;
35 import android.content.IntentSender;
36 import android.content.pm.ActivityInfo;
37 import android.content.pm.ResolveInfo;
38 import android.content.pm.UserInfo;
39 import android.os.Binder;
40 import android.os.UserHandle;
41 import android.os.UserManager;
43 import com.android.internal.app.UnlaunchableAppActivity;
44 import com.android.server.LocalServices;
47 * A class that contains activity intercepting logic for {@link ActivityStarter#startActivityLocked}
50 class ActivityStartInterceptor {
52 private final ActivityManagerService mService;
53 private UserManager mUserManager;
54 private final ActivityStackSupervisor mSupervisor;
57 * Per-intent states loaded from ActivityStarter than shouldn't be changed by any
58 * interception routines.
60 private int mRealCallingPid;
61 private int mRealCallingUid;
63 private int mStartFlags;
64 private String mCallingPackage;
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.
79 ActivityStartInterceptor(ActivityManagerService service, ActivityStackSupervisor supervisor) {
81 mSupervisor = supervisor;
84 void setStates(int userId, int realCallingPid, int realCallingUid, int startFlags,
85 String callingPackage) {
86 mRealCallingPid = realCallingPid;
87 mRealCallingUid = realCallingUid;
89 mStartFlags = startFlags;
90 mCallingPackage = callingPackage;
93 void intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType,
94 TaskRecord inTask, int callingPid, int callingUid) {
95 mUserManager = UserManager.get(mService.mContext);
97 mCallingPid = callingPid;
98 mCallingUid = callingUid;
101 mResolvedType = resolvedType;
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.
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.
113 interceptWorkProfileChallengeIfNeeded();
116 private boolean interceptQuietProfileIfNeeded() {
117 // Do not intercept if the user has not turned off the profile
118 if (!mUserManager.isQuietModeEnabled(UserHandle.of(mUserId))) {
121 mIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId);
122 mCallingPid = mRealCallingPid;
123 mCallingUid = mRealCallingUid;
124 mResolvedType = null;
126 final UserInfo parent = mUserManager.getProfileParent(mUserId);
127 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
128 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
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) {
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;
146 final UserInfo parent = mUserManager.getProfileParent(mUserId);
147 if (parent != null) {
148 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
150 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId);
152 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
156 private boolean interceptWorkProfileChallengeIfNeeded() {
157 final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mIntent,
158 mResolvedType, mAInfo, mCallingPackage, mUserId);
159 if (interceptingIntent == null) {
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);
174 final UserInfo parent = mUserManager.getProfileParent(mUserId);
175 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
176 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
181 * Creates an intent to intercept the current activity start with Confirm Credentials if needed.
183 * @return The intercepting intent if needed.
185 private Intent interceptWithConfirmCredentialsIfNeeded(Intent intent, String resolvedType,
186 ActivityInfo aInfo, String callingPackage, int userId) {
187 if (!mService.mUserController.shouldConfirmCredentials(userId)) {
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) {
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));