blob: b91c7b1726f3ff0a0531a812fd267dc222a36c1b [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
Rubin Xu89927b32016-07-28 14:34:26 +010032import android.app.ActivityManager;
Tony Mak853304c2016-04-18 15:17:41 +010033import android.app.ActivityOptions;
Rubin Xu58d25992016-01-21 17:47:13 +000034import android.app.KeyguardManager;
Sudheer Shanka7a9c34b2016-03-11 12:25:51 -080035import android.app.admin.DevicePolicyManagerInternal;
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
46import com.android.internal.app.UnlaunchableAppActivity;
Sudheer Shanka7a9c34b2016-03-11 12:25:51 -080047import com.android.server.LocalServices;
Rubin Xu58d25992016-01-21 17:47:13 +000048
49/**
50 * A class that contains activity intercepting logic for {@link ActivityStarter#startActivityLocked}
51 * It's initialized
52 */
53class ActivityStartInterceptor {
54
55 private final ActivityManagerService mService;
56 private UserManager mUserManager;
57 private final ActivityStackSupervisor mSupervisor;
58
59 /*
60 * Per-intent states loaded from ActivityStarter than shouldn't be changed by any
61 * interception routines.
62 */
63 private int mRealCallingPid;
64 private int mRealCallingUid;
65 private int mUserId;
66 private int mStartFlags;
67 private String mCallingPackage;
68
69 /*
70 * Per-intent states that were load from ActivityStarter and are subject to modifications
71 * by the interception routines. After calling {@link #intercept} the caller should assign
72 * these values back to {@link ActivityStarter#startActivityLocked}'s local variables.
73 */
74 Intent mIntent;
75 int mCallingPid;
76 int mCallingUid;
77 ResolveInfo mRInfo;
78 ActivityInfo mAInfo;
79 String mResolvedType;
80 TaskRecord mInTask;
Tony Mak853304c2016-04-18 15:17:41 +010081 ActivityOptions mActivityOptions;
Rubin Xu58d25992016-01-21 17:47:13 +000082
83 ActivityStartInterceptor(ActivityManagerService service, ActivityStackSupervisor supervisor) {
84 mService = service;
85 mSupervisor = supervisor;
86 }
87
88 void setStates(int userId, int realCallingPid, int realCallingUid, int startFlags,
89 String callingPackage) {
90 mRealCallingPid = realCallingPid;
91 mRealCallingUid = realCallingUid;
92 mUserId = userId;
93 mStartFlags = startFlags;
94 mCallingPackage = callingPackage;
95 }
96
97 void intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType,
Tony Mak853304c2016-04-18 15:17:41 +010098 TaskRecord inTask, int callingPid, int callingUid, ActivityOptions activityOptions) {
Rubin Xu58d25992016-01-21 17:47:13 +000099 mUserManager = UserManager.get(mService.mContext);
100 mIntent = intent;
101 mCallingPid = callingPid;
102 mCallingUid = callingUid;
103 mRInfo = rInfo;
104 mAInfo = aInfo;
105 mResolvedType = resolvedType;
106 mInTask = inTask;
Tony Mak853304c2016-04-18 15:17:41 +0100107 mActivityOptions = activityOptions;
Rubin Xub93522a2016-02-23 18:21:48 +0000108 if (interceptSuspendPackageIfNeed()) {
109 // Skip the rest of interceptions as the package is suspended by device admin so
110 // no user action can undo this.
111 return;
112 }
113 if (interceptQuietProfileIfNeeded()) {
114 // If work profile is turned off, skip the work challenge since the profile can only
115 // be unlocked when profile's user is running.
116 return;
117 }
Rubin Xu58d25992016-01-21 17:47:13 +0000118 interceptWorkProfileChallengeIfNeeded();
119 }
120
Rubin Xub93522a2016-02-23 18:21:48 +0000121 private boolean interceptQuietProfileIfNeeded() {
Rubin Xu58d25992016-01-21 17:47:13 +0000122 // Do not intercept if the user has not turned off the profile
123 if (!mUserManager.isQuietModeEnabled(UserHandle.of(mUserId))) {
Rubin Xub93522a2016-02-23 18:21:48 +0000124 return false;
Rubin Xu58d25992016-01-21 17:47:13 +0000125 }
Rubin Xue420c552016-04-06 19:04:30 +0100126 IIntentSender target = mService.getIntentSenderLocked(
127 INTENT_SENDER_ACTIVITY, mCallingPackage, mCallingUid, mUserId, null, null, 0,
128 new Intent[] {mIntent}, new String[] {mResolvedType},
129 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT, null);
130
131 mIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId,
132 new IntentSender(target));
Rubin Xu58d25992016-01-21 17:47:13 +0000133 mCallingPid = mRealCallingPid;
134 mCallingUid = mRealCallingUid;
135 mResolvedType = null;
136
137 final UserInfo parent = mUserManager.getProfileParent(mUserId);
138 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
Rubin Xub93522a2016-02-23 18:21:48 +0000139 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
140 return true;
Rubin Xu58d25992016-01-21 17:47:13 +0000141 }
142
Rubin Xub93522a2016-02-23 18:21:48 +0000143 private boolean interceptSuspendPackageIfNeed() {
Rubin Xu58d25992016-01-21 17:47:13 +0000144 // Do not intercept if the admin did not suspend the package
145 if (mAInfo == null || mAInfo.applicationInfo == null ||
146 (mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) {
Rubin Xub93522a2016-02-23 18:21:48 +0000147 return false;
Rubin Xu58d25992016-01-21 17:47:13 +0000148 }
Sudheer Shanka7a9c34b2016-03-11 12:25:51 -0800149 DevicePolicyManagerInternal devicePolicyManager = LocalServices.getService(
150 DevicePolicyManagerInternal.class);
Makoto Onuki26704952016-06-13 14:50:11 -0700151 if (devicePolicyManager == null) {
152 return false;
153 }
Nicolas Prevot709a63d2016-06-09 13:14:00 +0100154 mIntent = devicePolicyManager.createShowAdminSupportIntent(mUserId, true);
Rubin Xu58d25992016-01-21 17:47:13 +0000155 mCallingPid = mRealCallingPid;
156 mCallingUid = mRealCallingUid;
157 mResolvedType = null;
158
159 final UserInfo parent = mUserManager.getProfileParent(mUserId);
160 if (parent != null) {
161 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
162 } else {
163 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId);
164 }
Rubin Xub93522a2016-02-23 18:21:48 +0000165 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
166 return true;
Rubin Xu58d25992016-01-21 17:47:13 +0000167 }
168
Rubin Xub93522a2016-02-23 18:21:48 +0000169 private boolean interceptWorkProfileChallengeIfNeeded() {
Rubin Xu58d25992016-01-21 17:47:13 +0000170 final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mIntent,
171 mResolvedType, mAInfo, mCallingPackage, mUserId);
172 if (interceptingIntent == null) {
Rubin Xub93522a2016-02-23 18:21:48 +0000173 return false;
Rubin Xu58d25992016-01-21 17:47:13 +0000174 }
175 mIntent = interceptingIntent;
176 mCallingPid = mRealCallingPid;
177 mCallingUid = mRealCallingUid;
178 mResolvedType = null;
179 // If we are intercepting and there was a task, convert it into an extra for the
180 // ConfirmCredentials intent and unassign it, as otherwise the task will move to
181 // front even if ConfirmCredentials is cancelled.
182 if (mInTask != null) {
183 mIntent.putExtra(EXTRA_TASK_ID, mInTask.taskId);
184 mInTask = null;
185 }
Tony Mak853304c2016-04-18 15:17:41 +0100186 if (mActivityOptions == null) {
187 mActivityOptions = ActivityOptions.makeBasic();
188 }
Victor Chang89d4a9a2016-06-14 13:49:32 +0100189
190 ActivityRecord homeActivityRecord = mSupervisor.getHomeActivity();
Bryce Leeaf691c02017-03-20 14:20:22 -0700191 if (homeActivityRecord != null && homeActivityRecord.getTask() != null) {
Victor Chang89d4a9a2016-06-14 13:49:32 +0100192 // Showing credential confirmation activity in home task to avoid stopping multi-windowed
193 // mode after showing the full-screen credential confirmation activity.
Bryce Leeaf691c02017-03-20 14:20:22 -0700194 mActivityOptions.setLaunchTaskId(homeActivityRecord.getTask().taskId);
Victor Chang89d4a9a2016-06-14 13:49:32 +0100195 }
Rubin Xu58d25992016-01-21 17:47:13 +0000196
197 final UserInfo parent = mUserManager.getProfileParent(mUserId);
198 mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
Rubin Xub93522a2016-02-23 18:21:48 +0000199 mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
200 return true;
Rubin Xu58d25992016-01-21 17:47:13 +0000201 }
202
203 /**
204 * Creates an intent to intercept the current activity start with Confirm Credentials if needed.
205 *
206 * @return The intercepting intent if needed.
207 */
208 private Intent interceptWithConfirmCredentialsIfNeeded(Intent intent, String resolvedType,
209 ActivityInfo aInfo, String callingPackage, int userId) {
210 if (!mService.mUserController.shouldConfirmCredentials(userId)) {
211 return null;
212 }
Charles Hee7c5ced2017-04-12 16:22:35 +0100213 // TODO(b/28935539): should allow certain activities to bypass work challenge
Rubin Xu58d25992016-01-21 17:47:13 +0000214 final IIntentSender target = mService.getIntentSenderLocked(
215 INTENT_SENDER_ACTIVITY, callingPackage,
216 Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
217 new String[]{ resolvedType },
218 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE, null);
Rubin Xu58d25992016-01-21 17:47:13 +0000219 final KeyguardManager km = (KeyguardManager) mService.mContext
220 .getSystemService(KEYGUARD_SERVICE);
221 final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, userId);
222 if (newIntent == null) {
223 return null;
224 }
Tony Mak4291c762016-03-24 12:23:22 +0000225 newIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
226 FLAG_ACTIVITY_TASK_ON_HOME);
Rubin Xu58d25992016-01-21 17:47:13 +0000227 newIntent.putExtra(EXTRA_PACKAGE_NAME, aInfo.packageName);
228 newIntent.putExtra(EXTRA_INTENT, new IntentSender(target));
229 return newIntent;
230 }
231
232}