blob: b8442a887dac475a040fbe46fd7ee04ca705f9a2 [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
Wale Ogunwale59507092018-10-29 09:00:30 -070017package com.android.server.wm;
Rubin Xu58d25992016-01-21 17:47:13 +000018
19import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY;
Tony Mak83546a82018-01-22 13:56:20 +000020import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
Rubin Xu58d25992016-01-21 17:47:13 +000021import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
22import static android.app.PendingIntent.FLAG_IMMUTABLE;
23import static android.app.PendingIntent.FLAG_ONE_SHOT;
Tony Mak706fbe72018-04-03 18:49:05 +010024import static android.app.admin.DevicePolicyManager.EXTRA_RESTRICTION;
25import static android.app.admin.DevicePolicyManager.POLICY_SUSPEND_PACKAGES;
Rubin Xu58d25992016-01-21 17:47:13 +000026import static android.content.Context.KEYGUARD_SERVICE;
27import static android.content.Intent.EXTRA_INTENT;
28import static android.content.Intent.EXTRA_PACKAGE_NAME;
29import static android.content.Intent.EXTRA_TASK_ID;
30import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
31import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
Tony Mak4291c762016-03-24 12:23:22 +000032import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
Rubin Xu58d25992016-01-21 17:47:13 +000033import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
34
Suprabh Shukla3c3af142018-03-30 00:28:37 -070035import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
36
Tony Mak853304c2016-04-18 15:17:41 +010037import android.app.ActivityOptions;
Rubin Xu58d25992016-01-21 17:47:13 +000038import android.app.KeyguardManager;
Sudheer Shanka7a9c34b2016-03-11 12:25:51 -080039import android.app.admin.DevicePolicyManagerInternal;
Benjamin Franz563707b2017-06-29 15:06:13 +010040import android.content.Context;
Rubin Xu58d25992016-01-21 17:47:13 +000041import android.content.IIntentSender;
42import android.content.Intent;
43import android.content.IntentSender;
44import android.content.pm.ActivityInfo;
Suprabh Shukla3c3af142018-03-30 00:28:37 -070045import android.content.pm.PackageManagerInternal;
Rubin Xu58d25992016-01-21 17:47:13 +000046import android.content.pm.ResolveInfo;
Suprabh Shukla389cb6f2018-10-01 18:20:39 -070047import android.content.pm.SuspendDialogInfo;
Rubin Xu58d25992016-01-21 17:47:13 +000048import android.content.pm.UserInfo;
49import android.os.Binder;
Tony Mak83546a82018-01-22 13:56:20 +000050import android.os.Bundle;
Ben Gruver1ab3d6e2017-12-07 13:45:08 -080051import android.os.RemoteException;
Rubin Xu58d25992016-01-21 17:47:13 +000052import android.os.UserHandle;
53import android.os.UserManager;
54
Benjamin Franz563707b2017-06-29 15:06:13 +010055import com.android.internal.annotations.VisibleForTesting;
Ben Gruver1ab3d6e2017-12-07 13:45:08 -080056import com.android.internal.app.HarmfulAppWarningActivity;
Suprabh Shukla3c3af142018-03-30 00:28:37 -070057import com.android.internal.app.SuspendedAppActivity;
Rubin Xu58d25992016-01-21 17:47:13 +000058import com.android.internal.app.UnlaunchableAppActivity;
Sudheer Shanka7a9c34b2016-03-11 12:25:51 -080059import com.android.server.LocalServices;
Wale Ogunwale59507092018-10-29 09:00:30 -070060import com.android.server.am.ActivityManagerService;
Rubin Xu58d25992016-01-21 17:47:13 +000061
62/**
63 * A class that contains activity intercepting logic for {@link ActivityStarter#startActivityLocked}
Benjamin Franz563707b2017-06-29 15:06:13 +010064 * It's initialized via setStates and interception occurs via the intercept method.
65 *
66 * Note that this class is instantiated when {@link ActivityManagerService} gets created so there
67 * is no guarantee that other system services are already present.
Rubin Xu58d25992016-01-21 17:47:13 +000068 */
69class ActivityStartInterceptor {
70
Wale Ogunwalec9e57de2018-05-08 14:28:07 -070071 private final ActivityTaskManagerService mService;
Rubin Xu58d25992016-01-21 17:47:13 +000072 private final ActivityStackSupervisor mSupervisor;
Wale Ogunwaled32da472018-11-16 07:19:28 -080073 private final RootActivityContainer mRootActivityContainer;
Benjamin Franz563707b2017-06-29 15:06:13 +010074 private final Context mServiceContext;
Benjamin Franz563707b2017-06-29 15:06:13 +010075
76 // UserManager cannot be final as it's not ready when this class is instantiated during boot
77 private UserManager mUserManager;
Rubin Xu58d25992016-01-21 17:47:13 +000078
79 /*
80 * Per-intent states loaded from ActivityStarter than shouldn't be changed by any
81 * interception routines.
82 */
83 private int mRealCallingPid;
84 private int mRealCallingUid;
85 private int mUserId;
86 private int mStartFlags;
87 private String mCallingPackage;
88
89 /*
90 * Per-intent states that were load from ActivityStarter and are subject to modifications
91 * by the interception routines. After calling {@link #intercept} the caller should assign
Benjamin Franz563707b2017-06-29 15:06:13 +010092 * these values back to {@link ActivityStarter#startActivityLocked}'s local variables if
93 * {@link #intercept} returns true.
Rubin Xu58d25992016-01-21 17:47:13 +000094 */
95 Intent mIntent;
96 int mCallingPid;
97 int mCallingUid;
98 ResolveInfo mRInfo;
99 ActivityInfo mAInfo;
100 String mResolvedType;
101 TaskRecord mInTask;
Tony Mak853304c2016-04-18 15:17:41 +0100102 ActivityOptions mActivityOptions;
Rubin Xu58d25992016-01-21 17:47:13 +0000103
Wale Ogunwalec9e57de2018-05-08 14:28:07 -0700104 ActivityStartInterceptor(
105 ActivityTaskManagerService service, ActivityStackSupervisor supervisor) {
Wale Ogunwaled32da472018-11-16 07:19:28 -0800106 this(service, supervisor, service.mRootActivityContainer, service.mContext);
Rubin Xu58d25992016-01-21 17:47:13 +0000107 }
108
Benjamin Franz563707b2017-06-29 15:06:13 +0100109 @VisibleForTesting
Wale Ogunwalec9e57de2018-05-08 14:28:07 -0700110 ActivityStartInterceptor(ActivityTaskManagerService service, ActivityStackSupervisor supervisor,
Wale Ogunwaled32da472018-11-16 07:19:28 -0800111 RootActivityContainer root, Context context) {
Benjamin Franz563707b2017-06-29 15:06:13 +0100112 mService = service;
113 mSupervisor = supervisor;
Wale Ogunwaled32da472018-11-16 07:19:28 -0800114 mRootActivityContainer = root;
Benjamin Franz563707b2017-06-29 15:06:13 +0100115 mServiceContext = context;
Benjamin Franz563707b2017-06-29 15:06:13 +0100116 }
117
118 /**
119 * Effectively initialize the class before intercepting the start intent. The values set in this
120 * method should not be changed during intercept.
121 */
Rubin Xu58d25992016-01-21 17:47:13 +0000122 void setStates(int userId, int realCallingPid, int realCallingUid, int startFlags,
123 String callingPackage) {
124 mRealCallingPid = realCallingPid;
125 mRealCallingUid = realCallingUid;
126 mUserId = userId;
127 mStartFlags = startFlags;
128 mCallingPackage = callingPackage;
129 }
130
Ben Gruver1ab3d6e2017-12-07 13:45:08 -0800131 private IntentSender createIntentSenderForOriginalIntent(int callingUid, int flags) {
Tony Mak83546a82018-01-22 13:56:20 +0000132 Bundle activityOptions = deferCrossProfileAppsAnimationIfNecessary();
Wale Ogunwaleee6eca12018-09-19 20:37:53 -0700133 final IIntentSender target = mService.getIntentSenderLocked(
Ben Gruver1ab3d6e2017-12-07 13:45:08 -0800134 INTENT_SENDER_ACTIVITY, mCallingPackage, callingUid, mUserId, null /*token*/,
135 null /*resultCode*/, 0 /*requestCode*/,
136 new Intent[] { mIntent }, new String[] { mResolvedType },
Tony Mak83546a82018-01-22 13:56:20 +0000137 flags, activityOptions);
Ben Gruver1ab3d6e2017-12-07 13:45:08 -0800138 return new IntentSender(target);
139 }
140
Benjamin Franz563707b2017-06-29 15:06:13 +0100141 /**
142 * Intercept the launch intent based on various signals. If an interception happened the
143 * internal variables get assigned and need to be read explicitly by the caller.
144 *
145 * @return true if an interception occurred
146 */
147 boolean intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType,
Tony Mak853304c2016-04-18 15:17:41 +0100148 TaskRecord inTask, int callingPid, int callingUid, ActivityOptions activityOptions) {
Benjamin Franz563707b2017-06-29 15:06:13 +0100149 mUserManager = UserManager.get(mServiceContext);
150
Rubin Xu58d25992016-01-21 17:47:13 +0000151 mIntent = intent;
152 mCallingPid = callingPid;
153 mCallingUid = callingUid;
154 mRInfo = rInfo;
155 mAInfo = aInfo;
156 mResolvedType = resolvedType;
157 mInTask = inTask;
Tony Mak853304c2016-04-18 15:17:41 +0100158 mActivityOptions = activityOptions;
Benjamin Franz563707b2017-06-29 15:06:13 +0100159
Suprabh Shukla3c3af142018-03-30 00:28:37 -0700160 if (interceptSuspendedPackageIfNeeded()) {
Rubin Xub93522a2016-02-23 18:21:48 +0000161 // Skip the rest of interceptions as the package is suspended by device admin so
162 // no user action can undo this.
Benjamin Franz563707b2017-06-29 15:06:13 +0100163 return true;
Rubin Xub93522a2016-02-23 18:21:48 +0000164 }
165 if (interceptQuietProfileIfNeeded()) {
166 // If work profile is turned off, skip the work challenge since the profile can only
167 // be unlocked when profile's user is running.
Benjamin Franz563707b2017-06-29 15:06:13 +0100168 return true;
Rubin Xub93522a2016-02-23 18:21:48 +0000169 }
Ben Gruver1ab3d6e2017-12-07 13:45:08 -0800170 if (interceptHarmfulAppIfNeeded()) {
171 // If the app has a "harmful app" warning associated with it, we should ask to uninstall
172 // before issuing the work challenge.
173 return true;
174 }
Benjamin Franz563707b2017-06-29 15:06:13 +0100175 return interceptWorkProfileChallengeIfNeeded();
Rubin Xu58d25992016-01-21 17:47:13 +0000176 }
177
Tony Mak83546a82018-01-22 13:56:20 +0000178 /**
179 * If the activity option is the {@link ActivityOptions#ANIM_OPEN_CROSS_PROFILE_APPS} one,
180 * defer the animation until the original intent is started.
181 *
182 * @return the activity option used to start the original intent.
183 */
184 private Bundle deferCrossProfileAppsAnimationIfNecessary() {
185 if (mActivityOptions != null
186 && mActivityOptions.getAnimationType() == ANIM_OPEN_CROSS_PROFILE_APPS) {
187 mActivityOptions = null;
188 return ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle();
189 }
190 return null;
191 }
192
Rubin Xub93522a2016-02-23 18:21:48 +0000193 private boolean interceptQuietProfileIfNeeded() {
Rubin Xu58d25992016-01-21 17:47:13 +0000194 // Do not intercept if the user has not turned off the profile
195 if (!mUserManager.isQuietModeEnabled(UserHandle.of(mUserId))) {
Rubin Xub93522a2016-02-23 18:21:48 +0000196 return false;
Rubin Xu58d25992016-01-21 17:47:13 +0000197 }
Tony Mak83546a82018-01-22 13:56:20 +0000198
Ben Gruver1ab3d6e2017-12-07 13:45:08 -0800199 IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
200 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT);
Rubin Xue420c552016-04-06 19:04:30 +0100201
Ben Gruver1ab3d6e2017-12-07 13:45:08 -0800202 mIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId, target);
Rubin Xu58d25992016-01-21 17:47:13 +0000203 mCallingPid = mRealCallingPid;
204 mCallingUid = mRealCallingUid;
205 mResolvedType = null;
206
207 final UserInfo parent = mUserManager.getProfileParent(mUserId);
Makoto Onuki1a342742018-04-26 14:56:59 -0700208 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0, mRealCallingUid);
Rubin Xub93522a2016-02-23 18:21:48 +0000209 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
210 return true;
Rubin Xu58d25992016-01-21 17:47:13 +0000211 }
212
Suprabh Shukla3c3af142018-03-30 00:28:37 -0700213 private boolean interceptSuspendedByAdminPackage() {
Benjamin Franz563707b2017-06-29 15:06:13 +0100214 DevicePolicyManagerInternal devicePolicyManager = LocalServices
215 .getService(DevicePolicyManagerInternal.class);
Makoto Onuki26704952016-06-13 14:50:11 -0700216 if (devicePolicyManager == null) {
217 return false;
218 }
Nicolas Prevot709a63d2016-06-09 13:14:00 +0100219 mIntent = devicePolicyManager.createShowAdminSupportIntent(mUserId, true);
Tony Mak706fbe72018-04-03 18:49:05 +0100220 mIntent.putExtra(EXTRA_RESTRICTION, POLICY_SUSPEND_PACKAGES);
221
Rubin Xu58d25992016-01-21 17:47:13 +0000222 mCallingPid = mRealCallingPid;
223 mCallingUid = mRealCallingUid;
224 mResolvedType = null;
225
226 final UserInfo parent = mUserManager.getProfileParent(mUserId);
227 if (parent != null) {
Makoto Onuki1a342742018-04-26 14:56:59 -0700228 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0,
229 mRealCallingUid);
Rubin Xu58d25992016-01-21 17:47:13 +0000230 } else {
Makoto Onuki1a342742018-04-26 14:56:59 -0700231 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0,
232 mRealCallingUid);
Rubin Xu58d25992016-01-21 17:47:13 +0000233 }
Rubin Xub93522a2016-02-23 18:21:48 +0000234 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
235 return true;
Rubin Xu58d25992016-01-21 17:47:13 +0000236 }
237
Suprabh Shukla3c3af142018-03-30 00:28:37 -0700238 private boolean interceptSuspendedPackageIfNeeded() {
239 // Do not intercept if the package is not suspended
240 if (mAInfo == null || mAInfo.applicationInfo == null ||
241 (mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) {
242 return false;
243 }
Wale Ogunwale906f9c62018-07-23 11:23:44 -0700244 final PackageManagerInternal pmi = mService.getPackageManagerInternalLocked();
Suprabh Shukla3c3af142018-03-30 00:28:37 -0700245 if (pmi == null) {
246 return false;
247 }
248 final String suspendedPackage = mAInfo.applicationInfo.packageName;
249 final String suspendingPackage = pmi.getSuspendingPackage(suspendedPackage, mUserId);
250 if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
251 return interceptSuspendedByAdminPackage();
252 }
Suprabh Shukla389cb6f2018-10-01 18:20:39 -0700253 final SuspendDialogInfo dialogInfo = pmi.getSuspendedDialogInfo(suspendedPackage, mUserId);
Suprabh Shukla1ab90a22018-05-10 15:54:08 -0700254 mIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(suspendedPackage,
Suprabh Shukla389cb6f2018-10-01 18:20:39 -0700255 suspendingPackage, dialogInfo, mUserId);
Suprabh Shukla3c3af142018-03-30 00:28:37 -0700256 mCallingPid = mRealCallingPid;
257 mCallingUid = mRealCallingUid;
258 mResolvedType = null;
Makoto Onuki1a342742018-04-26 14:56:59 -0700259 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, mRealCallingUid);
Suprabh Shukla3c3af142018-03-30 00:28:37 -0700260 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
261 return true;
262 }
263
Rubin Xub93522a2016-02-23 18:21:48 +0000264 private boolean interceptWorkProfileChallengeIfNeeded() {
Tony Mak83546a82018-01-22 13:56:20 +0000265 final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mAInfo, mUserId);
Rubin Xu58d25992016-01-21 17:47:13 +0000266 if (interceptingIntent == null) {
Rubin Xub93522a2016-02-23 18:21:48 +0000267 return false;
Rubin Xu58d25992016-01-21 17:47:13 +0000268 }
269 mIntent = interceptingIntent;
270 mCallingPid = mRealCallingPid;
271 mCallingUid = mRealCallingUid;
272 mResolvedType = null;
273 // If we are intercepting and there was a task, convert it into an extra for the
274 // ConfirmCredentials intent and unassign it, as otherwise the task will move to
275 // front even if ConfirmCredentials is cancelled.
276 if (mInTask != null) {
277 mIntent.putExtra(EXTRA_TASK_ID, mInTask.taskId);
278 mInTask = null;
279 }
Tony Mak853304c2016-04-18 15:17:41 +0100280 if (mActivityOptions == null) {
281 mActivityOptions = ActivityOptions.makeBasic();
282 }
Victor Chang89d4a9a2016-06-14 13:49:32 +0100283
Wale Ogunwaled32da472018-11-16 07:19:28 -0800284 ActivityRecord homeActivityRecord = mRootActivityContainer.getDefaultDisplayHomeActivity();
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800285 if (homeActivityRecord != null && homeActivityRecord.getTaskRecord() != null) {
286 // Showing credential confirmation activity in home task to avoid stopping
287 // multi-windowed mode after showing the full-screen credential confirmation activity.
288 mActivityOptions.setLaunchTaskId(homeActivityRecord.getTaskRecord().taskId);
Victor Chang89d4a9a2016-06-14 13:49:32 +0100289 }
Rubin Xu58d25992016-01-21 17:47:13 +0000290
291 final UserInfo parent = mUserManager.getProfileParent(mUserId);
Makoto Onuki1a342742018-04-26 14:56:59 -0700292 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0, mRealCallingUid);
Rubin Xub93522a2016-02-23 18:21:48 +0000293 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
294 return true;
Rubin Xu58d25992016-01-21 17:47:13 +0000295 }
296
297 /**
298 * Creates an intent to intercept the current activity start with Confirm Credentials if needed.
299 *
300 * @return The intercepting intent if needed.
301 */
Tony Mak83546a82018-01-22 13:56:20 +0000302 private Intent interceptWithConfirmCredentialsIfNeeded(ActivityInfo aInfo, int userId) {
Wale Ogunwale86b74462018-07-02 08:42:43 -0700303 if (!mService.mAmInternal.shouldConfirmCredentials(userId)) {
Rubin Xu58d25992016-01-21 17:47:13 +0000304 return null;
305 }
Charles Hee7c5ced2017-04-12 16:22:35 +0100306 // TODO(b/28935539): should allow certain activities to bypass work challenge
Ben Gruver1ab3d6e2017-12-07 13:45:08 -0800307 final IntentSender target = createIntentSenderForOriginalIntent(Binder.getCallingUid(),
308 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE);
Benjamin Franz563707b2017-06-29 15:06:13 +0100309 final KeyguardManager km = (KeyguardManager) mServiceContext
Rubin Xu58d25992016-01-21 17:47:13 +0000310 .getSystemService(KEYGUARD_SERVICE);
311 final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, userId);
312 if (newIntent == null) {
313 return null;
314 }
Tony Mak4291c762016-03-24 12:23:22 +0000315 newIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
316 FLAG_ACTIVITY_TASK_ON_HOME);
Rubin Xu58d25992016-01-21 17:47:13 +0000317 newIntent.putExtra(EXTRA_PACKAGE_NAME, aInfo.packageName);
Ben Gruver1ab3d6e2017-12-07 13:45:08 -0800318 newIntent.putExtra(EXTRA_INTENT, target);
Rubin Xu58d25992016-01-21 17:47:13 +0000319 return newIntent;
320 }
321
Ben Gruver1ab3d6e2017-12-07 13:45:08 -0800322 private boolean interceptHarmfulAppIfNeeded() {
323 CharSequence harmfulAppWarning;
324 try {
Wale Ogunwale906f9c62018-07-23 11:23:44 -0700325 harmfulAppWarning = mService.getPackageManager()
Ben Gruver27ffd822018-03-07 13:24:18 -0800326 .getHarmfulAppWarning(mAInfo.packageName, mUserId);
327 } catch (RemoteException ex) {
Ben Gruver1ab3d6e2017-12-07 13:45:08 -0800328 return false;
329 }
330
331 if (harmfulAppWarning == null) {
332 return false;
333 }
334
335 final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
336 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE);
337
338 mIntent = HarmfulAppWarningActivity.createHarmfulAppWarningIntent(mServiceContext,
339 mAInfo.packageName, target, harmfulAppWarning);
340
341 mCallingPid = mRealCallingPid;
342 mCallingUid = mRealCallingUid;
343 mResolvedType = null;
344
Makoto Onuki1a342742018-04-26 14:56:59 -0700345 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, mRealCallingUid);
Ben Gruver1ab3d6e2017-12-07 13:45:08 -0800346 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
347 return true;
348 }
Rubin Xu58d25992016-01-21 17:47:13 +0000349}