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.content.pm.ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES; 20 import static android.view.Display.DEFAULT_DISPLAY; 21 import static android.view.Display.INVALID_DISPLAY; 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.annotation.UserIdInt; 28 import android.app.WindowConfiguration; 29 import android.app.compat.CompatChanges; 30 import android.companion.virtual.VirtualDeviceManager.ActivityListener; 31 import android.companion.virtual.flags.Flags; 32 import android.compat.annotation.ChangeId; 33 import android.compat.annotation.EnabledSince; 34 import android.content.AttributionSource; 35 import android.content.ComponentName; 36 import android.content.Intent; 37 import android.content.pm.ActivityInfo; 38 import android.os.Build; 39 import android.os.Handler; 40 import android.os.Looper; 41 import android.os.UserHandle; 42 import android.util.ArraySet; 43 import android.util.Slog; 44 import android.view.Display; 45 import android.window.DisplayWindowPolicyController; 46 47 import com.android.internal.annotations.GuardedBy; 48 import com.android.internal.annotations.VisibleForTesting; 49 import com.android.internal.app.BlockedAppStreamingActivity; 50 import com.android.modules.expresslog.Counter; 51 52 import java.util.Set; 53 import java.util.concurrent.CountDownLatch; 54 import java.util.concurrent.TimeUnit; 55 56 /** 57 * A controller to control the policies of the windows that can be displayed on the virtual display. 58 */ 59 public class GenericWindowPolicyController extends DisplayWindowPolicyController { 60 61 private static final String TAG = "GenericWindowPolicyController"; 62 63 /** Interface to listen running applications change on virtual display. */ 64 public interface RunningAppsChangedListener { 65 /** 66 * Notifies the running applications change. 67 */ onRunningAppsChanged(ArraySet<Integer> runningUids)68 void onRunningAppsChanged(ArraySet<Integer> runningUids); 69 } 70 71 /** 72 * For communicating when activities are blocked from running on the display by this policy 73 * controller. 74 */ 75 public interface ActivityBlockedCallback { 76 /** Called when an activity is blocked.*/ onActivityBlocked(int displayId, ActivityInfo activityInfo)77 void onActivityBlocked(int displayId, ActivityInfo activityInfo); 78 } 79 private static final ComponentName BLOCKED_APP_STREAMING_COMPONENT = 80 new ComponentName("android", BlockedAppStreamingActivity.class.getName()); 81 82 /** 83 * For communicating when a secure window shows on the virtual display. 84 */ 85 public interface SecureWindowCallback { 86 /** Called when a secure window shows on the virtual display. */ onSecureWindowShown(int displayId, int uid)87 void onSecureWindowShown(int displayId, int uid); 88 } 89 90 /** 91 * For communicating when activities are blocked from entering PIP on the display by this 92 * policy controller. 93 */ 94 public interface PipBlockedCallback { 95 /** Called when an activity is blocked from entering PIP. */ onEnteringPipBlocked(int uid)96 void onEnteringPipBlocked(int uid); 97 } 98 99 /** Interface to listen for interception of intents. */ 100 public interface IntentListenerCallback { 101 /** Returns true when an intent should be intercepted */ shouldInterceptIntent(Intent intent)102 boolean shouldInterceptIntent(Intent intent); 103 } 104 105 /** 106 * If required, allow the secure activity to display on remote device since 107 * {@link android.os.Build.VERSION_CODES#TIRAMISU}. 108 */ 109 @ChangeId 110 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) 111 public static final long ALLOW_SECURE_ACTIVITY_DISPLAY_ON_REMOTE_DEVICE = 201712607L; 112 @NonNull 113 private final AttributionSource mAttributionSource; 114 @NonNull 115 private final ArraySet<UserHandle> mAllowedUsers; 116 @GuardedBy("mGenericWindowPolicyControllerLock") 117 private boolean mActivityLaunchAllowedByDefault; 118 @NonNull 119 @GuardedBy("mGenericWindowPolicyControllerLock") 120 private final Set<ComponentName> mActivityPolicyExemptions; 121 private final boolean mCrossTaskNavigationAllowedByDefault; 122 @NonNull 123 private final ArraySet<ComponentName> mCrossTaskNavigationExemptions; 124 @Nullable 125 private final ComponentName mPermissionDialogComponent; 126 private final Object mGenericWindowPolicyControllerLock = new Object(); 127 @Nullable private final ActivityBlockedCallback mActivityBlockedCallback; 128 129 // Do not access mDisplayId and mIsMirrorDisplay directly, instead use waitAndGetDisplayId() 130 // and waitAndGetIsMirrorDisplay() 131 private int mDisplayId = Display.INVALID_DISPLAY; 132 private boolean mIsMirrorDisplay = false; 133 private final CountDownLatch mDisplayIdSetLatch = new CountDownLatch(1); 134 135 @NonNull 136 @GuardedBy("mGenericWindowPolicyControllerLock") 137 private final ArraySet<Integer> mRunningUids = new ArraySet<>(); 138 @Nullable private final ActivityListener mActivityListener; 139 @Nullable private final PipBlockedCallback mPipBlockedCallback; 140 @Nullable private final IntentListenerCallback mIntentListenerCallback; 141 private final Handler mHandler = new Handler(Looper.getMainLooper()); 142 @NonNull 143 @GuardedBy("mGenericWindowPolicyControllerLock") 144 private final ArraySet<RunningAppsChangedListener> mRunningAppsChangedListeners = 145 new ArraySet<>(); 146 @Nullable private final SecureWindowCallback mSecureWindowCallback; 147 @NonNull private final Set<String> mDisplayCategories; 148 149 @GuardedBy("mGenericWindowPolicyControllerLock") 150 private boolean mShowTasksInHostDeviceRecents; 151 @Nullable private final ComponentName mCustomHomeComponent; 152 153 /** 154 * Creates a window policy controller that is generic to the different use cases of virtual 155 * device. 156 * 157 * @param windowFlags The window flags that this controller is interested in. 158 * @param systemWindowFlags The system window flags that this controller is interested in. 159 * @param attributionSource The AttributionSource of the VirtualDevice owner application. 160 * @param allowedUsers The set of users that are allowed to stream in this display. 161 * @param activityLaunchAllowedByDefault Whether activities are default allowed to be launched 162 * or blocked. 163 * @param activityPolicyExemptions The set of activities explicitly exempt from the default 164 * activity policy. 165 * @param crossTaskNavigationAllowedByDefault Whether cross task navigations are allowed by 166 * default or not. 167 * @param crossTaskNavigationExemptions The set of components explicitly exempt from the default 168 * navigation policy. 169 * @param activityListener Activity listener to listen for activity changes. 170 * @param activityBlockedCallback Callback that is called when an activity is blocked from 171 * launching. 172 * @param secureWindowCallback Callback that is called when a secure window shows on the 173 * virtual display. 174 * @param intentListenerCallback Callback that is called to intercept intents when matching 175 * passed in filters. 176 * @param showTasksInHostDeviceRecents whether to show activities in recents on the host device. 177 * @param customHomeComponent The component acting as a home activity on the virtual display. If 178 * {@code null}, then the system-default secondary home activity will be used. This is only 179 * applicable to displays that support home activities, i.e. they're created with the relevant 180 * virtual display flag. 181 */ GenericWindowPolicyController( int windowFlags, int systemWindowFlags, AttributionSource attributionSource, @NonNull ArraySet<UserHandle> allowedUsers, boolean activityLaunchAllowedByDefault, @NonNull Set<ComponentName> activityPolicyExemptions, boolean crossTaskNavigationAllowedByDefault, @NonNull Set<ComponentName> crossTaskNavigationExemptions, @Nullable ComponentName permissionDialogComponent, @Nullable ActivityListener activityListener, @Nullable PipBlockedCallback pipBlockedCallback, @Nullable ActivityBlockedCallback activityBlockedCallback, @Nullable SecureWindowCallback secureWindowCallback, @Nullable IntentListenerCallback intentListenerCallback, @NonNull Set<String> displayCategories, boolean showTasksInHostDeviceRecents, @Nullable ComponentName customHomeComponent)182 public GenericWindowPolicyController( 183 int windowFlags, 184 int systemWindowFlags, 185 AttributionSource attributionSource, 186 @NonNull ArraySet<UserHandle> allowedUsers, 187 boolean activityLaunchAllowedByDefault, 188 @NonNull Set<ComponentName> activityPolicyExemptions, 189 boolean crossTaskNavigationAllowedByDefault, 190 @NonNull Set<ComponentName> crossTaskNavigationExemptions, 191 @Nullable ComponentName permissionDialogComponent, 192 @Nullable ActivityListener activityListener, 193 @Nullable PipBlockedCallback pipBlockedCallback, 194 @Nullable ActivityBlockedCallback activityBlockedCallback, 195 @Nullable SecureWindowCallback secureWindowCallback, 196 @Nullable IntentListenerCallback intentListenerCallback, 197 @NonNull Set<String> displayCategories, 198 boolean showTasksInHostDeviceRecents, 199 @Nullable ComponentName customHomeComponent) { 200 super(); 201 mAttributionSource = attributionSource; 202 mAllowedUsers = allowedUsers; 203 mActivityLaunchAllowedByDefault = activityLaunchAllowedByDefault; 204 mActivityPolicyExemptions = activityPolicyExemptions; 205 mCrossTaskNavigationAllowedByDefault = crossTaskNavigationAllowedByDefault; 206 mCrossTaskNavigationExemptions = new ArraySet<>(crossTaskNavigationExemptions); 207 mPermissionDialogComponent = permissionDialogComponent; 208 mActivityBlockedCallback = activityBlockedCallback; 209 setInterestedWindowFlags(windowFlags, systemWindowFlags); 210 mActivityListener = activityListener; 211 mPipBlockedCallback = pipBlockedCallback; 212 mSecureWindowCallback = secureWindowCallback; 213 mIntentListenerCallback = intentListenerCallback; 214 mDisplayCategories = displayCategories; 215 mShowTasksInHostDeviceRecents = showTasksInHostDeviceRecents; 216 mCustomHomeComponent = customHomeComponent; 217 } 218 219 /** 220 * Expected to be called once this object is associated with a newly created display. 221 */ setDisplayId(int displayId, boolean isMirrorDisplay)222 void setDisplayId(int displayId, boolean isMirrorDisplay) { 223 mDisplayId = displayId; 224 mIsMirrorDisplay = isMirrorDisplay; 225 mDisplayIdSetLatch.countDown(); 226 } 227 waitAndGetDisplayId()228 private int waitAndGetDisplayId() { 229 try { 230 if (!mDisplayIdSetLatch.await(10, TimeUnit.SECONDS)) { 231 Slog.e(TAG, "Timed out while waiting for GWPC displayId to be set."); 232 return INVALID_DISPLAY; 233 } 234 } catch (InterruptedException e) { 235 Slog.e(TAG, "Interrupted while waiting for GWPC displayId to be set."); 236 return INVALID_DISPLAY; 237 } 238 return mDisplayId; 239 } 240 waitAndGetIsMirrorDisplay()241 private boolean waitAndGetIsMirrorDisplay() { 242 try { 243 if (!mDisplayIdSetLatch.await(10, TimeUnit.SECONDS)) { 244 Slog.e(TAG, "Timed out while waiting for GWPC isMirrorDisplay to be set."); 245 return false; 246 } 247 } catch (InterruptedException e) { 248 Slog.e(TAG, "Interrupted while waiting for GWPC isMirrorDisplay to be set."); 249 return false; 250 } 251 return mIsMirrorDisplay; 252 } 253 254 /** 255 * Set whether to show activities in recents on the host device. 256 */ setShowInHostDeviceRecents(boolean showInHostDeviceRecents)257 public void setShowInHostDeviceRecents(boolean showInHostDeviceRecents) { 258 synchronized (mGenericWindowPolicyControllerLock) { 259 mShowTasksInHostDeviceRecents = showInHostDeviceRecents; 260 } 261 } 262 setActivityLaunchDefaultAllowed(boolean activityLaunchDefaultAllowed)263 void setActivityLaunchDefaultAllowed(boolean activityLaunchDefaultAllowed) { 264 synchronized (mGenericWindowPolicyControllerLock) { 265 if (mActivityLaunchAllowedByDefault != activityLaunchDefaultAllowed) { 266 mActivityPolicyExemptions.clear(); 267 } 268 mActivityLaunchAllowedByDefault = activityLaunchDefaultAllowed; 269 } 270 } 271 addActivityPolicyExemption(@onNull ComponentName componentName)272 void addActivityPolicyExemption(@NonNull ComponentName componentName) { 273 synchronized (mGenericWindowPolicyControllerLock) { 274 mActivityPolicyExemptions.add(componentName); 275 } 276 } 277 removeActivityPolicyExemption(@onNull ComponentName componentName)278 void removeActivityPolicyExemption(@NonNull ComponentName componentName) { 279 synchronized (mGenericWindowPolicyControllerLock) { 280 mActivityPolicyExemptions.remove(componentName); 281 } 282 } 283 284 /** Register a listener for running applications changes. */ registerRunningAppsChangedListener(@onNull RunningAppsChangedListener listener)285 public void registerRunningAppsChangedListener(@NonNull RunningAppsChangedListener listener) { 286 synchronized (mGenericWindowPolicyControllerLock) { 287 mRunningAppsChangedListeners.add(listener); 288 } 289 } 290 291 /** Unregister a listener for running applications changes. */ unregisterRunningAppsChangedListener(@onNull RunningAppsChangedListener listener)292 public void unregisterRunningAppsChangedListener(@NonNull RunningAppsChangedListener listener) { 293 synchronized (mGenericWindowPolicyControllerLock) { 294 mRunningAppsChangedListeners.remove(listener); 295 } 296 } 297 298 @Override canActivityBeLaunched(@onNull ActivityInfo activityInfo, @Nullable Intent intent, @WindowConfiguration.WindowingMode int windowingMode, int launchingFromDisplayId, boolean isNewTask)299 public boolean canActivityBeLaunched(@NonNull ActivityInfo activityInfo, 300 @Nullable Intent intent, @WindowConfiguration.WindowingMode int windowingMode, 301 int launchingFromDisplayId, boolean isNewTask) { 302 if (Flags.interceptIntentsBeforeApplyingPolicy()) { 303 if (mIntentListenerCallback != null && intent != null 304 && mIntentListenerCallback.shouldInterceptIntent(intent)) { 305 logActivityLaunchBlocked("Virtual device intercepting intent"); 306 return false; 307 } 308 if (!canContainActivity(activityInfo, windowingMode, launchingFromDisplayId, 309 isNewTask)) { 310 notifyActivityBlocked(activityInfo); 311 return false; 312 } 313 } else { 314 if (!canContainActivity(activityInfo, windowingMode, launchingFromDisplayId, 315 isNewTask)) { 316 notifyActivityBlocked(activityInfo); 317 return false; 318 } 319 if (mIntentListenerCallback != null && intent != null 320 && mIntentListenerCallback.shouldInterceptIntent(intent)) { 321 logActivityLaunchBlocked("Virtual device intercepting intent"); 322 return false; 323 } 324 } 325 return true; 326 } 327 328 @Override canContainActivity(@onNull ActivityInfo activityInfo, @WindowConfiguration.WindowingMode int windowingMode, int launchingFromDisplayId, boolean isNewTask)329 public boolean canContainActivity(@NonNull ActivityInfo activityInfo, 330 @WindowConfiguration.WindowingMode int windowingMode, int launchingFromDisplayId, 331 boolean isNewTask) { 332 // Mirror displays cannot contain activities. 333 if (waitAndGetIsMirrorDisplay()) { 334 logActivityLaunchBlocked("Mirror virtual displays cannot contain activities."); 335 return false; 336 } 337 if (!isWindowingModeSupported(windowingMode)) { 338 logActivityLaunchBlocked( 339 "Virtual device doesn't support windowing mode " + windowingMode); 340 return false; 341 } 342 if ((activityInfo.flags & FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES) == 0) { 343 logActivityLaunchBlocked( 344 "Activity requires android:canDisplayOnRemoteDevices=true"); 345 return false; 346 } 347 final UserHandle activityUser = 348 UserHandle.getUserHandleForUid(activityInfo.applicationInfo.uid); 349 final ComponentName activityComponent = activityInfo.getComponentName(); 350 if (BLOCKED_APP_STREAMING_COMPONENT.equals(activityComponent) && activityUser.isSystem()) { 351 // The error dialog alerting users that streaming is blocked is always allowed. 352 return true; 353 } 354 if (!activityUser.isSystem() && !mAllowedUsers.contains(activityUser)) { 355 logActivityLaunchBlocked("Activity launch disallowed from user " + activityUser); 356 return false; 357 } 358 if (!activityMatchesDisplayCategory(activityInfo)) { 359 logActivityLaunchBlocked("The activity's required display category '" 360 + activityInfo.requiredDisplayCategory 361 + "' not found on virtual display with the following categories: " 362 + mDisplayCategories); 363 return false; 364 } 365 synchronized (mGenericWindowPolicyControllerLock) { 366 if (!isAllowedByPolicy(mActivityLaunchAllowedByDefault, mActivityPolicyExemptions, 367 activityComponent)) { 368 logActivityLaunchBlocked("Activity launch disallowed by policy: " 369 + activityComponent); 370 return false; 371 } 372 } 373 if (isNewTask && launchingFromDisplayId != DEFAULT_DISPLAY 374 && !isAllowedByPolicy(mCrossTaskNavigationAllowedByDefault, 375 mCrossTaskNavigationExemptions, activityComponent)) { 376 logActivityLaunchBlocked("Cross task navigation disallowed by policy: " 377 + activityComponent); 378 return false; 379 } 380 381 // mPermissionDialogComponent being null means we don't want to block permission Dialogs 382 // based on FLAG_STREAM_PERMISSIONS 383 if (mPermissionDialogComponent != null 384 && mPermissionDialogComponent.equals(activityComponent)) { 385 logActivityLaunchBlocked("Permission dialog not allowed on virtual device"); 386 return false; 387 } 388 389 return true; 390 } 391 logActivityLaunchBlocked(String reason)392 private void logActivityLaunchBlocked(String reason) { 393 Slog.d(TAG, "Virtual device activity launch disallowed on display " 394 + waitAndGetDisplayId() + ", reason: " + reason); 395 } 396 397 @Override 398 @SuppressWarnings("AndroidFrameworkRequiresPermission") keepActivityOnWindowFlagsChanged(ActivityInfo activityInfo, int windowFlags, int systemWindowFlags)399 public boolean keepActivityOnWindowFlagsChanged(ActivityInfo activityInfo, int windowFlags, 400 int systemWindowFlags) { 401 int displayId = waitAndGetDisplayId(); 402 // The callback is fired only when windowFlags are changed. To let VirtualDevice owner 403 // aware that the virtual display has a secure window on top. 404 if ((windowFlags & FLAG_SECURE) != 0 && mSecureWindowCallback != null 405 && displayId != INVALID_DISPLAY) { 406 // Post callback on the main thread, so it doesn't block activity launching. 407 mHandler.post(() -> mSecureWindowCallback.onSecureWindowShown(displayId, 408 activityInfo.applicationInfo.uid)); 409 } 410 411 if (!CompatChanges.isChangeEnabled(ALLOW_SECURE_ACTIVITY_DISPLAY_ON_REMOTE_DEVICE, 412 activityInfo.packageName, 413 UserHandle.getUserHandleForUid(activityInfo.applicationInfo.uid))) { 414 // TODO(b/201712607): Add checks for the apps that use SurfaceView#setSecure. 415 if ((windowFlags & FLAG_SECURE) != 0 416 || (systemWindowFlags & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) { 417 notifyActivityBlocked(activityInfo); 418 return false; 419 } 420 } 421 422 return true; 423 } 424 425 @Override onTopActivityChanged(ComponentName topActivity, int uid, @UserIdInt int userId)426 public void onTopActivityChanged(ComponentName topActivity, int uid, @UserIdInt int userId) { 427 int displayId = waitAndGetDisplayId(); 428 // Don't send onTopActivityChanged() callback when topActivity is null because it's defined 429 // as @NonNull in ActivityListener interface. Sends onDisplayEmpty() callback instead when 430 // there is no activity running on virtual display. 431 if (mActivityListener != null && topActivity != null && displayId != INVALID_DISPLAY) { 432 // Post callback on the main thread so it doesn't block activity launching 433 mHandler.post(() -> 434 mActivityListener.onTopActivityChanged(displayId, topActivity, userId)); 435 } 436 } 437 438 @Override onRunningAppsChanged(ArraySet<Integer> runningUids)439 public void onRunningAppsChanged(ArraySet<Integer> runningUids) { 440 synchronized (mGenericWindowPolicyControllerLock) { 441 mRunningUids.clear(); 442 mRunningUids.addAll(runningUids); 443 int displayId = waitAndGetDisplayId(); 444 if (mActivityListener != null && mRunningUids.isEmpty() 445 && displayId != INVALID_DISPLAY) { 446 // Post callback on the main thread so it doesn't block activity launching 447 mHandler.post(() -> mActivityListener.onDisplayEmpty(displayId)); 448 } 449 if (!mRunningAppsChangedListeners.isEmpty()) { 450 final ArraySet<RunningAppsChangedListener> listeners = 451 new ArraySet<>(mRunningAppsChangedListeners); 452 mHandler.post(() -> { 453 for (RunningAppsChangedListener listener : listeners) { 454 listener.onRunningAppsChanged(runningUids); 455 } 456 }); 457 } 458 } 459 } 460 461 @Override canShowTasksInHostDeviceRecents()462 public boolean canShowTasksInHostDeviceRecents() { 463 synchronized (mGenericWindowPolicyControllerLock) { 464 return mShowTasksInHostDeviceRecents; 465 } 466 } 467 468 @Override isEnteringPipAllowed(int uid)469 public boolean isEnteringPipAllowed(int uid) { 470 if (super.isEnteringPipAllowed(uid)) { 471 return true; 472 } 473 if (mPipBlockedCallback != null) { 474 mHandler.post(() -> mPipBlockedCallback.onEnteringPipBlocked(uid)); 475 } 476 return false; 477 } 478 479 @Override getCustomHomeComponent()480 public @Nullable ComponentName getCustomHomeComponent() { 481 return mCustomHomeComponent; 482 } 483 484 /** 485 * Returns true if an app with the given UID has an activity running on the virtual display for 486 * this controller. 487 */ containsUid(int uid)488 boolean containsUid(int uid) { 489 synchronized (mGenericWindowPolicyControllerLock) { 490 return mRunningUids.contains(uid); 491 } 492 } 493 activityMatchesDisplayCategory(ActivityInfo activityInfo)494 private boolean activityMatchesDisplayCategory(ActivityInfo activityInfo) { 495 if (mDisplayCategories.isEmpty()) { 496 return activityInfo.requiredDisplayCategory == null; 497 } 498 return activityInfo.requiredDisplayCategory != null 499 && mDisplayCategories.contains(activityInfo.requiredDisplayCategory); 500 } 501 notifyActivityBlocked(ActivityInfo activityInfo)502 private void notifyActivityBlocked(ActivityInfo activityInfo) { 503 int displayId = waitAndGetDisplayId(); 504 // Don't trigger activity blocked callback for mirror displays, because we can't show 505 // any activity or presentation on it anyway. 506 if (!waitAndGetIsMirrorDisplay() && mActivityBlockedCallback != null 507 && displayId != INVALID_DISPLAY) { 508 mActivityBlockedCallback.onActivityBlocked(displayId, activityInfo); 509 } 510 if (android.companion.virtualdevice.flags.Flags.metricsCollection()) { 511 Counter.logIncrementWithUid( 512 "virtual_devices.value_activity_blocked_count", 513 mAttributionSource.getUid()); 514 } 515 516 } 517 isAllowedByPolicy(boolean allowedByDefault, Set<ComponentName> exemptions, ComponentName component)518 private static boolean isAllowedByPolicy(boolean allowedByDefault, 519 Set<ComponentName> exemptions, ComponentName component) { 520 // Either allowed and the exemptions do not contain the component, 521 // or disallowed and the exemptions contain the component. 522 return allowedByDefault != exemptions.contains(component); 523 } 524 525 @VisibleForTesting getRunningAppsChangedListenersSizeForTesting()526 int getRunningAppsChangedListenersSizeForTesting() { 527 synchronized (mGenericWindowPolicyControllerLock) { 528 return mRunningAppsChangedListeners.size(); 529 } 530 } 531 } 532