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