• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.companion.virtual;
18 
19 import static android.companion.AssociationRequest.DEVICE_PROFILE_APP_STREAMING;
20 import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
21 import static android.content.pm.ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
22 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
23 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
24 
25 import android.annotation.NonNull;
26 import android.annotation.Nullable;
27 import android.app.WindowConfiguration;
28 import android.app.compat.CompatChanges;
29 import android.companion.AssociationRequest;
30 import android.companion.virtual.VirtualDeviceManager.ActivityListener;
31 import android.companion.virtual.VirtualDeviceParams;
32 import android.companion.virtual.VirtualDeviceParams.ActivityPolicy;
33 import android.compat.annotation.ChangeId;
34 import android.compat.annotation.EnabledSince;
35 import android.content.ComponentName;
36 import android.content.pm.ActivityInfo;
37 import android.os.Build;
38 import android.os.Handler;
39 import android.os.Looper;
40 import android.os.UserHandle;
41 import android.util.ArraySet;
42 import android.util.Slog;
43 import android.view.Display;
44 import android.window.DisplayWindowPolicyController;
45 
46 import com.android.internal.annotations.GuardedBy;
47 import com.android.internal.app.BlockedAppStreamingActivity;
48 
49 import java.util.List;
50 import java.util.Set;
51 
52 
53 /**
54  * A controller to control the policies of the windows that can be displayed on the virtual display.
55  */
56 public class GenericWindowPolicyController extends DisplayWindowPolicyController {
57 
58     private static final String TAG = "GenericWindowPolicyController";
59 
60     /** Interface to listen running applications change on virtual display. */
61     public interface RunningAppsChangedListener {
62         /**
63          * Notifies the running applications change.
64          */
onRunningAppsChanged(ArraySet<Integer> runningUids)65         void onRunningAppsChanged(ArraySet<Integer> runningUids);
66     }
67 
68     /**
69      * For communicating when activities are blocked from running on the display by this policy
70      * controller.
71      */
72     public interface ActivityBlockedCallback {
73         /** Called when an activity is blocked.*/
onActivityBlocked(int displayId, ActivityInfo activityInfo)74         void onActivityBlocked(int displayId, ActivityInfo activityInfo);
75     }
76     private static final ComponentName BLOCKED_APP_STREAMING_COMPONENT =
77             new ComponentName("android", BlockedAppStreamingActivity.class.getName());
78 
79     /**
80      * For communicating when a secure window shows on the virtual display.
81      */
82     public interface SecureWindowCallback {
83         /** Called when a secure window shows on the virtual display. */
onSecureWindowShown(int displayId, int uid)84         void onSecureWindowShown(int displayId, int uid);
85     }
86 
87     /**
88      * If required, allow the secure activity to display on remote device since
89      * {@link android.os.Build.VERSION_CODES#TIRAMISU}.
90      */
91     @ChangeId
92     @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
93     public static final long ALLOW_SECURE_ACTIVITY_DISPLAY_ON_REMOTE_DEVICE = 201712607L;
94     @NonNull
95     private final ArraySet<UserHandle> mAllowedUsers;
96     @Nullable
97     private final ArraySet<ComponentName> mAllowedCrossTaskNavigations;
98     @Nullable
99     private final ArraySet<ComponentName> mBlockedCrossTaskNavigations;
100     @Nullable
101     private final ArraySet<ComponentName> mAllowedActivities;
102     @Nullable
103     private final ArraySet<ComponentName> mBlockedActivities;
104     private final Object mGenericWindowPolicyControllerLock = new Object();
105     @ActivityPolicy
106     private final int mDefaultActivityPolicy;
107     private final ActivityBlockedCallback mActivityBlockedCallback;
108     private int mDisplayId = Display.INVALID_DISPLAY;
109 
110     @NonNull
111     @GuardedBy("mGenericWindowPolicyControllerLock")
112     final ArraySet<Integer> mRunningUids = new ArraySet<>();
113     @Nullable private final ActivityListener mActivityListener;
114     private final Handler mHandler = new Handler(Looper.getMainLooper());
115     private final ArraySet<RunningAppsChangedListener> mRunningAppsChangedListener =
116             new ArraySet<>();
117     @Nullable
118     private final @AssociationRequest.DeviceProfile String mDeviceProfile;
119     @Nullable private final SecureWindowCallback mSecureWindowCallback;
120 
121     /**
122      * Creates a window policy controller that is generic to the different use cases of virtual
123      * device.
124      *
125      * @param windowFlags The window flags that this controller is interested in.
126      * @param systemWindowFlags The system window flags that this controller is interested in.
127      * @param allowedUsers The set of users that are allowed to stream in this display.
128      * @param allowedCrossTaskNavigations The set of components explicitly allowed to navigate
129      *   across tasks on this device.
130      * @param blockedCrossTaskNavigations The set of components explicitly blocked from
131      *   navigating across tasks on this device.
132      * @param allowedActivities The set of activities explicitly allowed to stream on this device.
133      *   Used only if the {@code activityPolicy} is
134      *   {@link VirtualDeviceParams#ACTIVITY_POLICY_DEFAULT_BLOCKED}.
135      * @param blockedActivities The set of activities explicitly blocked from streaming on this
136      *   device. Used only if the {@code activityPolicy} is
137      *   {@link VirtualDeviceParams#ACTIVITY_POLICY_DEFAULT_ALLOWED}
138      * @param defaultActivityPolicy Whether activities are default allowed to be displayed or
139      *   blocked.
140      * @param activityListener Activity listener to listen for activity changes.
141      * @param activityBlockedCallback Callback that is called when an activity is blocked from
142      *   launching.
143      * @param secureWindowCallback Callback that is called when a secure window shows on the
144      *   virtual display.
145      * @param deviceProfile The {@link AssociationRequest.DeviceProfile} of this virtual device.
146      */
GenericWindowPolicyController(int windowFlags, int systemWindowFlags, @NonNull ArraySet<UserHandle> allowedUsers, @NonNull Set<ComponentName> allowedCrossTaskNavigations, @NonNull Set<ComponentName> blockedCrossTaskNavigations, @NonNull Set<ComponentName> allowedActivities, @NonNull Set<ComponentName> blockedActivities, @ActivityPolicy int defaultActivityPolicy, @NonNull ActivityListener activityListener, @NonNull ActivityBlockedCallback activityBlockedCallback, @NonNull SecureWindowCallback secureWindowCallback, @AssociationRequest.DeviceProfile String deviceProfile)147     public GenericWindowPolicyController(int windowFlags, int systemWindowFlags,
148             @NonNull ArraySet<UserHandle> allowedUsers,
149             @NonNull Set<ComponentName> allowedCrossTaskNavigations,
150             @NonNull Set<ComponentName> blockedCrossTaskNavigations,
151             @NonNull Set<ComponentName> allowedActivities,
152             @NonNull Set<ComponentName> blockedActivities,
153             @ActivityPolicy int defaultActivityPolicy,
154             @NonNull ActivityListener activityListener,
155             @NonNull ActivityBlockedCallback activityBlockedCallback,
156             @NonNull SecureWindowCallback secureWindowCallback,
157             @AssociationRequest.DeviceProfile String deviceProfile) {
158         super();
159         mAllowedUsers = allowedUsers;
160         mAllowedCrossTaskNavigations = new ArraySet<>(allowedCrossTaskNavigations);
161         mBlockedCrossTaskNavigations = new ArraySet<>(blockedCrossTaskNavigations);
162         mAllowedActivities = new ArraySet<>(allowedActivities);
163         mBlockedActivities = new ArraySet<>(blockedActivities);
164         mDefaultActivityPolicy = defaultActivityPolicy;
165         mActivityBlockedCallback = activityBlockedCallback;
166         setInterestedWindowFlags(windowFlags, systemWindowFlags);
167         mActivityListener = activityListener;
168         mDeviceProfile = deviceProfile;
169         mSecureWindowCallback = secureWindowCallback;
170     }
171 
172     /**
173      * Expected to be called once this object is associated with a newly created display.
174      */
setDisplayId(int displayId)175     public void setDisplayId(int displayId) {
176         mDisplayId = displayId;
177     }
178 
179     /** Register a listener for running applications changes. */
registerRunningAppsChangedListener(@onNull RunningAppsChangedListener listener)180     public void registerRunningAppsChangedListener(@NonNull RunningAppsChangedListener listener) {
181         mRunningAppsChangedListener.add(listener);
182     }
183 
184     /** Unregister a listener for running applications changes. */
unregisterRunningAppsChangedListener(@onNull RunningAppsChangedListener listener)185     public void unregisterRunningAppsChangedListener(@NonNull RunningAppsChangedListener listener) {
186         mRunningAppsChangedListener.remove(listener);
187     }
188 
189     @Override
canContainActivities(@onNull List<ActivityInfo> activities, @WindowConfiguration.WindowingMode int windowingMode)190     public boolean canContainActivities(@NonNull List<ActivityInfo> activities,
191             @WindowConfiguration.WindowingMode int windowingMode) {
192         if (!isWindowingModeSupported(windowingMode)) {
193             return false;
194         }
195         // Can't display all the activities if any of them don't want to be displayed.
196         final int activityCount = activities.size();
197         for (int i = 0; i < activityCount; i++) {
198             final ActivityInfo aInfo = activities.get(i);
199             if (!canContainActivity(aInfo, /* windowFlags= */ 0, /* systemWindowFlags= */ 0)) {
200                 mActivityBlockedCallback.onActivityBlocked(mDisplayId, aInfo);
201                 return false;
202             }
203         }
204         return true;
205     }
206 
207     @Override
canActivityBeLaunched(ActivityInfo activityInfo, @WindowConfiguration.WindowingMode int windowingMode, int launchingFromDisplayId, boolean isNewTask)208     public boolean canActivityBeLaunched(ActivityInfo activityInfo,
209             @WindowConfiguration.WindowingMode int windowingMode, int launchingFromDisplayId,
210             boolean isNewTask) {
211         if (!isWindowingModeSupported(windowingMode)) {
212             return false;
213         }
214 
215         final ComponentName activityComponent = activityInfo.getComponentName();
216         if (BLOCKED_APP_STREAMING_COMPONENT.equals(activityComponent)) {
217             // The error dialog alerting users that streaming is blocked is always allowed.
218             return true;
219         }
220 
221         if (!canContainActivity(activityInfo, /* windowFlags= */  0, /* systemWindowFlags= */ 0)) {
222             mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
223             return false;
224         }
225 
226         if (launchingFromDisplayId == Display.DEFAULT_DISPLAY) {
227             return true;
228         }
229         if (isNewTask && !mBlockedCrossTaskNavigations.isEmpty()
230                 && mBlockedCrossTaskNavigations.contains(activityComponent)) {
231             Slog.d(TAG, "Virtual device blocking cross task navigation of " + activityComponent);
232             mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
233             return false;
234         }
235         if (isNewTask && !mAllowedCrossTaskNavigations.isEmpty()
236                 && !mAllowedCrossTaskNavigations.contains(activityComponent)) {
237             Slog.d(TAG, "Virtual device not allowing cross task navigation of "
238                     + activityComponent);
239             mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
240             return false;
241         }
242 
243         return true;
244     }
245 
246 
247     @Override
keepActivityOnWindowFlagsChanged(ActivityInfo activityInfo, int windowFlags, int systemWindowFlags)248     public boolean keepActivityOnWindowFlagsChanged(ActivityInfo activityInfo, int windowFlags,
249             int systemWindowFlags) {
250         // The callback is fired only when windowFlags are changed. To let VirtualDevice owner
251         // aware that the virtual display has a secure window on top.
252         if ((windowFlags & FLAG_SECURE) != 0) {
253             // Post callback on the main thread, so it doesn't block activity launching.
254             mHandler.post(() -> mSecureWindowCallback.onSecureWindowShown(mDisplayId,
255                     activityInfo.applicationInfo.uid));
256         }
257 
258         if (!canContainActivity(activityInfo, windowFlags, systemWindowFlags)) {
259             mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
260             return false;
261         }
262         return true;
263     }
264 
265     @Override
onTopActivityChanged(ComponentName topActivity, int uid)266     public void onTopActivityChanged(ComponentName topActivity, int uid) {
267         // Don't send onTopActivityChanged() callback when topActivity is null because it's defined
268         // as @NonNull in ActivityListener interface. Sends onDisplayEmpty() callback instead when
269         // there is no activity running on virtual display.
270         if (mActivityListener != null && topActivity != null) {
271             // Post callback on the main thread so it doesn't block activity launching
272             mHandler.post(() ->
273                     mActivityListener.onTopActivityChanged(mDisplayId, topActivity));
274         }
275     }
276 
277     @Override
onRunningAppsChanged(ArraySet<Integer> runningUids)278     public void onRunningAppsChanged(ArraySet<Integer> runningUids) {
279         synchronized (mGenericWindowPolicyControllerLock) {
280             mRunningUids.clear();
281             mRunningUids.addAll(runningUids);
282             if (mActivityListener != null && mRunningUids.isEmpty()) {
283                 // Post callback on the main thread so it doesn't block activity launching
284                 mHandler.post(() -> mActivityListener.onDisplayEmpty(mDisplayId));
285             }
286         }
287         mHandler.post(() -> {
288             for (RunningAppsChangedListener listener : mRunningAppsChangedListener) {
289                 listener.onRunningAppsChanged(runningUids);
290             }
291         });
292     }
293 
294     @Override
canShowTasksInRecents()295     public boolean canShowTasksInRecents() {
296         if (mDeviceProfile == null) {
297             return true;
298         }
299        // TODO(b/234075973) : Remove this once proper API is ready.
300         switch (mDeviceProfile) {
301             case DEVICE_PROFILE_AUTOMOTIVE_PROJECTION:
302                 return false;
303             case DEVICE_PROFILE_APP_STREAMING:
304             default:
305                 return true;
306         }
307     }
308 
309     /**
310      * Returns true if an app with the given UID has an activity running on the virtual display for
311      * this controller.
312      */
containsUid(int uid)313     boolean containsUid(int uid) {
314         synchronized (mGenericWindowPolicyControllerLock) {
315             return mRunningUids.contains(uid);
316         }
317     }
318 
canContainActivity(ActivityInfo activityInfo, int windowFlags, int systemWindowFlags)319     private boolean canContainActivity(ActivityInfo activityInfo, int windowFlags,
320             int systemWindowFlags) {
321         if ((activityInfo.flags & FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES) == 0) {
322             return false;
323         }
324         ComponentName activityComponent = activityInfo.getComponentName();
325         if (BLOCKED_APP_STREAMING_COMPONENT.equals(activityComponent)) {
326             // The error dialog alerting users that streaming is blocked is always allowed.
327             return true;
328         }
329         final UserHandle activityUser =
330                 UserHandle.getUserHandleForUid(activityInfo.applicationInfo.uid);
331         if (!mAllowedUsers.contains(activityUser)) {
332             Slog.d(TAG, "Virtual device activity not allowed from user " + activityUser);
333             return false;
334         }
335         if (mDefaultActivityPolicy == VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED
336                 && mBlockedActivities.contains(activityComponent)) {
337             Slog.d(TAG, "Virtual device blocking launch of " + activityComponent);
338             return false;
339         }
340         if (mDefaultActivityPolicy == VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_BLOCKED
341                 && !mAllowedActivities.contains(activityComponent)) {
342             Slog.d(TAG, activityComponent + " is not in the allowed list.");
343             return false;
344         }
345         if (!CompatChanges.isChangeEnabled(ALLOW_SECURE_ACTIVITY_DISPLAY_ON_REMOTE_DEVICE,
346                 activityInfo.packageName, activityUser)) {
347             // TODO(b/201712607): Add checks for the apps that use SurfaceView#setSecure.
348             if ((windowFlags & FLAG_SECURE) != 0) {
349                 return false;
350             }
351             if ((systemWindowFlags & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
352                 return false;
353             }
354         }
355         return true;
356     }
357 }
358