blob: 6684f257fb2fd9e491eacd9094a554b474f45d74 [file] [log] [blame]
Kenny Guyb1b30262016-02-09 16:02:35 +00001/*
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
Rubin Xu58d25992016-01-21 17:47:13 +000017package 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;
Tony Mak4291c762016-03-24 12:23:22 +000029import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
Rubin Xu58d25992016-01-21 17:47:13 +000030import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
31
Tony Mak853304c2016-04-18 15:17:41 +010032import android.app.ActivityOptions;
Rubin Xu58d25992016-01-21 17:47:13 +000033import android.app.KeyguardManager;
Sudheer Shanka7a9c34b2016-03-11 12:25:51 -080034import android.app.admin.DevicePolicyManagerInternal;
Benjamin Franz563707b2017-06-29 15:06:13 +010035import android.content.Context;
Rubin Xu58d25992016-01-21 17:47:13 +000036import android.content.IIntentSender;
37import android.content.Intent;
38import android.content.IntentSender;
39import android.content.pm.ActivityInfo;
40import android.content.pm.ResolveInfo;
41import android.content.pm.UserInfo;
42import android.os.Binder;
43import android.os.UserHandle;
44import android.os.UserManager;
45
Benjamin Franz563707b2017-06-29 15:06:13 +010046import com.android.internal.annotations.VisibleForTesting;
Rubin Xu58d25992016-01-21 17:47:13 +000047import com.android.internal.app.UnlaunchableAppActivity;
Sudheer Shanka7a9c34b2016-03-11 12:25:51 -080048import com.android.server.LocalServices;
Rubin Xu58d25992016-01-21 17:47:13 +000049
50/**
51 * A class that contains activity intercepting logic for {@link ActivityStarter#startActivityLocked}
Benjamin Franz563707b2017-06-29 15:06:13 +010052 * It's initialized via setStates and interception occurs via the intercept method.
53 *
54 * Note that this class is instantiated when {@link ActivityManagerService} gets created so there
55 * is no guarantee that other system services are already present.
Rubin Xu58d25992016-01-21 17:47:13 +000056 */
57class ActivityStartInterceptor {
58
59 private final ActivityManagerService mService;
Rubin Xu58d25992016-01-21 17:47:13 +000060 private final ActivityStackSupervisor mSupervisor;
Benjamin Franz563707b2017-06-29 15:06:13 +010061 private final Context mServiceContext;
62 private final UserController mUserController;
63
64 // UserManager cannot be final as it's not ready when this class is instantiated during boot
65 private UserManager mUserManager;
Rubin Xu58d25992016-01-21 17:47:13 +000066
67 /*
68 * Per-intent states loaded from ActivityStarter than shouldn't be changed by any
69 * interception routines.
70 */
71 private int mRealCallingPid;
72 private int mRealCallingUid;
73 private int mUserId;
74 private int mStartFlags;
75 private String mCallingPackage;
76
77 /*
78 * Per-intent states that were load from ActivityStarter and are subject to modifications
79 * by the interception routines. After calling {@link #intercept} the caller should assign
Benjamin Franz563707b2017-06-29 15:06:13 +010080 * these values back to {@link ActivityStarter#startActivityLocked}'s local variables if
81 * {@link #intercept} returns true.
Rubin Xu58d25992016-01-21 17:47:13 +000082 */
83 Intent mIntent;
84 int mCallingPid;
85 int mCallingUid;
86 ResolveInfo mRInfo;
87 ActivityInfo mAInfo;
88 String mResolvedType;
89 TaskRecord mInTask;
Tony Mak853304c2016-04-18 15:17:41 +010090 ActivityOptions mActivityOptions;
Rubin Xu58d25992016-01-21 17:47:13 +000091
92 ActivityStartInterceptor(ActivityManagerService service, ActivityStackSupervisor supervisor) {
Benjamin Franz563707b2017-06-29 15:06:13 +010093 this(service, supervisor, service.mContext, service.mUserController);
Rubin Xu58d25992016-01-21 17:47:13 +000094 }
95
Benjamin Franz563707b2017-06-29 15:06:13 +010096 @VisibleForTesting
97 ActivityStartInterceptor(ActivityManagerService service, ActivityStackSupervisor supervisor,
98 Context context, UserController userController) {
99 mService = service;
100 mSupervisor = supervisor;
101 mServiceContext = context;
102 mUserController = userController;
103 }
104
105 /**
106 * Effectively initialize the class before intercepting the start intent. The values set in this
107 * method should not be changed during intercept.
108 */
Rubin Xu58d25992016-01-21 17:47:13 +0000109 void setStates(int userId, int realCallingPid, int realCallingUid, int startFlags,
110 String callingPackage) {
111 mRealCallingPid = realCallingPid;
112 mRealCallingUid = realCallingUid;
113 mUserId = userId;
114 mStartFlags = startFlags;
115 mCallingPackage = callingPackage;
116 }
117
Benjamin Franz563707b2017-06-29 15:06:13 +0100118 /**
119 * Intercept the launch intent based on various signals. If an interception happened the
120 * internal variables get assigned and need to be read explicitly by the caller.
121 *
122 * @return true if an interception occurred
123 */
124 boolean intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType,
Tony Mak853304c2016-04-18 15:17:41 +0100125 TaskRecord inTask, int callingPid, int callingUid, ActivityOptions activityOptions) {
Benjamin Franz563707b2017-06-29 15:06:13 +0100126 mUserManager = UserManager.get(mServiceContext);
127
Rubin Xu58d25992016-01-21 17:47:13 +0000128 mIntent = intent;
129 mCallingPid = callingPid;
130 mCallingUid = callingUid;
131 mRInfo = rInfo;
132 mAInfo = aInfo;
133 mResolvedType = resolvedType;
134 mInTask = inTask;
Tony Mak853304c2016-04-18 15:17:41 +0100135 mActivityOptions = activityOptions;
Benjamin Franz563707b2017-06-29 15:06:13 +0100136
Rubin Xub93522a2016-02-23 18:21:48 +0000137 if (interceptSuspendPackageIfNeed()) {
138 // Skip the rest of interceptions as the package is suspended by device admin so
139 // no user action can undo this.
Benjamin Franz563707b2017-06-29 15:06:13 +0100140 return true;
Rubin Xub93522a2016-02-23 18:21:48 +0000141 }
142 if (interceptQuietProfileIfNeeded()) {
143 // If work profile is turned off, skip the work challenge since the profile can only
144 // be unlocked when profile's user is running.
Benjamin Franz563707b2017-06-29 15:06:13 +0100145 return true;
Rubin Xub93522a2016-02-23 18:21:48 +0000146 }
Benjamin Franz563707b2017-06-29 15:06:13 +0100147 return interceptWorkProfileChallengeIfNeeded();
Rubin Xu58d25992016-01-21 17:47:13 +0000148 }
149
Rubin Xub93522a2016-02-23 18:21:48 +0000150 private boolean interceptQuietProfileIfNeeded() {
Rubin Xu58d25992016-01-21 17:47:13 +0000151 // Do not intercept if the user has not turned off the profile
152 if (!mUserManager.isQuietModeEnabled(UserHandle.of(mUserId))) {
Rubin Xub93522a2016-02-23 18:21:48 +0000153 return false;
Rubin Xu58d25992016-01-21 17:47:13 +0000154 }
Rubin Xue420c552016-04-06 19:04:30 +0100155 IIntentSender target = mService.getIntentSenderLocked(
156 INTENT_SENDER_ACTIVITY, mCallingPackage, mCallingUid, mUserId, null, null, 0,
157 new Intent[] {mIntent}, new String[] {mResolvedType},
158 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT, null);
159
160 mIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId,
161 new IntentSender(target));
Rubin Xu58d25992016-01-21 17:47:13 +0000162 mCallingPid = mRealCallingPid;
163 mCallingUid = mRealCallingUid;
164 mResolvedType = null;
165
166 final UserInfo parent = mUserManager.getProfileParent(mUserId);
167 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
Rubin Xub93522a2016-02-23 18:21:48 +0000168 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
169 return true;
Rubin Xu58d25992016-01-21 17:47:13 +0000170 }
171
Rubin Xub93522a2016-02-23 18:21:48 +0000172 private boolean interceptSuspendPackageIfNeed() {
Rubin Xu58d25992016-01-21 17:47:13 +0000173 // Do not intercept if the admin did not suspend the package
174 if (mAInfo == null || mAInfo.applicationInfo == null ||
175 (mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) {
Rubin Xub93522a2016-02-23 18:21:48 +0000176 return false;
Rubin Xu58d25992016-01-21 17:47:13 +0000177 }
Benjamin Franz563707b2017-06-29 15:06:13 +0100178 DevicePolicyManagerInternal devicePolicyManager = LocalServices
179 .getService(DevicePolicyManagerInternal.class);
Makoto Onuki26704952016-06-13 14:50:11 -0700180 if (devicePolicyManager == null) {
181 return false;
182 }
Nicolas Prevot709a63d2016-06-09 13:14:00 +0100183 mIntent = devicePolicyManager.createShowAdminSupportIntent(mUserId, true);
Rubin Xu58d25992016-01-21 17:47:13 +0000184 mCallingPid = mRealCallingPid;
185 mCallingUid = mRealCallingUid;
186 mResolvedType = null;
187
188 final UserInfo parent = mUserManager.getProfileParent(mUserId);
189 if (parent != null) {
190 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
191 } else {
192 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId);
193 }
Rubin Xub93522a2016-02-23 18:21:48 +0000194 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
195 return true;
Rubin Xu58d25992016-01-21 17:47:13 +0000196 }
197
Rubin Xub93522a2016-02-23 18:21:48 +0000198 private boolean interceptWorkProfileChallengeIfNeeded() {
Rubin Xu58d25992016-01-21 17:47:13 +0000199 final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mIntent,
200 mResolvedType, mAInfo, mCallingPackage, mUserId);
201 if (interceptingIntent == null) {
Rubin Xub93522a2016-02-23 18:21:48 +0000202 return false;
Rubin Xu58d25992016-01-21 17:47:13 +0000203 }
204 mIntent = interceptingIntent;
205 mCallingPid = mRealCallingPid;
206 mCallingUid = mRealCallingUid;
207 mResolvedType = null;
208 // If we are intercepting and there was a task, convert it into an extra for the
209 // ConfirmCredentials intent and unassign it, as otherwise the task will move to
210 // front even if ConfirmCredentials is cancelled.
211 if (mInTask != null) {
212 mIntent.putExtra(EXTRA_TASK_ID, mInTask.taskId);
213 mInTask = null;
214 }
Tony Mak853304c2016-04-18 15:17:41 +0100215 if (mActivityOptions == null) {
216 mActivityOptions = ActivityOptions.makeBasic();
217 }
Victor Chang89d4a9a2016-06-14 13:49:32 +0100218
219 ActivityRecord homeActivityRecord = mSupervisor.getHomeActivity();
Bryce Leeaf691c02017-03-20 14:20:22 -0700220 if (homeActivityRecord != null && homeActivityRecord.getTask() != null) {
Victor Chang89d4a9a2016-06-14 13:49:32 +0100221 // Showing credential confirmation activity in home task to avoid stopping multi-windowed
222 // mode after showing the full-screen credential confirmation activity.
Bryce Leeaf691c02017-03-20 14:20:22 -0700223 mActivityOptions.setLaunchTaskId(homeActivityRecord.getTask().taskId);
Victor Chang89d4a9a2016-06-14 13:49:32 +0100224 }
Rubin Xu58d25992016-01-21 17:47:13 +0000225
226 final UserInfo parent = mUserManager.getProfileParent(mUserId);
227 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
Rubin Xub93522a2016-02-23 18:21:48 +0000228 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
229 return true;
Rubin Xu58d25992016-01-21 17:47:13 +0000230 }
231
232 /**
233 * Creates an intent to intercept the current activity start with Confirm Credentials if needed.
234 *
235 * @return The intercepting intent if needed.
236 */
237 private Intent interceptWithConfirmCredentialsIfNeeded(Intent intent, String resolvedType,
238 ActivityInfo aInfo, String callingPackage, int userId) {
Benjamin Franz563707b2017-06-29 15:06:13 +0100239 if (!mUserController.shouldConfirmCredentials(userId)) {
Rubin Xu58d25992016-01-21 17:47:13 +0000240 return null;
241 }
Charles Hee7c5ced2017-04-12 16:22:35 +0100242 // TODO(b/28935539): should allow certain activities to bypass work challenge
Rubin Xu58d25992016-01-21 17:47:13 +0000243 final IIntentSender target = mService.getIntentSenderLocked(
244 INTENT_SENDER_ACTIVITY, callingPackage,
245 Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
246 new String[]{ resolvedType },
247 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE, null);
Benjamin Franz563707b2017-06-29 15:06:13 +0100248 final KeyguardManager km = (KeyguardManager) mServiceContext
Rubin Xu58d25992016-01-21 17:47:13 +0000249 .getSystemService(KEYGUARD_SERVICE);
250 final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, userId);
251 if (newIntent == null) {
252 return null;
253 }
Tony Mak4291c762016-03-24 12:23:22 +0000254 newIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
255 FLAG_ACTIVITY_TASK_ON_HOME);
Rubin Xu58d25992016-01-21 17:47:13 +0000256 newIntent.putExtra(EXTRA_PACKAGE_NAME, aInfo.packageName);
257 newIntent.putExtra(EXTRA_INTENT, new IntentSender(target));
258 return newIntent;
259 }
260
261}