• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.server.wm;
18 
19 import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY;
20 import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
21 import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
22 import static android.app.PendingIntent.FLAG_IMMUTABLE;
23 import static android.app.PendingIntent.FLAG_ONE_SHOT;
24 import static android.app.admin.DevicePolicyManager.EXTRA_RESTRICTION;
25 import static android.app.admin.DevicePolicyManager.POLICY_SUSPEND_PACKAGES;
26 import static android.content.Context.KEYGUARD_SERVICE;
27 import static android.content.Intent.EXTRA_INTENT;
28 import static android.content.Intent.EXTRA_PACKAGE_NAME;
29 import static android.content.Intent.EXTRA_TASK_ID;
30 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
31 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
32 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
33 import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
34 
35 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
36 
37 import android.annotation.Nullable;
38 import android.app.ActivityOptions;
39 import android.app.KeyguardManager;
40 import android.app.admin.DevicePolicyManagerInternal;
41 import android.content.Context;
42 import android.content.IIntentSender;
43 import android.content.Intent;
44 import android.content.IntentSender;
45 import android.content.pm.ActivityInfo;
46 import android.content.pm.PackageManagerInternal;
47 import android.content.pm.ResolveInfo;
48 import android.content.pm.SuspendDialogInfo;
49 import android.content.pm.UserInfo;
50 import android.os.Bundle;
51 import android.os.RemoteException;
52 import android.os.UserHandle;
53 import android.os.UserManager;
54 
55 import com.android.internal.annotations.VisibleForTesting;
56 import com.android.internal.app.BlockedAppActivity;
57 import com.android.internal.app.HarmfulAppWarningActivity;
58 import com.android.internal.app.SuspendedAppActivity;
59 import com.android.internal.app.UnlaunchableAppActivity;
60 import com.android.server.LocalServices;
61 import com.android.server.am.ActivityManagerService;
62 
63 /**
64  * A class that contains activity intercepting logic for {@link ActivityStarter#startActivityLocked}
65  * It's initialized via setStates and interception occurs via the intercept method.
66  *
67  * Note that this class is instantiated when {@link ActivityManagerService} gets created so there
68  * is no guarantee that other system services are already present.
69  */
70 class ActivityStartInterceptor {
71 
72     private final ActivityTaskManagerService mService;
73     private final ActivityTaskSupervisor mSupervisor;
74     private final RootWindowContainer mRootWindowContainer;
75     private final Context mServiceContext;
76 
77     // UserManager cannot be final as it's not ready when this class is instantiated during boot
78     private UserManager mUserManager;
79 
80     /*
81      * Per-intent states loaded from ActivityStarter than shouldn't be changed by any
82      * interception routines.
83      */
84     private int mRealCallingPid;
85     private int mRealCallingUid;
86     private int mUserId;
87     private int mStartFlags;
88     private String mCallingPackage;
89     private @Nullable String mCallingFeatureId;
90 
91     /*
92      * Per-intent states that were load from ActivityStarter and are subject to modifications
93      * by the interception routines. After calling {@link #intercept} the caller should assign
94      * these values back to {@link ActivityStarter#startActivityLocked}'s local variables if
95      * {@link #intercept} returns true.
96      */
97     Intent mIntent;
98     int mCallingPid;
99     int mCallingUid;
100     ResolveInfo mRInfo;
101     ActivityInfo mAInfo;
102     String mResolvedType;
103     Task mInTask;
104     ActivityOptions mActivityOptions;
105 
ActivityStartInterceptor( ActivityTaskManagerService service, ActivityTaskSupervisor supervisor)106     ActivityStartInterceptor(
107             ActivityTaskManagerService service, ActivityTaskSupervisor supervisor) {
108         this(service, supervisor, service.mRootWindowContainer, service.mContext);
109     }
110 
111     @VisibleForTesting
ActivityStartInterceptor(ActivityTaskManagerService service, ActivityTaskSupervisor supervisor, RootWindowContainer root, Context context)112     ActivityStartInterceptor(ActivityTaskManagerService service, ActivityTaskSupervisor supervisor,
113             RootWindowContainer root, Context context) {
114         mService = service;
115         mSupervisor = supervisor;
116         mRootWindowContainer = root;
117         mServiceContext = context;
118     }
119 
120     /**
121      * Effectively initialize the class before intercepting the start intent. The values set in this
122      * method should not be changed during intercept.
123      */
setStates(int userId, int realCallingPid, int realCallingUid, int startFlags, String callingPackage, @Nullable String callingFeatureId)124     void setStates(int userId, int realCallingPid, int realCallingUid, int startFlags,
125             String callingPackage, @Nullable String callingFeatureId) {
126         mRealCallingPid = realCallingPid;
127         mRealCallingUid = realCallingUid;
128         mUserId = userId;
129         mStartFlags = startFlags;
130         mCallingPackage = callingPackage;
131         mCallingFeatureId = callingFeatureId;
132     }
133 
createIntentSenderForOriginalIntent(int callingUid, int flags)134     private IntentSender createIntentSenderForOriginalIntent(int callingUid, int flags) {
135         Bundle activityOptions = deferCrossProfileAppsAnimationIfNecessary();
136         final IIntentSender target = mService.getIntentSenderLocked(
137                 INTENT_SENDER_ACTIVITY, mCallingPackage, mCallingFeatureId, callingUid, mUserId,
138                 null /*token*/, null /*resultCode*/, 0 /*requestCode*/,
139                 new Intent[] { mIntent }, new String[] { mResolvedType },
140                 flags, activityOptions);
141         return new IntentSender(target);
142     }
143 
144     /**
145      * Intercept the launch intent based on various signals. If an interception happened the
146      * internal variables get assigned and need to be read explicitly by the caller.
147      *
148      * @return true if an interception occurred
149      */
intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType, Task inTask, int callingPid, int callingUid, ActivityOptions activityOptions)150     boolean intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType,
151             Task inTask, int callingPid, int callingUid, ActivityOptions activityOptions) {
152         mUserManager = UserManager.get(mServiceContext);
153 
154         mIntent = intent;
155         mCallingPid = callingPid;
156         mCallingUid = callingUid;
157         mRInfo = rInfo;
158         mAInfo = aInfo;
159         mResolvedType = resolvedType;
160         mInTask = inTask;
161         mActivityOptions = activityOptions;
162 
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.
166             return true;
167         }
168         if (interceptSuspendedPackageIfNeeded()) {
169             // Skip the rest of interceptions as the package is suspended by device admin so
170             // no user action can undo this.
171             return true;
172         }
173         if (interceptLockTaskModeViolationPackageIfNeeded()) {
174             return true;
175         }
176         if (interceptHarmfulAppIfNeeded()) {
177             // If the app has a "harmful app" warning associated with it, we should ask to uninstall
178             // before issuing the work challenge.
179             return true;
180         }
181         return interceptLockedManagedProfileIfNeeded();
182     }
183 
hasCrossProfileAnimation()184     private boolean hasCrossProfileAnimation() {
185         return mActivityOptions != null
186                 && mActivityOptions.getAnimationType() == ANIM_OPEN_CROSS_PROFILE_APPS;
187     }
188 
189     /**
190      * If the activity option is the {@link ActivityOptions#ANIM_OPEN_CROSS_PROFILE_APPS} one,
191      * defer the animation until the original intent is started.
192      *
193      * @return the activity option used to start the original intent.
194      */
deferCrossProfileAppsAnimationIfNecessary()195     private Bundle deferCrossProfileAppsAnimationIfNecessary() {
196         if (hasCrossProfileAnimation()) {
197             mActivityOptions = null;
198             return ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle();
199         }
200         return null;
201     }
202 
interceptQuietProfileIfNeeded()203     private boolean interceptQuietProfileIfNeeded() {
204         // Do not intercept if the user has not turned off the profile
205         if (!mUserManager.isQuietModeEnabled(UserHandle.of(mUserId))) {
206             return false;
207         }
208 
209         IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
210                 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT);
211 
212         mIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId, target);
213         mCallingPid = mRealCallingPid;
214         mCallingUid = mRealCallingUid;
215         mResolvedType = null;
216 
217         final UserInfo parent = mUserManager.getProfileParent(mUserId);
218         mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0, mRealCallingUid);
219         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
220         return true;
221     }
222 
interceptSuspendedByAdminPackage()223     private boolean interceptSuspendedByAdminPackage() {
224         DevicePolicyManagerInternal devicePolicyManager = LocalServices
225                 .getService(DevicePolicyManagerInternal.class);
226         if (devicePolicyManager == null) {
227             return false;
228         }
229         mIntent = devicePolicyManager.createShowAdminSupportIntent(mUserId, true);
230         mIntent.putExtra(EXTRA_RESTRICTION, POLICY_SUSPEND_PACKAGES);
231 
232         mCallingPid = mRealCallingPid;
233         mCallingUid = mRealCallingUid;
234         mResolvedType = null;
235 
236         final UserInfo parent = mUserManager.getProfileParent(mUserId);
237         if (parent != null) {
238             mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0,
239                     mRealCallingUid);
240         } else {
241             mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0,
242                     mRealCallingUid);
243         }
244         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
245         return true;
246     }
247 
interceptSuspendedPackageIfNeeded()248     private boolean interceptSuspendedPackageIfNeeded() {
249         // Do not intercept if the package is not suspended
250         if (mAInfo == null || mAInfo.applicationInfo == null ||
251                 (mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) {
252             return false;
253         }
254         final PackageManagerInternal pmi = mService.getPackageManagerInternalLocked();
255         if (pmi == null) {
256             return false;
257         }
258         final String suspendedPackage = mAInfo.applicationInfo.packageName;
259         final String suspendingPackage = pmi.getSuspendingPackage(suspendedPackage, mUserId);
260         if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
261             return interceptSuspendedByAdminPackage();
262         }
263         final SuspendDialogInfo dialogInfo = pmi.getSuspendedDialogInfo(suspendedPackage,
264                 suspendingPackage, mUserId);
265         final Bundle crossProfileOptions = hasCrossProfileAnimation()
266                 ? ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle()
267                 : null;
268         final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
269                 FLAG_IMMUTABLE);
270         mIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(suspendedPackage,
271                 suspendingPackage, dialogInfo, crossProfileOptions, target, mUserId);
272         mCallingPid = mRealCallingPid;
273         mCallingUid = mRealCallingUid;
274         mResolvedType = null;
275         mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, mRealCallingUid);
276         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
277         return true;
278     }
279 
interceptLockTaskModeViolationPackageIfNeeded()280     private boolean interceptLockTaskModeViolationPackageIfNeeded() {
281         if (mAInfo == null || mAInfo.applicationInfo == null) {
282             return false;
283         }
284         LockTaskController controller = mService.getLockTaskController();
285         String packageName = mAInfo.applicationInfo.packageName;
286         int lockTaskLaunchMode = ActivityRecord.getLockTaskLaunchMode(mAInfo, mActivityOptions);
287         if (controller.isActivityAllowed(mUserId, packageName, lockTaskLaunchMode)) {
288             return false;
289         }
290         mIntent = BlockedAppActivity.createIntent(mUserId, mAInfo.applicationInfo.packageName);
291         mCallingPid = mRealCallingPid;
292         mCallingUid = mRealCallingUid;
293         mResolvedType = null;
294         mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, mRealCallingUid);
295         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
296         return true;
297     }
298 
interceptLockedManagedProfileIfNeeded()299     private boolean interceptLockedManagedProfileIfNeeded() {
300         final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mAInfo, mUserId);
301         if (interceptingIntent == null) {
302             return false;
303         }
304         mIntent = interceptingIntent;
305         mCallingPid = mRealCallingPid;
306         mCallingUid = mRealCallingUid;
307         mResolvedType = null;
308         // If we are intercepting and there was a task, convert it into an extra for the
309         // ConfirmCredentials intent and unassign it, as otherwise the task will move to
310         // front even if ConfirmCredentials is cancelled.
311         if (mInTask != null) {
312             mIntent.putExtra(EXTRA_TASK_ID, mInTask.mTaskId);
313             mInTask = null;
314         }
315         if (mActivityOptions == null) {
316             mActivityOptions = ActivityOptions.makeBasic();
317         }
318 
319         final UserInfo parent = mUserManager.getProfileParent(mUserId);
320         mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0, mRealCallingUid);
321         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
322         return true;
323     }
324 
325     /**
326      * Creates an intent to intercept the current activity start with Confirm Credentials if needed.
327      *
328      * @return The intercepting intent if needed.
329      */
interceptWithConfirmCredentialsIfNeeded(ActivityInfo aInfo, int userId)330     private Intent interceptWithConfirmCredentialsIfNeeded(ActivityInfo aInfo, int userId) {
331         if (!mService.mAmInternal.shouldConfirmCredentials(userId)) {
332             return null;
333         }
334         // TODO(b/28935539): should allow certain activities to bypass work challenge
335         final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
336                 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE);
337         final KeyguardManager km = (KeyguardManager) mServiceContext
338                 .getSystemService(KEYGUARD_SERVICE);
339         final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, userId,
340                 true /* disallowBiometricsIfPolicyExists */);
341         if (newIntent == null) {
342             return null;
343         }
344         newIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
345                 FLAG_ACTIVITY_TASK_ON_HOME);
346         newIntent.putExtra(EXTRA_PACKAGE_NAME, aInfo.packageName);
347         newIntent.putExtra(EXTRA_INTENT, target);
348         return newIntent;
349     }
350 
interceptHarmfulAppIfNeeded()351     private boolean interceptHarmfulAppIfNeeded() {
352         CharSequence harmfulAppWarning;
353         try {
354             harmfulAppWarning = mService.getPackageManager()
355                     .getHarmfulAppWarning(mAInfo.packageName, mUserId);
356         } catch (RemoteException ex) {
357             return false;
358         }
359 
360         if (harmfulAppWarning == null) {
361             return false;
362         }
363 
364         final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
365                 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE);
366 
367         mIntent = HarmfulAppWarningActivity.createHarmfulAppWarningIntent(mServiceContext,
368                 mAInfo.packageName, target, harmfulAppWarning);
369 
370         mCallingPid = mRealCallingPid;
371         mCallingUid = mRealCallingUid;
372         mResolvedType = null;
373 
374         mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, mRealCallingUid);
375         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
376         return true;
377     }
378 }
379