blob: 5b6b50869dda259d6a1eb6169a2c8fe052981e22 [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;
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
37import android.Manifest;
Tony Mak853304c2016-04-18 15:17:41 +010038import android.app.ActivityOptions;
Rubin Xu58d25992016-01-21 17:47:13 +000039import android.app.KeyguardManager;
Sudheer Shanka7a9c34b2016-03-11 12:25:51 -080040import android.app.admin.DevicePolicyManagerInternal;
Benjamin Franz563707b2017-06-29 15:06:13 +010041import android.content.Context;
Rubin Xu58d25992016-01-21 17:47:13 +000042import android.content.IIntentSender;
43import android.content.Intent;
44import android.content.IntentSender;
45import android.content.pm.ActivityInfo;
Suprabh Shukla3c3af142018-03-30 00:28:37 -070046import android.content.pm.PackageManagerInternal;
Rubin Xu58d25992016-01-21 17:47:13 +000047import android.content.pm.ResolveInfo;
48import 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;
Rubin Xu58d25992016-01-21 17:47:13 +000060
61/**
62 * A class that contains activity intercepting logic for {@link ActivityStarter#startActivityLocked}
Benjamin Franz563707b2017-06-29 15:06:13 +010063 * It's initialized via setStates and interception occurs via the intercept method.
64 *
65 * Note that this class is instantiated when {@link ActivityManagerService} gets created so there
66 * is no guarantee that other system services are already present.
Rubin Xu58d25992016-01-21 17:47:13 +000067 */
68class ActivityStartInterceptor {
69
70 private final ActivityManagerService mService;
Rubin Xu58d25992016-01-21 17:47:13 +000071 private final ActivityStackSupervisor mSupervisor;
Benjamin Franz563707b2017-06-29 15:06:13 +010072 private final Context mServiceContext;
73 private final UserController mUserController;
74
75 // UserManager cannot be final as it's not ready when this class is instantiated during boot
76 private UserManager mUserManager;
Rubin Xu58d25992016-01-21 17:47:13 +000077
78 /*
79 * Per-intent states loaded from ActivityStarter than shouldn't be changed by any
80 * interception routines.
81 */
82 private int mRealCallingPid;
83 private int mRealCallingUid;
84 private int mUserId;
85 private int mStartFlags;
86 private String mCallingPackage;
87
88 /*
89 * Per-intent states that were load from ActivityStarter and are subject to modifications
90 * by the interception routines. After calling {@link #intercept} the caller should assign
Benjamin Franz563707b2017-06-29 15:06:13 +010091 * these values back to {@link ActivityStarter#startActivityLocked}'s local variables if
92 * {@link #intercept} returns true.
Rubin Xu58d25992016-01-21 17:47:13 +000093 */
94 Intent mIntent;
95 int mCallingPid;
96 int mCallingUid;
97 ResolveInfo mRInfo;
98 ActivityInfo mAInfo;
99 String mResolvedType;
100 TaskRecord mInTask;
Tony Mak853304c2016-04-18 15:17:41 +0100101 ActivityOptions mActivityOptions;
Rubin Xu58d25992016-01-21 17:47:13 +0000102
103 ActivityStartInterceptor(ActivityManagerService service, ActivityStackSupervisor supervisor) {
Benjamin Franz563707b2017-06-29 15:06:13 +0100104 this(service, supervisor, service.mContext, service.mUserController);
Rubin Xu58d25992016-01-21 17:47:13 +0000105 }
106
Benjamin Franz563707b2017-06-29 15:06:13 +0100107 @VisibleForTesting
108 ActivityStartInterceptor(ActivityManagerService service, ActivityStackSupervisor supervisor,
109 Context context, UserController userController) {
110 mService = service;
111 mSupervisor = supervisor;
112 mServiceContext = context;
113 mUserController = userController;
114 }
115
116 /**
117 * Effectively initialize the class before intercepting the start intent. The values set in this
118 * method should not be changed during intercept.
119 */
Rubin Xu58d25992016-01-21 17:47:13 +0000120 void setStates(int userId, int realCallingPid, int realCallingUid, int startFlags,
121 String callingPackage) {
122 mRealCallingPid = realCallingPid;
123 mRealCallingUid = realCallingUid;
124 mUserId = userId;
125 mStartFlags = startFlags;
126 mCallingPackage = callingPackage;
127 }
128
Ben Gruver1ab3d6e2017-12-07 13:45:08 -0800129 private IntentSender createIntentSenderForOriginalIntent(int callingUid, int flags) {
Tony Mak83546a82018-01-22 13:56:20 +0000130 Bundle activityOptions = deferCrossProfileAppsAnimationIfNecessary();
Ben Gruver1ab3d6e2017-12-07 13:45:08 -0800131 final IIntentSender target = mService.getIntentSenderLocked(
132 INTENT_SENDER_ACTIVITY, mCallingPackage, callingUid, mUserId, null /*token*/,
133 null /*resultCode*/, 0 /*requestCode*/,
134 new Intent[] { mIntent }, new String[] { mResolvedType },
Tony Mak83546a82018-01-22 13:56:20 +0000135 flags, activityOptions);
Ben Gruver1ab3d6e2017-12-07 13:45:08 -0800136 return new IntentSender(target);
137 }
138
Benjamin Franz563707b2017-06-29 15:06:13 +0100139 /**
140 * Intercept the launch intent based on various signals. If an interception happened the
141 * internal variables get assigned and need to be read explicitly by the caller.
142 *
143 * @return true if an interception occurred
144 */
145 boolean intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType,
Tony Mak853304c2016-04-18 15:17:41 +0100146 TaskRecord inTask, int callingPid, int callingUid, ActivityOptions activityOptions) {
Benjamin Franz563707b2017-06-29 15:06:13 +0100147 mUserManager = UserManager.get(mServiceContext);
148
Rubin Xu58d25992016-01-21 17:47:13 +0000149 mIntent = intent;
150 mCallingPid = callingPid;
151 mCallingUid = callingUid;
152 mRInfo = rInfo;
153 mAInfo = aInfo;
154 mResolvedType = resolvedType;
155 mInTask = inTask;
Tony Mak853304c2016-04-18 15:17:41 +0100156 mActivityOptions = activityOptions;
Benjamin Franz563707b2017-06-29 15:06:13 +0100157
Suprabh Shukla3c3af142018-03-30 00:28:37 -0700158 if (interceptSuspendedPackageIfNeeded()) {
Rubin Xub93522a2016-02-23 18:21:48 +0000159 // Skip the rest of interceptions as the package is suspended by device admin so
160 // no user action can undo this.
Benjamin Franz563707b2017-06-29 15:06:13 +0100161 return true;
Rubin Xub93522a2016-02-23 18:21:48 +0000162 }
163 if (interceptQuietProfileIfNeeded()) {
164 // If work profile is turned off, skip the work challenge since the profile can only
165 // be unlocked when profile's user is running.
Benjamin Franz563707b2017-06-29 15:06:13 +0100166 return true;
Rubin Xub93522a2016-02-23 18:21:48 +0000167 }
Ben Gruver1ab3d6e2017-12-07 13:45:08 -0800168 if (interceptHarmfulAppIfNeeded()) {
169 // If the app has a "harmful app" warning associated with it, we should ask to uninstall
170 // before issuing the work challenge.
171 return true;
172 }
Benjamin Franz563707b2017-06-29 15:06:13 +0100173 return interceptWorkProfileChallengeIfNeeded();
Rubin Xu58d25992016-01-21 17:47:13 +0000174 }
175
Tony Mak83546a82018-01-22 13:56:20 +0000176 /**
177 * If the activity option is the {@link ActivityOptions#ANIM_OPEN_CROSS_PROFILE_APPS} one,
178 * defer the animation until the original intent is started.
179 *
180 * @return the activity option used to start the original intent.
181 */
182 private Bundle deferCrossProfileAppsAnimationIfNecessary() {
183 if (mActivityOptions != null
184 && mActivityOptions.getAnimationType() == ANIM_OPEN_CROSS_PROFILE_APPS) {
185 mActivityOptions = null;
186 return ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle();
187 }
188 return null;
189 }
190
Rubin Xub93522a2016-02-23 18:21:48 +0000191 private boolean interceptQuietProfileIfNeeded() {
Rubin Xu58d25992016-01-21 17:47:13 +0000192 // Do not intercept if the user has not turned off the profile
193 if (!mUserManager.isQuietModeEnabled(UserHandle.of(mUserId))) {
Rubin Xub93522a2016-02-23 18:21:48 +0000194 return false;
Rubin Xu58d25992016-01-21 17:47:13 +0000195 }
Tony Mak83546a82018-01-22 13:56:20 +0000196
Ben Gruver1ab3d6e2017-12-07 13:45:08 -0800197 IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
198 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT);
Rubin Xue420c552016-04-06 19:04:30 +0100199
Ben Gruver1ab3d6e2017-12-07 13:45:08 -0800200 mIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId, target);
Rubin Xu58d25992016-01-21 17:47:13 +0000201 mCallingPid = mRealCallingPid;
202 mCallingUid = mRealCallingUid;
203 mResolvedType = null;
204
205 final UserInfo parent = mUserManager.getProfileParent(mUserId);
206 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
Rubin Xub93522a2016-02-23 18:21:48 +0000207 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
208 return true;
Rubin Xu58d25992016-01-21 17:47:13 +0000209 }
210
Suprabh Shukla3c3af142018-03-30 00:28:37 -0700211 private boolean interceptSuspendedByAdminPackage() {
Benjamin Franz563707b2017-06-29 15:06:13 +0100212 DevicePolicyManagerInternal devicePolicyManager = LocalServices
213 .getService(DevicePolicyManagerInternal.class);
Makoto Onuki26704952016-06-13 14:50:11 -0700214 if (devicePolicyManager == null) {
215 return false;
216 }
Nicolas Prevot709a63d2016-06-09 13:14:00 +0100217 mIntent = devicePolicyManager.createShowAdminSupportIntent(mUserId, true);
Tony Mak706fbe72018-04-03 18:49:05 +0100218 mIntent.putExtra(EXTRA_RESTRICTION, POLICY_SUSPEND_PACKAGES);
219
Rubin Xu58d25992016-01-21 17:47:13 +0000220 mCallingPid = mRealCallingPid;
221 mCallingUid = mRealCallingUid;
222 mResolvedType = null;
223
224 final UserInfo parent = mUserManager.getProfileParent(mUserId);
225 if (parent != null) {
226 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
227 } else {
228 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId);
229 }
Rubin Xub93522a2016-02-23 18:21:48 +0000230 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
231 return true;
Rubin Xu58d25992016-01-21 17:47:13 +0000232 }
233
Suprabh Shukla3c3af142018-03-30 00:28:37 -0700234 private Intent createSuspendedAppInterceptIntent(String suspendedPackage,
235 String suspendingPackage, String dialogMessage, int userId) {
236 final Intent interceptIntent = new Intent(mServiceContext, SuspendedAppActivity.class)
Suprabh Shuklac401f152018-04-10 17:07:32 -0700237 .putExtra(SuspendedAppActivity.EXTRA_SUSPENDED_PACKAGE, suspendedPackage)
Suprabh Shukla3c3af142018-03-30 00:28:37 -0700238 .putExtra(SuspendedAppActivity.EXTRA_DIALOG_MESSAGE, dialogMessage)
Suprabh Shuklac401f152018-04-10 17:07:32 -0700239 .putExtra(SuspendedAppActivity.EXTRA_SUSPENDING_PACKAGE, suspendingPackage)
Suprabh Shukla3c3af142018-03-30 00:28:37 -0700240 .putExtra(Intent.EXTRA_USER_ID, userId)
241 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
242 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
243
244 final Intent moreDetailsIntent = new Intent(Intent.ACTION_SHOW_SUSPENDED_APP_DETAILS)
245 .setPackage(suspendingPackage);
246 final String requiredPermission = Manifest.permission.SEND_SHOW_SUSPENDED_APP_DETAILS;
247 final ResolveInfo resolvedInfo = mSupervisor.resolveIntent(moreDetailsIntent, null, userId);
248 if (resolvedInfo != null && resolvedInfo.activityInfo != null
249 && requiredPermission.equals(resolvedInfo.activityInfo.permission)) {
250 moreDetailsIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, suspendedPackage)
251 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
252 interceptIntent.putExtra(SuspendedAppActivity.EXTRA_MORE_DETAILS_INTENT,
253 moreDetailsIntent);
254 }
255 return interceptIntent;
256 }
257
258 private boolean interceptSuspendedPackageIfNeeded() {
259 // Do not intercept if the package is not suspended
260 if (mAInfo == null || mAInfo.applicationInfo == null ||
261 (mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) {
262 return false;
263 }
264 final PackageManagerInternal pmi = mService.getPackageManagerInternalLocked();
265 if (pmi == null) {
266 return false;
267 }
268 final String suspendedPackage = mAInfo.applicationInfo.packageName;
269 final String suspendingPackage = pmi.getSuspendingPackage(suspendedPackage, mUserId);
270 if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
271 return interceptSuspendedByAdminPackage();
272 }
273 final String dialogMessage = pmi.getSuspendedDialogMessage(suspendedPackage, mUserId);
274 mIntent = createSuspendedAppInterceptIntent(suspendedPackage, suspendingPackage,
275 dialogMessage, mUserId);
276 mCallingPid = mRealCallingPid;
277 mCallingUid = mRealCallingUid;
278 mResolvedType = null;
279 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, 0);
280 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
281 return true;
282 }
283
Rubin Xub93522a2016-02-23 18:21:48 +0000284 private boolean interceptWorkProfileChallengeIfNeeded() {
Tony Mak83546a82018-01-22 13:56:20 +0000285 final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mAInfo, mUserId);
Rubin Xu58d25992016-01-21 17:47:13 +0000286 if (interceptingIntent == null) {
Rubin Xub93522a2016-02-23 18:21:48 +0000287 return false;
Rubin Xu58d25992016-01-21 17:47:13 +0000288 }
289 mIntent = interceptingIntent;
290 mCallingPid = mRealCallingPid;
291 mCallingUid = mRealCallingUid;
292 mResolvedType = null;
293 // If we are intercepting and there was a task, convert it into an extra for the
294 // ConfirmCredentials intent and unassign it, as otherwise the task will move to
295 // front even if ConfirmCredentials is cancelled.
296 if (mInTask != null) {
297 mIntent.putExtra(EXTRA_TASK_ID, mInTask.taskId);
298 mInTask = null;
299 }
Tony Mak853304c2016-04-18 15:17:41 +0100300 if (mActivityOptions == null) {
301 mActivityOptions = ActivityOptions.makeBasic();
302 }
Victor Chang89d4a9a2016-06-14 13:49:32 +0100303
304 ActivityRecord homeActivityRecord = mSupervisor.getHomeActivity();
Bryce Leeaf691c02017-03-20 14:20:22 -0700305 if (homeActivityRecord != null && homeActivityRecord.getTask() != null) {
Victor Chang89d4a9a2016-06-14 13:49:32 +0100306 // Showing credential confirmation activity in home task to avoid stopping multi-windowed
307 // mode after showing the full-screen credential confirmation activity.
Bryce Leeaf691c02017-03-20 14:20:22 -0700308 mActivityOptions.setLaunchTaskId(homeActivityRecord.getTask().taskId);
Victor Chang89d4a9a2016-06-14 13:49:32 +0100309 }
Rubin Xu58d25992016-01-21 17:47:13 +0000310
311 final UserInfo parent = mUserManager.getProfileParent(mUserId);
312 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
Rubin Xub93522a2016-02-23 18:21:48 +0000313 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
314 return true;
Rubin Xu58d25992016-01-21 17:47:13 +0000315 }
316
317 /**
318 * Creates an intent to intercept the current activity start with Confirm Credentials if needed.
319 *
320 * @return The intercepting intent if needed.
321 */
Tony Mak83546a82018-01-22 13:56:20 +0000322 private Intent interceptWithConfirmCredentialsIfNeeded(ActivityInfo aInfo, int userId) {
Benjamin Franz563707b2017-06-29 15:06:13 +0100323 if (!mUserController.shouldConfirmCredentials(userId)) {
Rubin Xu58d25992016-01-21 17:47:13 +0000324 return null;
325 }
Charles Hee7c5ced2017-04-12 16:22:35 +0100326 // TODO(b/28935539): should allow certain activities to bypass work challenge
Ben Gruver1ab3d6e2017-12-07 13:45:08 -0800327 final IntentSender target = createIntentSenderForOriginalIntent(Binder.getCallingUid(),
328 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE);
Benjamin Franz563707b2017-06-29 15:06:13 +0100329 final KeyguardManager km = (KeyguardManager) mServiceContext
Rubin Xu58d25992016-01-21 17:47:13 +0000330 .getSystemService(KEYGUARD_SERVICE);
331 final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, userId);
332 if (newIntent == null) {
333 return null;
334 }
Tony Mak4291c762016-03-24 12:23:22 +0000335 newIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
336 FLAG_ACTIVITY_TASK_ON_HOME);
Rubin Xu58d25992016-01-21 17:47:13 +0000337 newIntent.putExtra(EXTRA_PACKAGE_NAME, aInfo.packageName);
Ben Gruver1ab3d6e2017-12-07 13:45:08 -0800338 newIntent.putExtra(EXTRA_INTENT, target);
Rubin Xu58d25992016-01-21 17:47:13 +0000339 return newIntent;
340 }
341
Ben Gruver1ab3d6e2017-12-07 13:45:08 -0800342 private boolean interceptHarmfulAppIfNeeded() {
343 CharSequence harmfulAppWarning;
344 try {
Ben Gruver27ffd822018-03-07 13:24:18 -0800345 harmfulAppWarning = mService.getPackageManager()
346 .getHarmfulAppWarning(mAInfo.packageName, mUserId);
347 } catch (RemoteException ex) {
Ben Gruver1ab3d6e2017-12-07 13:45:08 -0800348 return false;
349 }
350
351 if (harmfulAppWarning == null) {
352 return false;
353 }
354
355 final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
356 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE);
357
358 mIntent = HarmfulAppWarningActivity.createHarmfulAppWarningIntent(mServiceContext,
359 mAInfo.packageName, target, harmfulAppWarning);
360
361 mCallingPid = mRealCallingPid;
362 mCallingUid = mRealCallingUid;
363 mResolvedType = null;
364
365 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId);
366 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
367 return true;
368 }
Rubin Xu58d25992016-01-21 17:47:13 +0000369}