• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.Manifest.permission.CONTROL_KEYGUARD;
20 import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
21 import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS;
22 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
23 import static android.Manifest.permission.STATUS_BAR_SERVICE;
24 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
25 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
26 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
27 import static android.app.WindowConfiguration.activityTypeToString;
28 import static android.content.pm.PackageManager.PERMISSION_DENIED;
29 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
30 import static android.view.Display.DEFAULT_DISPLAY;
31 import static android.view.Display.INVALID_DISPLAY;
32 import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
33 
34 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
35 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
36 
37 import android.annotation.Nullable;
38 import android.app.ActivityOptions;
39 import android.app.AppGlobals;
40 import android.app.PendingIntent;
41 import android.content.Intent;
42 import android.content.pm.ActivityInfo;
43 import android.content.pm.PackageManager;
44 import android.os.Binder;
45 import android.os.Bundle;
46 import android.os.Process;
47 import android.os.RemoteException;
48 import android.os.UserHandle;
49 import android.util.Slog;
50 import android.view.RemoteAnimationAdapter;
51 import android.window.RemoteTransition;
52 import android.window.WindowContainerToken;
53 
54 import com.android.internal.annotations.VisibleForTesting;
55 
56 /**
57  * Wraps {@link ActivityOptions}, records binder identity, and checks permission when retrieving
58  * the inner options. Also supports having two set of options: Once from the original caller, and
59  * once from the caller that is overriding it, which happens when sending a {@link PendingIntent}.
60  */
61 public class SafeActivityOptions {
62 
63     private static final String TAG = TAG_WITH_CLASS_NAME ? "SafeActivityOptions" : TAG_ATM;
64 
65     private final int mOriginalCallingPid;
66     private final int mOriginalCallingUid;
67     private int mRealCallingPid;
68     private int mRealCallingUid;
69     private final @Nullable ActivityOptions mOriginalOptions;
70     private @Nullable ActivityOptions mCallerOptions;
71 
72     /**
73      * Constructs a new instance from a bundle and provided pid/uid.
74      *
75      * @param bOptions The {@link ActivityOptions} as {@link Bundle}.
76      */
fromBundle(Bundle bOptions, int callingPid, int callingUid)77     static SafeActivityOptions fromBundle(Bundle bOptions, int callingPid, int callingUid) {
78         return bOptions != null
79                 ? new SafeActivityOptions(ActivityOptions.fromBundle(bOptions),
80                         callingPid, callingUid)
81                 : null;
82     }
83 
84     /**
85      * Constructs a new instance.
86      *
87      * @param options The options to wrap.
88      */
SafeActivityOptions(@ullable ActivityOptions options, int callingPid, int callingUid)89     public SafeActivityOptions(@Nullable ActivityOptions options, int callingPid, int callingUid) {
90         mOriginalCallingPid = callingPid;
91         mOriginalCallingUid = callingUid;
92         mOriginalOptions = options;
93     }
94 
95     /**
96      * To ensure that two activities, one using this object, and the other using the
97      * SafeActivityOptions returned from this function, are launched into the same display/root task
98      * through ActivityStartController#startActivities, all display-related information, i.e.
99      * displayAreaToken, launchDisplayId, callerDisplayId and the launch root task are cloned.
100      */
selectiveCloneLaunchOptions()101     @Nullable SafeActivityOptions selectiveCloneLaunchOptions() {
102         final ActivityOptions options = cloneLaunchingOptions(mOriginalOptions);
103         final ActivityOptions callerOptions = cloneLaunchingOptions(mCallerOptions);
104         if (options == null && callerOptions == null) {
105             return null;
106         }
107 
108         final SafeActivityOptions safeOptions = new SafeActivityOptions(options,
109                 mOriginalCallingPid, mOriginalCallingUid);
110         safeOptions.mCallerOptions = callerOptions;
111         safeOptions.mRealCallingPid = mRealCallingPid;
112         safeOptions.mRealCallingUid = mRealCallingUid;
113         return safeOptions;
114     }
115 
cloneLaunchingOptions(ActivityOptions options)116     private ActivityOptions cloneLaunchingOptions(ActivityOptions options) {
117         if (options == null) return null;
118 
119         final ActivityOptions cloneOptions = ActivityOptions.makeBasic()
120                 .setLaunchTaskDisplayArea(options.getLaunchTaskDisplayArea())
121                 .setLaunchDisplayId(options.getLaunchDisplayId())
122                 .setCallerDisplayId(options.getCallerDisplayId())
123                 .setLaunchRootTask(options.getLaunchRootTask())
124                 .setPendingIntentBackgroundActivityStartMode(
125                         options.getPendingIntentBackgroundActivityStartMode())
126                 .setPendingIntentCreatorBackgroundActivityStartMode(
127                         options.getPendingIntentCreatorBackgroundActivityStartMode())
128                 .setRemoteTransition(options.getRemoteTransition());
129         cloneOptions.setLaunchWindowingMode(options.getLaunchWindowingMode());
130         return cloneOptions;
131     }
132 
133     /**
134      * Overrides options with options from a caller and records {@link Binder#getCallingPid}/
135      * {@link Binder#getCallingUid}.
136      */
setCallerOptions(@ullable ActivityOptions options, int callingPid, int callingUid)137     public void setCallerOptions(@Nullable ActivityOptions options, int callingPid,
138             int callingUid) {
139         mRealCallingPid = callingPid;
140         mRealCallingUid = callingUid;
141         mCallerOptions = options;
142     }
143 
144     /**
145      * Performs permission check and retrieves the options.
146      *
147      * @param r The record of the being started activity.
148      */
getOptions(ActivityRecord r)149     ActivityOptions getOptions(ActivityRecord r) throws SecurityException {
150         return getOptions(r.intent, r.info, r.app, r.mTaskSupervisor);
151     }
152 
153     /**
154      * Performs permission check and retrieves the options when options are not being used to launch
155      * a specific activity (i.e. a task is moved to front).
156      */
getOptions(ActivityTaskSupervisor supervisor)157     ActivityOptions getOptions(ActivityTaskSupervisor supervisor) throws SecurityException {
158         return getOptions(null, null, null, supervisor);
159     }
160 
161     /**
162      * Performs permission check and retrieves the options.
163      *
164      * @param intent The intent that is being launched.
165      * @param aInfo The info of the activity being launched.
166      * @param callerApp The record of the caller.
167      */
getOptions(@ullable Intent intent, @Nullable ActivityInfo aInfo, @Nullable WindowProcessController callerApp, ActivityTaskSupervisor supervisor)168     ActivityOptions getOptions(@Nullable Intent intent, @Nullable ActivityInfo aInfo,
169             @Nullable WindowProcessController callerApp,
170             ActivityTaskSupervisor supervisor) throws SecurityException {
171         if (mOriginalOptions != null) {
172             checkPermissions(intent, aInfo, callerApp, supervisor, mOriginalOptions,
173                     mOriginalCallingPid, mOriginalCallingUid);
174             setCallingPidUidForRemoteAnimationAdapter(mOriginalOptions, mOriginalCallingPid,
175                     mOriginalCallingUid);
176         }
177         if (mCallerOptions != null) {
178             checkPermissions(intent, aInfo, callerApp, supervisor, mCallerOptions,
179                     mRealCallingPid, mRealCallingUid);
180             setCallingPidUidForRemoteAnimationAdapter(mCallerOptions, mRealCallingPid,
181                     mRealCallingUid);
182         }
183         return mergeActivityOptions(mOriginalOptions, mCallerOptions);
184     }
185 
setCallingPidUidForRemoteAnimationAdapter(ActivityOptions options, int callingPid, int callingUid)186     private void setCallingPidUidForRemoteAnimationAdapter(ActivityOptions options,
187             int callingPid, int callingUid) {
188         final RemoteAnimationAdapter adapter = options.getRemoteAnimationAdapter();
189         if (adapter == null) {
190             return;
191         }
192         if (callingPid == WindowManagerService.MY_PID) {
193             Slog.wtf(TAG, "Safe activity options constructed after clearing calling id");
194             return;
195         }
196         adapter.setCallingPidUid(callingPid, callingUid);
197     }
198 
199     /**
200      * Gets the original options passed in. It should only be used for logging. DO NOT use it as a
201      * condition in the logic of activity launch.
202      */
getOriginalOptions()203     ActivityOptions getOriginalOptions() {
204         return mOriginalOptions;
205     }
206 
207     /**
208      * @see ActivityOptions#popAppVerificationBundle
209      */
popAppVerificationBundle()210     Bundle popAppVerificationBundle() {
211         return mOriginalOptions != null ? mOriginalOptions.popAppVerificationBundle() : null;
212     }
213 
abort()214     private void abort() {
215         if (mOriginalOptions != null) {
216             ActivityOptions.abort(mOriginalOptions);
217         }
218         if (mCallerOptions != null) {
219             ActivityOptions.abort(mCallerOptions);
220         }
221     }
222 
abort(@ullable SafeActivityOptions options)223     static void abort(@Nullable SafeActivityOptions options) {
224         if (options != null) {
225             options.abort();
226         }
227     }
228 
229     /**
230      * Merges two activity options into one, with {@code options2} taking precedence in case of a
231      * conflict.
232      */
233     @VisibleForTesting
mergeActivityOptions(@ullable ActivityOptions options1, @Nullable ActivityOptions options2)234     @Nullable ActivityOptions mergeActivityOptions(@Nullable ActivityOptions options1,
235             @Nullable ActivityOptions options2) {
236         if (options1 == null) {
237             return options2;
238         }
239         if (options2 == null) {
240             return options1;
241         }
242         final Bundle b1 = options1.toBundle();
243         final Bundle b2 = options2.toBundle();
244         b1.putAll(b2);
245         return ActivityOptions.fromBundle(b1);
246     }
247 
checkPermissions(@ullable Intent intent, @Nullable ActivityInfo aInfo, @Nullable WindowProcessController callerApp, ActivityTaskSupervisor supervisor, ActivityOptions options, int callingPid, int callingUid)248     private void checkPermissions(@Nullable Intent intent, @Nullable ActivityInfo aInfo,
249             @Nullable WindowProcessController callerApp, ActivityTaskSupervisor supervisor,
250             ActivityOptions options, int callingPid, int callingUid) {
251         // If a launch task id is specified, then ensure that the caller is the recents
252         // component or has the START_TASKS_FROM_RECENTS permission
253         if ((options.getLaunchTaskId() != INVALID_TASK_ID || options.getDisableStartingWindow())
254                 && !supervisor.mRecentTasks.isCallerRecents(callingUid)) {
255             final int startInTaskPerm = ActivityTaskManagerService.checkPermission(
256                     START_TASKS_FROM_RECENTS, callingPid, callingUid);
257             if (startInTaskPerm == PERMISSION_DENIED) {
258                 final String msg = "Permission Denial: starting " + getIntentString(intent)
259                         + " from " + callerApp + " (pid=" + callingPid
260                         + ", uid=" + callingUid + ") with launchTaskId="
261                         + options.getLaunchTaskId();
262                 Slog.w(TAG, msg);
263                 throw new SecurityException(msg);
264             }
265         }
266         if (options.getTransientLaunch() && !supervisor.mRecentTasks.isCallerRecents(callingUid)
267                 && ActivityTaskManagerService.checkPermission(
268                         MANAGE_ACTIVITY_TASKS, callingPid, callingUid) == PERMISSION_DENIED) {
269             final String msg = "Permission Denial: starting transient launch from " + callerApp
270                     + ", pid=" + callingPid + ", uid=" + callingUid;
271             Slog.w(TAG, msg);
272             throw new SecurityException(msg);
273         }
274         // Check if the caller is allowed to launch on the specified display area.
275         final TaskDisplayArea taskDisplayArea = getLaunchTaskDisplayArea(options, supervisor);
276         if (aInfo != null && taskDisplayArea != null
277                 && !supervisor.isCallerAllowedToLaunchOnTaskDisplayArea(callingPid, callingUid,
278                 taskDisplayArea, aInfo)) {
279             final String msg = "Permission Denial: starting " + getIntentString(intent)
280                     + " from " + callerApp + " (pid=" + callingPid
281                     + ", uid=" + callingUid + ") with launchTaskDisplayArea=" + taskDisplayArea;
282             Slog.w(TAG, msg);
283             throw new SecurityException(msg);
284         }
285         // Check if the caller is allowed to launch on the specified display.
286         final int launchDisplayId = options.getLaunchDisplayId();
287         if (aInfo != null && launchDisplayId != INVALID_DISPLAY
288                 && !supervisor.isCallerAllowedToLaunchOnDisplay(callingPid, callingUid,
289                         launchDisplayId, aInfo)) {
290             final String msg = "Permission Denial: starting " + getIntentString(intent)
291                     + " from " + callerApp + " (pid=" + callingPid
292                     + ", uid=" + callingUid + ") with launchDisplayId="
293                     + launchDisplayId;
294             Slog.w(TAG, msg);
295             throw new SecurityException(msg);
296         }
297         // Check if someone tries to launch an unallowlisted activity into LockTask mode.
298         final boolean lockTaskMode = options.getLockTaskMode();
299         if (aInfo != null && lockTaskMode
300                 && !supervisor.mService.getLockTaskController().isPackageAllowlisted(
301                         UserHandle.getUserId(callingUid), aInfo.packageName)) {
302             final String msg = "Permission Denial: starting " + getIntentString(intent)
303                     + " from " + callerApp + " (pid=" + callingPid
304                     + ", uid=" + callingUid + ") with lockTaskMode=true";
305             Slog.w(TAG, msg);
306             throw new SecurityException(msg);
307         }
308 
309         // Check if the caller is allowed to override any app transition animation.
310         final boolean overrideTaskTransition = options.getOverrideTaskTransition();
311         if (aInfo != null && overrideTaskTransition) {
312             final int startTasksFromRecentsPerm = ActivityTaskManagerService.checkPermission(
313                     START_TASKS_FROM_RECENTS, callingPid, callingUid);
314             // Allow if calling uid is from assistant, or start task from recents
315             if (startTasksFromRecentsPerm != PERMISSION_GRANTED
316                     && !isAssistant(supervisor.mService, callingUid)) {
317                 final String msg = "Permission Denial: starting " + getIntentString(intent)
318                         + " from " + callerApp + " (pid=" + callingPid
319                         + ", uid=" + callingUid + ") with overrideTaskTransition=true";
320                 Slog.w(TAG, msg);
321                 throw new SecurityException(msg);
322             }
323         }
324 
325         // Check if the caller is allowed to dismiss keyguard.
326         final boolean dismissKeyguardIfInsecure = options.getDismissKeyguardIfInsecure();
327         if (aInfo != null && dismissKeyguardIfInsecure) {
328             final int controlKeyguardPerm = ActivityTaskManagerService.checkPermission(
329                     CONTROL_KEYGUARD, callingPid, callingUid);
330             if (controlKeyguardPerm != PERMISSION_GRANTED) {
331                 final String msg = "Permission Denial: starting " + getIntentString(intent)
332                         + " from " + callerApp + " (pid=" + callingPid
333                         + ", uid=" + callingUid + ") with dismissKeyguardIfInsecure=true";
334                 Slog.w(TAG, msg);
335                 throw new SecurityException(msg);
336             }
337         }
338 
339         // Check permission for remote animations
340         final RemoteAnimationAdapter adapter = options.getRemoteAnimationAdapter();
341         if (adapter != null && supervisor.mService.checkPermission(
342                 CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, callingPid, callingUid)
343                         != PERMISSION_GRANTED) {
344             final String msg = "Permission Denial: starting " + getIntentString(intent)
345                     + " from " + callerApp + " (pid=" + callingPid
346                     + ", uid=" + callingUid + ") with remoteAnimationAdapter";
347             Slog.w(TAG, msg);
348             throw new SecurityException(msg);
349         }
350 
351         // Check permission for remote transitions
352         final RemoteTransition transition = options.getRemoteTransition();
353         if (transition != null && supervisor.mService.checkPermission(
354                 CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, callingPid, callingUid)
355                 != PERMISSION_GRANTED) {
356             final String msg = "Permission Denial: starting " + getIntentString(intent)
357                     + " from " + callerApp + " (pid=" + callingPid
358                     + ", uid=" + callingUid + ") with remoteTransition";
359             Slog.w(TAG, msg);
360             throw new SecurityException(msg);
361         }
362 
363         // If launched from bubble is specified, then ensure that the caller is system or sysui.
364         if ((options.getLaunchedFromBubble() || options.getTaskAlwaysOnTop())
365                 && !isSystemOrSystemUI(callingPid, callingUid)) {
366             final String msg = "Permission Denial: starting " + getIntentString(intent)
367                     + " from " + callerApp + " (pid=" + callingPid
368                     + ", uid=" + callingUid + ") with"
369                     + (options.getLaunchedFromBubble() ? " launchedFromBubble=true" : "")
370                     + (options.getTaskAlwaysOnTop() ? " taskAlwaysOnTop=true" : "");
371             Slog.w(TAG, msg);
372             throw new SecurityException(msg);
373         }
374 
375         final int activityType = options.getLaunchActivityType();
376         if (activityType != ACTIVITY_TYPE_UNDEFINED
377                 && !isSystemOrSystemUI(callingPid, callingUid)) {
378             // Granted if it is assistant type and the calling uid is assistant.
379             boolean activityTypeGranted = false;
380             if (activityType == ACTIVITY_TYPE_ASSISTANT
381                     && isAssistant(supervisor.mService, callingUid)) {
382                 activityTypeGranted = true;
383             }
384 
385             if (!activityTypeGranted) {
386                 final String msg = "Permission Denial: starting " + getIntentString(intent)
387                         + " from " + callerApp + " (pid=" + callingPid
388                         + ", uid=" + callingUid + ") with launchActivityType="
389                         + activityTypeToString(options.getLaunchActivityType());
390                 Slog.w(TAG, msg);
391                 throw new SecurityException(msg);
392             }
393         }
394     }
395 
396     @VisibleForTesting
getLaunchTaskDisplayArea(ActivityOptions options, ActivityTaskSupervisor supervisor)397     TaskDisplayArea getLaunchTaskDisplayArea(ActivityOptions options,
398             ActivityTaskSupervisor supervisor) {
399         final WindowContainerToken daToken = options.getLaunchTaskDisplayArea();
400         TaskDisplayArea taskDisplayArea = daToken != null
401                 ? (TaskDisplayArea) WindowContainer.fromBinder(daToken.asBinder()) : null;
402         if (taskDisplayArea != null) {
403             return taskDisplayArea;
404         }
405 
406         // If we do not have a task display area token, check if the launch task display area
407         // feature id is specified.
408         final int launchTaskDisplayAreaFeatureId = options.getLaunchTaskDisplayAreaFeatureId();
409         if (launchTaskDisplayAreaFeatureId != FEATURE_UNDEFINED) {
410             final int launchDisplayId = options.getLaunchDisplayId() == INVALID_DISPLAY
411                     ? DEFAULT_DISPLAY : options.getLaunchDisplayId();
412             final DisplayContent dc = supervisor.mRootWindowContainer
413                     .getDisplayContent(launchDisplayId);
414             if (dc != null) {
415                 taskDisplayArea = dc.getItemFromTaskDisplayAreas(tda ->
416                         tda.mFeatureId == launchTaskDisplayAreaFeatureId ? tda : null);
417             }
418         }
419         return taskDisplayArea;
420     }
421 
422     /**
423      * Returns whether the given UID caller is the assistant.
424      */
isAssistant(ActivityTaskManagerService atmService, int callingUid)425     public static boolean isAssistant(ActivityTaskManagerService atmService, int callingUid) {
426         if (atmService.mActiveVoiceInteractionServiceComponent == null) {
427             return false;
428         }
429 
430         final String assistantPackage =
431                 atmService.mActiveVoiceInteractionServiceComponent.getPackageName();
432         try {
433             final int uid = AppGlobals.getPackageManager().getPackageUid(assistantPackage,
434                     PackageManager.MATCH_DIRECT_BOOT_AUTO,
435                     UserHandle.getUserId(callingUid));
436             if (uid == callingUid) {
437                 return true;
438             }
439         } catch (RemoteException e) {
440             // Should not happen
441         }
442         return false;
443     }
444 
isSystemOrSystemUI(int callingPid, int callingUid)445     private boolean isSystemOrSystemUI(int callingPid, int callingUid) {
446         if (callingUid == Process.SYSTEM_UID) {
447             return true;
448         }
449 
450         final int statusBarPerm = ActivityTaskManagerService.checkPermission(
451                 STATUS_BAR_SERVICE, callingPid, callingUid);
452         return statusBarPerm == PERMISSION_GRANTED;
453     }
454 
getIntentString(Intent intent)455     private String getIntentString(Intent intent) {
456         return intent != null ? intent.toString() : "(no intent)";
457     }
458 }
459