• 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.TaskInfo;
41 import android.app.admin.DevicePolicyManagerInternal;
42 import android.content.Context;
43 import android.content.IIntentSender;
44 import android.content.Intent;
45 import android.content.IntentSender;
46 import android.content.pm.ActivityInfo;
47 import android.content.pm.PackageManagerInternal;
48 import android.content.pm.ResolveInfo;
49 import android.content.pm.SuspendDialogInfo;
50 import android.content.pm.UserInfo;
51 import android.os.Bundle;
52 import android.os.IBinder;
53 import android.os.RemoteException;
54 import android.os.UserHandle;
55 import android.os.UserManager;
56 import android.util.SparseArray;
57 
58 import com.android.internal.annotations.VisibleForTesting;
59 import com.android.internal.app.BlockedAppActivity;
60 import com.android.internal.app.HarmfulAppWarningActivity;
61 import com.android.internal.app.SuspendedAppActivity;
62 import com.android.internal.app.UnlaunchableAppActivity;
63 import com.android.server.LocalServices;
64 import com.android.server.am.ActivityManagerService;
65 import com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptResult;
66 
67 /**
68  * A class that contains activity intercepting logic for {@link ActivityStarter#execute()}
69  * It's initialized via setStates and interception occurs via the intercept method.
70  *
71  * Note that this class is instantiated when {@link ActivityManagerService} gets created so there
72  * is no guarantee that other system services are already present.
73  */
74 class ActivityStartInterceptor {
75 
76     private final ActivityTaskManagerService mService;
77     private final ActivityTaskSupervisor mSupervisor;
78     private final RootWindowContainer mRootWindowContainer;
79     private final Context mServiceContext;
80 
81     // UserManager cannot be final as it's not ready when this class is instantiated during boot
82     private UserManager mUserManager;
83 
84     /*
85      * Per-intent states loaded from ActivityStarter than shouldn't be changed by any
86      * interception routines.
87      */
88     private int mRealCallingPid;
89     private int mRealCallingUid;
90     private int mUserId;
91     private int mStartFlags;
92     private String mCallingPackage;
93     private @Nullable String mCallingFeatureId;
94 
95     /*
96      * Per-intent states that were load from ActivityStarter and are subject to modifications
97      * by the interception routines. After calling {@link #intercept} the caller should assign
98      * these values back to {@link ActivityStarter#startActivityLocked}'s local variables if
99      * {@link #intercept} returns true.
100      */
101     Intent mIntent;
102     int mCallingPid;
103     int mCallingUid;
104     ResolveInfo mRInfo;
105     ActivityInfo mAInfo;
106     String mResolvedType;
107     Task mInTask;
108     TaskFragment mInTaskFragment;
109     ActivityOptions mActivityOptions;
110 
ActivityStartInterceptor( ActivityTaskManagerService service, ActivityTaskSupervisor supervisor)111     ActivityStartInterceptor(
112             ActivityTaskManagerService service, ActivityTaskSupervisor supervisor) {
113         this(service, supervisor, service.mRootWindowContainer, service.mContext);
114     }
115 
116     @VisibleForTesting
ActivityStartInterceptor(ActivityTaskManagerService service, ActivityTaskSupervisor supervisor, RootWindowContainer root, Context context)117     ActivityStartInterceptor(ActivityTaskManagerService service, ActivityTaskSupervisor supervisor,
118             RootWindowContainer root, Context context) {
119         mService = service;
120         mSupervisor = supervisor;
121         mRootWindowContainer = root;
122         mServiceContext = context;
123     }
124 
125     /**
126      * Effectively initialize the class before intercepting the start intent. The values set in this
127      * method should not be changed during intercept.
128      */
setStates(int userId, int realCallingPid, int realCallingUid, int startFlags, String callingPackage, @Nullable String callingFeatureId)129     void setStates(int userId, int realCallingPid, int realCallingUid, int startFlags,
130             String callingPackage, @Nullable String callingFeatureId) {
131         mRealCallingPid = realCallingPid;
132         mRealCallingUid = realCallingUid;
133         mUserId = userId;
134         mStartFlags = startFlags;
135         mCallingPackage = callingPackage;
136         mCallingFeatureId = callingFeatureId;
137     }
138 
createIntentSenderForOriginalIntent(int callingUid, int flags)139     private IntentSender createIntentSenderForOriginalIntent(int callingUid, int flags) {
140         Bundle bOptions = deferCrossProfileAppsAnimationIfNecessary();
141         final TaskFragment taskFragment = getLaunchTaskFragment();
142         // If the original intent is going to be embedded, try to forward the embedding TaskFragment
143         // and its task id to embed back the original intent.
144         if (taskFragment != null) {
145             ActivityOptions activityOptions = bOptions != null
146                     ? ActivityOptions.fromBundle(bOptions)
147                     : ActivityOptions.makeBasic();
148             activityOptions.setLaunchTaskFragmentToken(taskFragment.getFragmentToken());
149             bOptions = activityOptions.toBundle();
150         }
151         final IIntentSender target = mService.getIntentSenderLocked(
152                 INTENT_SENDER_ACTIVITY, mCallingPackage, mCallingFeatureId, callingUid, mUserId,
153                 null /*token*/, null /*resultCode*/, 0 /*requestCode*/,
154                 new Intent[] { mIntent }, new String[] { mResolvedType },
155                 flags, bOptions);
156         return new IntentSender(target);
157     }
158 
159 
160     /**
161      * A helper function to obtain the targeted {@link TaskFragment} during
162      * {@link #intercept(Intent, ResolveInfo, ActivityInfo, String, Task, TaskFragment, int, int,
163      * ActivityOptions)} if any.
164      */
165     @Nullable
getLaunchTaskFragment()166     private TaskFragment getLaunchTaskFragment() {
167         if (mInTaskFragment != null) {
168             return mInTaskFragment;
169         }
170         if (mActivityOptions == null) {
171             return null;
172         }
173         final IBinder taskFragToken = mActivityOptions.getLaunchTaskFragmentToken();
174         if (taskFragToken == null) {
175             return null;
176         }
177         return TaskFragment.fromTaskFragmentToken(taskFragToken, mService);
178     }
179 
180     /**
181      * Intercept the launch intent based on various signals. If an interception happened the
182      * internal variables get assigned and need to be read explicitly by the caller.
183      *
184      * @return true if an interception occurred
185      */
intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType, Task inTask, TaskFragment inTaskFragment, int callingPid, int callingUid, ActivityOptions activityOptions)186     boolean intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType,
187             Task inTask, TaskFragment inTaskFragment, int callingPid, int callingUid,
188             ActivityOptions activityOptions) {
189         mUserManager = UserManager.get(mServiceContext);
190 
191         mIntent = intent;
192         mCallingPid = callingPid;
193         mCallingUid = callingUid;
194         mRInfo = rInfo;
195         mAInfo = aInfo;
196         mResolvedType = resolvedType;
197         mInTask = inTask;
198         mInTaskFragment = inTaskFragment;
199         mActivityOptions = activityOptions;
200 
201         if (interceptQuietProfileIfNeeded()) {
202             // If work profile is turned off, skip the work challenge since the profile can only
203             // be unlocked when profile's user is running.
204             return true;
205         }
206         if (interceptSuspendedPackageIfNeeded()) {
207             // Skip the rest of interceptions as the package is suspended by device admin so
208             // no user action can undo this.
209             return true;
210         }
211         if (interceptLockTaskModeViolationPackageIfNeeded()) {
212             return true;
213         }
214         if (interceptHarmfulAppIfNeeded()) {
215             // If the app has a "harmful app" warning associated with it, we should ask to uninstall
216             // before issuing the work challenge.
217             return true;
218         }
219         if (interceptLockedManagedProfileIfNeeded()) {
220             return true;
221         }
222 
223         final SparseArray<ActivityInterceptorCallback> callbacks =
224                 mService.getActivityInterceptorCallbacks();
225         final ActivityInterceptorCallback.ActivityInterceptorInfo interceptorInfo =
226                 getInterceptorInfo(null /* clearOptionsAnimation */);
227 
228         for (int i = 0; i < callbacks.size(); i++) {
229             final ActivityInterceptorCallback callback = callbacks.valueAt(i);
230             final ActivityInterceptResult interceptResult = callback.intercept(interceptorInfo);
231             if (interceptResult == null) {
232                 continue;
233             }
234             mIntent = interceptResult.intent;
235             mActivityOptions = interceptResult.activityOptions;
236             mCallingPid = mRealCallingPid;
237             mCallingUid = mRealCallingUid;
238             mRInfo = mSupervisor.resolveIntent(mIntent, null, mUserId, 0, mRealCallingUid);
239             mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags,
240                     null /*profilerInfo*/);
241             return true;
242         }
243         return false;
244     }
245 
hasCrossProfileAnimation()246     private boolean hasCrossProfileAnimation() {
247         return mActivityOptions != null
248                 && mActivityOptions.getAnimationType() == ANIM_OPEN_CROSS_PROFILE_APPS;
249     }
250 
251     /**
252      * If the activity option is the {@link ActivityOptions#ANIM_OPEN_CROSS_PROFILE_APPS} one,
253      * defer the animation until the original intent is started.
254      *
255      * @return the activity option used to start the original intent.
256      */
deferCrossProfileAppsAnimationIfNecessary()257     private Bundle deferCrossProfileAppsAnimationIfNecessary() {
258         if (hasCrossProfileAnimation()) {
259             mActivityOptions = null;
260             return ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle();
261         }
262         return null;
263     }
264 
interceptQuietProfileIfNeeded()265     private boolean interceptQuietProfileIfNeeded() {
266         // Do not intercept if the user has not turned off the profile
267         if (!mUserManager.isQuietModeEnabled(UserHandle.of(mUserId))) {
268             return false;
269         }
270 
271         IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
272                 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT);
273 
274         mIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId, target);
275         mCallingPid = mRealCallingPid;
276         mCallingUid = mRealCallingUid;
277         mResolvedType = null;
278 
279         final UserInfo parent = mUserManager.getProfileParent(mUserId);
280         mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0, mRealCallingUid);
281         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
282         return true;
283     }
284 
interceptSuspendedByAdminPackage()285     private boolean interceptSuspendedByAdminPackage() {
286         DevicePolicyManagerInternal devicePolicyManager = LocalServices
287                 .getService(DevicePolicyManagerInternal.class);
288         if (devicePolicyManager == null) {
289             return false;
290         }
291         mIntent = devicePolicyManager.createShowAdminSupportIntent(mUserId, true);
292         mIntent.putExtra(EXTRA_RESTRICTION, POLICY_SUSPEND_PACKAGES);
293 
294         mCallingPid = mRealCallingPid;
295         mCallingUid = mRealCallingUid;
296         mResolvedType = null;
297 
298         final UserInfo parent = mUserManager.getProfileParent(mUserId);
299         if (parent != null) {
300             mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0,
301                     mRealCallingUid);
302         } else {
303             mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0,
304                     mRealCallingUid);
305         }
306         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
307         return true;
308     }
309 
interceptSuspendedPackageIfNeeded()310     private boolean interceptSuspendedPackageIfNeeded() {
311         // Do not intercept if the package is not suspended
312         if (mAInfo == null || mAInfo.applicationInfo == null ||
313                 (mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) {
314             return false;
315         }
316         final PackageManagerInternal pmi = mService.getPackageManagerInternalLocked();
317         if (pmi == null) {
318             return false;
319         }
320         final String suspendedPackage = mAInfo.applicationInfo.packageName;
321         final String suspendingPackage = pmi.getSuspendingPackage(suspendedPackage, mUserId);
322         if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
323             return interceptSuspendedByAdminPackage();
324         }
325         final SuspendDialogInfo dialogInfo = pmi.getSuspendedDialogInfo(suspendedPackage,
326                 suspendingPackage, mUserId);
327         final Bundle crossProfileOptions = hasCrossProfileAnimation()
328                 ? ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle()
329                 : null;
330         final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
331                 FLAG_IMMUTABLE);
332         mIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(suspendedPackage,
333                 suspendingPackage, dialogInfo, crossProfileOptions, target, mUserId);
334         mCallingPid = mRealCallingPid;
335         mCallingUid = mRealCallingUid;
336         mResolvedType = null;
337         mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, mRealCallingUid);
338         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
339         return true;
340     }
341 
interceptLockTaskModeViolationPackageIfNeeded()342     private boolean interceptLockTaskModeViolationPackageIfNeeded() {
343         if (mAInfo == null || mAInfo.applicationInfo == null) {
344             return false;
345         }
346         LockTaskController controller = mService.getLockTaskController();
347         String packageName = mAInfo.applicationInfo.packageName;
348         int lockTaskLaunchMode = ActivityRecord.getLockTaskLaunchMode(mAInfo, mActivityOptions);
349         if (controller.isActivityAllowed(mUserId, packageName, lockTaskLaunchMode)) {
350             return false;
351         }
352         mIntent = BlockedAppActivity.createIntent(mUserId, mAInfo.applicationInfo.packageName);
353         mCallingPid = mRealCallingPid;
354         mCallingUid = mRealCallingUid;
355         mResolvedType = null;
356         mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, mRealCallingUid);
357         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
358         return true;
359     }
360 
interceptLockedManagedProfileIfNeeded()361     private boolean interceptLockedManagedProfileIfNeeded() {
362         final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mAInfo, mUserId);
363         if (interceptingIntent == null) {
364             return false;
365         }
366         mIntent = interceptingIntent;
367         mCallingPid = mRealCallingPid;
368         mCallingUid = mRealCallingUid;
369         mResolvedType = null;
370         final TaskFragment taskFragment = getLaunchTaskFragment();
371         // If we are intercepting and there was a task, convert it into an extra for the
372         // ConfirmCredentials intent and unassign it, as otherwise the task will move to
373         // front even if ConfirmCredentials is cancelled.
374         if (mInTask != null) {
375             mIntent.putExtra(EXTRA_TASK_ID, mInTask.mTaskId);
376             mInTask = null;
377         } else if (taskFragment != null) {
378             // If the original intent is started to an embedded TaskFragment, append its parent task
379             // id to extra. It is to embed back the original intent to the TaskFragment with the
380             // same task.
381             final Task parentTask = taskFragment.getTask();
382             if (parentTask != null) {
383                 mIntent.putExtra(EXTRA_TASK_ID, parentTask.mTaskId);
384             }
385         }
386         if (mActivityOptions == null) {
387             mActivityOptions = ActivityOptions.makeBasic();
388         }
389 
390         final UserInfo parent = mUserManager.getProfileParent(mUserId);
391         mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0, mRealCallingUid);
392         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
393         return true;
394     }
395 
396     /**
397      * Creates an intent to intercept the current activity start with Confirm Credentials if needed.
398      *
399      * @return The intercepting intent if needed.
400      */
interceptWithConfirmCredentialsIfNeeded(ActivityInfo aInfo, int userId)401     private Intent interceptWithConfirmCredentialsIfNeeded(ActivityInfo aInfo, int userId) {
402         if ((aInfo.flags & ActivityInfo.FLAG_SHOW_WHEN_LOCKED) != 0
403                 || !mService.mAmInternal.shouldConfirmCredentials(userId)) {
404             return null;
405         }
406         final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
407                 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE);
408         final KeyguardManager km = (KeyguardManager) mServiceContext
409                 .getSystemService(KEYGUARD_SERVICE);
410         final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, userId,
411                 true /* disallowBiometricsIfPolicyExists */);
412         if (newIntent == null) {
413             return null;
414         }
415         newIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
416                 FLAG_ACTIVITY_TASK_ON_HOME);
417         newIntent.putExtra(EXTRA_PACKAGE_NAME, aInfo.packageName);
418         newIntent.putExtra(EXTRA_INTENT, target);
419         return newIntent;
420     }
421 
interceptHarmfulAppIfNeeded()422     private boolean interceptHarmfulAppIfNeeded() {
423         CharSequence harmfulAppWarning;
424         try {
425             harmfulAppWarning = mService.getPackageManager()
426                     .getHarmfulAppWarning(mAInfo.packageName, mUserId);
427         } catch (RemoteException | IllegalArgumentException ex) {
428             return false;
429         }
430 
431         if (harmfulAppWarning == null) {
432             return false;
433         }
434 
435         final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
436                 FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE);
437 
438         mIntent = HarmfulAppWarningActivity.createHarmfulAppWarningIntent(mServiceContext,
439                 mAInfo.packageName, target, harmfulAppWarning);
440 
441         mCallingPid = mRealCallingPid;
442         mCallingUid = mRealCallingUid;
443         mResolvedType = null;
444 
445         mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, mRealCallingUid);
446         mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
447         return true;
448     }
449 
450     /**
451      * Called when an activity is successfully launched.
452      */
onActivityLaunched(TaskInfo taskInfo, ActivityRecord r)453     void onActivityLaunched(TaskInfo taskInfo, ActivityRecord r) {
454         final SparseArray<ActivityInterceptorCallback> callbacks =
455                 mService.getActivityInterceptorCallbacks();
456         ActivityInterceptorCallback.ActivityInterceptorInfo info = getInterceptorInfo(
457                 r::clearOptionsAnimationForSiblings);
458         for (int i = 0; i < callbacks.size(); i++) {
459             final ActivityInterceptorCallback callback = callbacks.valueAt(i);
460             callback.onActivityLaunched(taskInfo, r.info, info);
461         }
462     }
463 
getInterceptorInfo( @ullable Runnable clearOptionsAnimation)464     private ActivityInterceptorCallback.ActivityInterceptorInfo getInterceptorInfo(
465             @Nullable Runnable clearOptionsAnimation) {
466         return new ActivityInterceptorCallback.ActivityInterceptorInfo(mRealCallingUid,
467                 mRealCallingPid, mUserId, mCallingPackage, mCallingFeatureId, mIntent,
468                 mRInfo, mAInfo, mResolvedType, mCallingPid, mCallingUid,
469                 mActivityOptions, clearOptionsAnimation);
470     }
471 }
472