Merge "Skeleton for content protection allowlist manager" into main
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 57011e8..5f612d6b 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -395,6 +395,22 @@
public static final String DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD =
"content_protection_optional_groups_threshold";
+ /**
+ * Sets the initial delay for fetching content protection allowlist in milliseconds.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS =
+ "content_protection_allowlist_delay_ms";
+
+ /**
+ * Sets the timeout for fetching content protection allowlist in milliseconds.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS =
+ "content_protection_allowlist_timeout_ms";
+
/** @hide */
@TestApi
public static final int LOGGING_LEVEL_OFF = 0;
@@ -445,6 +461,10 @@
public static final String DEFAULT_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG = "";
/** @hide */
public static final int DEFAULT_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD = 0;
+ /** @hide */
+ public static final long DEFAULT_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS = 30000;
+ /** @hide */
+ public static final long DEFAULT_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS = 250;
private final Object mLock = new Object();
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 76ebdf4..9f4528b 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -20,6 +20,8 @@
import static android.content.Context.CONTENT_CAPTURE_MANAGER_SERVICE;
import static android.service.contentcapture.ContentCaptureService.setClientState;
import static android.view.contentcapture.ContentCaptureHelper.toList;
+import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS;
+import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS;
import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG;
import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD;
import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_REQUIRED_GROUPS_CONFIG;
@@ -219,6 +221,12 @@
@GuardedBy("mLock")
int mDevCfgContentProtectionOptionalGroupsThreshold;
+ @GuardedBy("mLock")
+ long mDevCfgContentProtectionAllowlistDelayMs;
+
+ @GuardedBy("mLock")
+ long mDevCfgContentProtectionAllowlistTimeoutMs;
+
private final Executor mDataShareExecutor = Executors.newCachedThreadPool();
private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -231,11 +239,17 @@
final GlobalContentCaptureOptions mGlobalContentCaptureOptions =
new GlobalContentCaptureOptions();
- @Nullable private final ComponentName mContentProtectionServiceComponentName;
+ @GuardedBy("mLock")
+ @Nullable
+ private ComponentName mContentProtectionServiceComponentName;
- @Nullable private final ContentProtectionAllowlistManager mContentProtectionAllowlistManager;
+ @GuardedBy("mLock")
+ @Nullable
+ private ContentProtectionAllowlistManager mContentProtectionAllowlistManager;
- @Nullable private final ContentProtectionConsentManager mContentProtectionConsentManager;
+ @GuardedBy("mLock")
+ @Nullable
+ private ContentProtectionConsentManager mContentProtectionConsentManager;
public ContentCaptureManagerService(@NonNull Context context) {
super(context, new FrameworkResourcesServiceNameResolver(context,
@@ -279,21 +293,6 @@
mServiceNameResolver.getServiceName(userId),
mServiceNameResolver.isTemporary(userId));
}
-
- if (getEnableContentProtectionReceiverLocked()) {
- mContentProtectionServiceComponentName = getContentProtectionServiceComponentName();
- if (mContentProtectionServiceComponentName != null) {
- mContentProtectionAllowlistManager = createContentProtectionAllowlistManager();
- mContentProtectionConsentManager = createContentProtectionConsentManager();
- } else {
- mContentProtectionAllowlistManager = null;
- mContentProtectionConsentManager = null;
- }
- } else {
- mContentProtectionServiceComponentName = null;
- mContentProtectionAllowlistManager = null;
- mContentProtectionConsentManager = null;
- }
}
@Override // from AbstractMasterSystemService
@@ -442,6 +441,8 @@
case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_REQUIRED_GROUPS_CONFIG:
case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG:
case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD:
+ case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS:
+ case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS:
setFineTuneParamsFromDeviceConfig();
return;
default:
@@ -453,8 +454,15 @@
/** @hide */
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
protected void setFineTuneParamsFromDeviceConfig() {
+ boolean enableContentProtectionReceiverOld;
+ boolean enableContentProtectionReceiverNew;
String contentProtectionRequiredGroupsConfig;
String contentProtectionOptionalGroupsConfig;
+ int contentProtectionOptionalGroupsThreshold;
+ long contentProtectionAllowlistDelayMs;
+ long contentProtectionAllowlistTimeoutMs;
+ ContentProtectionAllowlistManager contentProtectionAllowlistManagerOld;
+
synchronized (mLock) {
mDevCfgMaxBufferSize =
DeviceConfig.getInt(
@@ -488,12 +496,9 @@
ContentCaptureManager
.DEVICE_CONFIG_PROPERTY_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING,
false);
- mDevCfgEnableContentProtectionReceiver =
- DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
- ContentCaptureManager
- .DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER,
- ContentCaptureManager.DEFAULT_ENABLE_CONTENT_PROTECTION_RECEIVER);
+
+ enableContentProtectionReceiverOld = mDevCfgEnableContentProtectionReceiver;
+ enableContentProtectionReceiverNew = getDeviceConfigEnableContentProtectionReceiver();
mDevCfgContentProtectionBufferSize =
DeviceConfig.getInt(
DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
@@ -512,12 +517,25 @@
DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG,
ContentCaptureManager
.DEFAULT_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG);
- mDevCfgContentProtectionOptionalGroupsThreshold =
+ contentProtectionOptionalGroupsThreshold =
DeviceConfig.getInt(
DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD,
ContentCaptureManager
.DEFAULT_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD);
+ contentProtectionAllowlistDelayMs =
+ DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS,
+ ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS);
+ contentProtectionAllowlistTimeoutMs =
+ DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS,
+ ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS);
+
+ contentProtectionAllowlistManagerOld = mContentProtectionAllowlistManager;
+
if (verbose) {
Slog.v(
TAG,
@@ -535,7 +553,7 @@
+ ", disableFlushForViewTreeAppearing="
+ mDevCfgDisableFlushForViewTreeAppearing
+ ", enableContentProtectionReceiver="
- + mDevCfgEnableContentProtectionReceiver
+ + enableContentProtectionReceiverNew
+ ", contentProtectionBufferSize="
+ mDevCfgContentProtectionBufferSize
+ ", contentProtectionRequiredGroupsConfig="
@@ -543,7 +561,11 @@
+ ", contentProtectionOptionalGroupsConfig="
+ contentProtectionOptionalGroupsConfig
+ ", contentProtectionOptionalGroupsThreshold="
- + mDevCfgContentProtectionOptionalGroupsThreshold);
+ + contentProtectionOptionalGroupsThreshold
+ + ", contentProtectionAllowlistDelayMs="
+ + contentProtectionAllowlistDelayMs
+ + ", contentProtectionAllowlistTimeoutMs="
+ + contentProtectionAllowlistTimeoutMs);
}
}
@@ -551,9 +573,37 @@
parseContentProtectionGroupsConfig(contentProtectionRequiredGroupsConfig);
List<List<String>> contentProtectionOptionalGroups =
parseContentProtectionGroupsConfig(contentProtectionOptionalGroupsConfig);
+ ComponentName contentProtectionServiceComponentNameNew = null;
+ ContentProtectionAllowlistManager contentProtectionAllowlistManagerNew = null;
+ ContentProtectionConsentManager contentProtectionConsentManagerNew = null;
+
+ if (contentProtectionAllowlistManagerOld != null && !enableContentProtectionReceiverNew) {
+ contentProtectionAllowlistManagerOld.stop();
+ }
+ if (!enableContentProtectionReceiverOld && enableContentProtectionReceiverNew) {
+ contentProtectionServiceComponentNameNew = getContentProtectionServiceComponentName();
+ if (contentProtectionServiceComponentNameNew != null) {
+ contentProtectionAllowlistManagerNew =
+ createContentProtectionAllowlistManager(
+ contentProtectionAllowlistTimeoutMs);
+ contentProtectionAllowlistManagerNew.start(contentProtectionAllowlistDelayMs);
+ contentProtectionConsentManagerNew = createContentProtectionConsentManager();
+ }
+ }
+
synchronized (mLock) {
+ mDevCfgEnableContentProtectionReceiver = enableContentProtectionReceiverNew;
mDevCfgContentProtectionRequiredGroups = contentProtectionRequiredGroups;
mDevCfgContentProtectionOptionalGroups = contentProtectionOptionalGroups;
+ mDevCfgContentProtectionOptionalGroupsThreshold =
+ contentProtectionOptionalGroupsThreshold;
+ mDevCfgContentProtectionAllowlistDelayMs = contentProtectionAllowlistDelayMs;
+
+ if (enableContentProtectionReceiverOld ^ enableContentProtectionReceiverNew) {
+ mContentProtectionServiceComponentName = contentProtectionServiceComponentNameNew;
+ mContentProtectionAllowlistManager = contentProtectionAllowlistManagerNew;
+ mContentProtectionConsentManager = contentProtectionConsentManagerNew;
+ }
}
}
@@ -837,27 +887,34 @@
pw.print(prefix2);
pw.print("contentProtectionOptionalGroupsThreshold: ");
pw.println(mDevCfgContentProtectionOptionalGroupsThreshold);
+ pw.print(prefix2);
+ pw.print("contentProtectionAllowlistDelayMs: ");
+ pw.println(mDevCfgContentProtectionAllowlistDelayMs);
+ pw.print(prefix2);
+ pw.print("contentProtectionAllowlistTimeoutMs: ");
+ pw.println(mDevCfgContentProtectionAllowlistTimeoutMs);
pw.print(prefix);
pw.println("Global Options:");
mGlobalContentCaptureOptions.dump(prefix2, pw);
}
- /**
- * Used by the constructor in order to be able to override the value in the tests.
- *
- * @hide
- */
+ /** @hide */
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- @GuardedBy("mLock")
- protected boolean getEnableContentProtectionReceiverLocked() {
- return mDevCfgEnableContentProtectionReceiver;
+ protected boolean getDeviceConfigEnableContentProtectionReceiver() {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ ContentCaptureManager.DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER,
+ ContentCaptureManager.DEFAULT_ENABLE_CONTENT_PROTECTION_RECEIVER);
}
/** @hide */
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
@NonNull
- protected ContentProtectionAllowlistManager createContentProtectionAllowlistManager() {
- return new ContentProtectionAllowlistManager();
+ protected ContentProtectionAllowlistManager createContentProtectionAllowlistManager(
+ long timeoutMs) {
+ // Same handler as used by AbstractMasterSystemService
+ return new ContentProtectionAllowlistManager(
+ this, BackgroundThread.getHandler(), timeoutMs);
}
/** @hide */
@@ -874,6 +931,9 @@
@Nullable
private ComponentName getContentProtectionServiceComponentName() {
String flatComponentName = getContentProtectionServiceFlatComponentName();
+ if (flatComponentName == null) {
+ return null;
+ }
return ComponentName.unflattenFromString(flatComponentName);
}
@@ -898,27 +958,27 @@
getContext(), componentName, /* isTemp= */ false, UserHandle.getCallingUserId());
}
+ /** @hide */
@Nullable
- private RemoteContentProtectionService createRemoteContentProtectionService() {
- if (mContentProtectionServiceComponentName == null) {
- // This case should not be possible but make sure
- return null;
- }
+ public RemoteContentProtectionService createRemoteContentProtectionService() {
+ ComponentName componentName;
synchronized (mLock) {
- if (!mDevCfgEnableContentProtectionReceiver) {
+ if (!mDevCfgEnableContentProtectionReceiver
+ || mContentProtectionServiceComponentName == null) {
return null;
}
+ componentName = mContentProtectionServiceComponentName;
}
// Check permissions by trying to construct {@link ContentCaptureServiceInfo}
try {
- createContentProtectionServiceInfo(mContentProtectionServiceComponentName);
+ createContentProtectionServiceInfo(componentName);
} catch (Exception ex) {
// Swallow, exception was already logged
return null;
}
- return createRemoteContentProtectionService(mContentProtectionServiceComponentName);
+ return createRemoteContentProtectionService(componentName);
}
/** @hide */
@@ -976,6 +1036,16 @@
.toList();
}
+ @GuardedBy("mLock")
+ private boolean isContentProtectionEnabledLocked() {
+ return mDevCfgEnableContentProtectionReceiver
+ && mContentProtectionServiceComponentName != null
+ && mContentProtectionAllowlistManager != null
+ && mContentProtectionConsentManager != null
+ && !(mDevCfgContentProtectionRequiredGroups.isEmpty()
+ && mDevCfgContentProtectionOptionalGroups.isEmpty());
+ }
+
final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
@Override
@@ -1406,22 +1476,17 @@
private boolean isContentProtectionReceiverEnabled(
@UserIdInt int userId, @NonNull String packageName) {
- if (mContentProtectionServiceComponentName == null
- || mContentProtectionAllowlistManager == null
- || mContentProtectionConsentManager == null) {
- return false;
- }
+ ContentProtectionConsentManager consentManager;
+ ContentProtectionAllowlistManager allowlistManager;
synchronized (mLock) {
- if (!mDevCfgEnableContentProtectionReceiver) {
+ if (!isContentProtectionEnabledLocked()) {
return false;
}
- if (mDevCfgContentProtectionRequiredGroups.isEmpty()
- && mDevCfgContentProtectionOptionalGroups.isEmpty()) {
- return false;
- }
+ consentManager = mContentProtectionConsentManager;
+ allowlistManager = mContentProtectionAllowlistManager;
}
- return mContentProtectionConsentManager.isConsentGranted(userId)
- && mContentProtectionAllowlistManager.isAllowed(packageName);
+ return consentManager.isConsentGranted(userId)
+ && allowlistManager.isAllowed(packageName);
}
}
diff --git a/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionAllowlistManager.java b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionAllowlistManager.java
index 59af526..f77430d 100644
--- a/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionAllowlistManager.java
+++ b/services/contentcapture/java/com/android/server/contentprotection/ContentProtectionAllowlistManager.java
@@ -16,8 +16,22 @@
package com.android.server.contentprotection;
+import static android.view.contentprotection.flags.Flags.blocklistUpdateEnabled;
+
import android.annotation.NonNull;
-import android.util.Slog;
+import android.annotation.Nullable;
+import android.os.Handler;
+import android.os.UserHandle;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.content.PackageMonitor;
+import com.android.server.contentcapture.ContentCaptureManagerService;
+
+import java.time.Instant;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
/**
* Manages whether the content protection is enabled for an app using a allowlist.
@@ -28,11 +42,124 @@
private static final String TAG = "ContentProtectionAllowlistManager";
- public ContentProtectionAllowlistManager() {}
+ @NonNull private final ContentCaptureManagerService mContentCaptureManagerService;
+
+ @NonNull private final Handler mHandler;
+
+ private final long mTimeoutMs;
+
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ @NonNull
+ final PackageMonitor mPackageMonitor;
+
+ private final Object mHandlerToken = new Object();
+
+ private final Object mLock = new Object();
+
+ // Used outside of the handler
+ private boolean mStarted;
+
+ // Used inside the handler
+ @Nullable private Instant mUpdatePendingUntil;
+
+ @NonNull
+ @GuardedBy("mLock")
+ private Set<String> mAllowedPackages = Set.of();
+
+ public ContentProtectionAllowlistManager(
+ @NonNull ContentCaptureManagerService contentCaptureManagerService,
+ @NonNull Handler handler,
+ long timeoutMs) {
+ mContentCaptureManagerService = contentCaptureManagerService;
+ mHandler = handler;
+ mTimeoutMs = timeoutMs;
+ mPackageMonitor = createPackageMonitor();
+ }
+
+ /** Starts the manager. */
+ public void start(long delayMs) {
+ if (mStarted) {
+ return;
+ }
+ mStarted = true;
+ mHandler.postDelayed(this::handleInitialUpdate, mHandlerToken, delayMs);
+ // PackageMonitor will be registered inside handleInitialUpdate to respect the initial delay
+ }
+
+ /** Stops the manager. */
+ public void stop() {
+ try {
+ mPackageMonitor.unregister();
+ } catch (IllegalStateException ex) {
+ // Swallow, throws if not registered
+ }
+ mHandler.removeCallbacksAndMessages(mHandlerToken);
+ mUpdatePendingUntil = null;
+ mStarted = false;
+ }
/** Returns true if the package is allowed. */
public boolean isAllowed(@NonNull String packageName) {
- Slog.v(TAG, packageName);
- return false;
+ Set<String> allowedPackages;
+ synchronized (mLock) {
+ allowedPackages = mAllowedPackages;
+ }
+ return allowedPackages.contains(packageName);
+ }
+
+ private void setAllowlist(@NonNull List<String> packages) {
+ synchronized (mLock) {
+ mAllowedPackages = packages.stream().collect(Collectors.toUnmodifiableSet());
+ }
+ mUpdatePendingUntil = null;
+ }
+
+ private void handleInitialUpdate() {
+ handleUpdate();
+
+ // Initial update done, start listening to package updates now
+ mPackageMonitor.register(
+ mContentCaptureManagerService.getContext(), UserHandle.ALL, mHandler);
+ }
+
+ private void handleUpdate() {
+ if (!blocklistUpdateEnabled()) {
+ return;
+ }
+
+ /**
+ * PackageMonitor callback can be invoked more than once in a matter of milliseconds on the
+ * same monitor instance for the same package (eg: b/295969873). This check acts both as a
+ * simple generic rate limit and as a mitigation for this quirk.
+ */
+ if (mUpdatePendingUntil != null && Instant.now().isBefore(mUpdatePendingUntil)) {
+ return;
+ }
+
+ RemoteContentProtectionService remoteContentProtectionService =
+ mContentCaptureManagerService.createRemoteContentProtectionService();
+ if (remoteContentProtectionService == null) {
+ return;
+ }
+
+ // If there are any pending updates queued already, they can be removed immediately
+ mHandler.removeCallbacksAndMessages(mHandlerToken);
+ mUpdatePendingUntil = Instant.now().plusMillis(mTimeoutMs);
+ }
+
+ /** @hide */
+ @NonNull
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ protected PackageMonitor createPackageMonitor() {
+ return new ContentProtectionPackageMonitor();
+ }
+
+ private final class ContentProtectionPackageMonitor extends PackageMonitor {
+
+ // This callback might be invoked multiple times, for more info refer to the comment above
+ @Override
+ public void onSomePackagesChanged() {
+ handleUpdate();
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
index 78bf9b0..9a5241e 100644
--- a/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
@@ -21,6 +21,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -31,7 +32,6 @@
import android.content.ComponentName;
import android.content.ContentCaptureOptions;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.platform.test.flag.junit.SetFlagsRule;
@@ -130,36 +130,10 @@
}
@Test
- public void constructor_contentProtection_flagDisabled_noManagers() {
+ public void constructor_contentProtection_disabled_noManagers() {
assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(0);
- assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
assertThat(mContentProtectionConsentManagersCreated).isEqualTo(0);
- verifyZeroInteractions(mMockContentProtectionAllowlistManager);
- verifyZeroInteractions(mMockContentProtectionConsentManager);
- }
-
- @Test
- public void constructor_contentProtection_componentNameNull_noManagers() {
- mConfigDefaultContentProtectionService = null;
-
- mContentCaptureManagerService = new TestContentCaptureManagerService();
-
- assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(0);
assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
- assertThat(mContentProtectionConsentManagersCreated).isEqualTo(0);
- verifyZeroInteractions(mMockContentProtectionAllowlistManager);
- verifyZeroInteractions(mMockContentProtectionConsentManager);
- }
-
- @Test
- public void constructor_contentProtection_componentNameBlank_noManagers() {
- mConfigDefaultContentProtectionService = " ";
-
- mContentCaptureManagerService = new TestContentCaptureManagerService();
-
- assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(0);
- assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
- assertThat(mContentProtectionConsentManagersCreated).isEqualTo(0);
verifyZeroInteractions(mMockContentProtectionAllowlistManager);
verifyZeroInteractions(mMockContentProtectionConsentManager);
}
@@ -173,20 +147,137 @@
assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(1);
assertThat(mContentProtectionConsentManagersCreated).isEqualTo(1);
assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
+ verify(mMockContentProtectionAllowlistManager).start(anyLong());
+ verify(mMockContentProtectionAllowlistManager, never()).stop();
+ verifyZeroInteractions(mMockContentProtectionConsentManager);
+ }
+
+ @Test
+ public void setFineTuneParamsFromDeviceConfig_contentProtection_disabled_to_disabled() {
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+
+ assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(0);
+ assertThat(mContentProtectionConsentManagersCreated).isEqualTo(0);
+ assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
+ verifyZeroInteractions(mMockContentProtectionAllowlistManager);
+ verifyZeroInteractions(mMockContentProtectionConsentManager);
+ }
+
+ @Test
+ public void setFineTuneParamsFromDeviceConfig_contentProtection_disabled_to_enabled() {
+ mDevCfgEnableContentProtectionReceiver = true;
+
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+
+ assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(1);
+ assertThat(mContentProtectionConsentManagersCreated).isEqualTo(1);
+ assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
+ verify(mMockContentProtectionAllowlistManager).start(anyLong());
+ verify(mMockContentProtectionAllowlistManager, never()).stop();
+ verifyZeroInteractions(mMockContentProtectionConsentManager);
+ }
+
+ @Test
+ public void setFineTuneParamsFromDeviceConfig_contentProtection_enabled_to_enabled() {
+ mDevCfgEnableContentProtectionReceiver = true;
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+
+ assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(1);
+ assertThat(mContentProtectionConsentManagersCreated).isEqualTo(1);
+ assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
+ verify(mMockContentProtectionAllowlistManager).start(anyLong());
+ verify(mMockContentProtectionAllowlistManager, never()).stop();
+ verifyZeroInteractions(mMockContentProtectionConsentManager);
+ }
+
+ @Test
+ public void setFineTuneParamsFromDeviceConfig_contentProtection_enabled_to_disabled() {
+ mDevCfgEnableContentProtectionReceiver = true;
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+ mDevCfgEnableContentProtectionReceiver = false;
+
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+
+ assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(1);
+ assertThat(mContentProtectionConsentManagersCreated).isEqualTo(1);
+ assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
+ verify(mMockContentProtectionAllowlistManager).start(anyLong());
+ verify(mMockContentProtectionAllowlistManager).stop();
+ verifyZeroInteractions(mMockContentProtectionConsentManager);
+ }
+
+ @Test
+ public void setFineTuneParamsFromDeviceConfig_contentProtection_enabled_componentNameNull() {
+ mDevCfgEnableContentProtectionReceiver = true;
+ mConfigDefaultContentProtectionService = null;
+
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+
+ assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(0);
+ assertThat(mContentProtectionConsentManagersCreated).isEqualTo(0);
+ assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
+ verifyZeroInteractions(mMockContentProtectionAllowlistManager);
+ verifyZeroInteractions(mMockContentProtectionConsentManager);
+ }
+
+ @Test
+ public void setFineTuneParamsFromDeviceConfig_contentProtection_enabled_componentNameBlank() {
+ mDevCfgEnableContentProtectionReceiver = true;
+ mConfigDefaultContentProtectionService = " ";
+
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+
+ assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(0);
+ assertThat(mContentProtectionConsentManagersCreated).isEqualTo(0);
+ assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
+ verifyZeroInteractions(mMockContentProtectionAllowlistManager);
+ verifyZeroInteractions(mMockContentProtectionConsentManager);
+ }
+
+ @Test
+ public void setFineTuneParamsFromDeviceConfig_contentProtection_disabled_componentNameNull() {
+ mDevCfgEnableContentProtectionReceiver = true;
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+ mDevCfgEnableContentProtectionReceiver = false;
+ mConfigDefaultContentProtectionService = null;
+
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+
+ assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(1);
+ assertThat(mContentProtectionConsentManagersCreated).isEqualTo(1);
+ assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
+ verify(mMockContentProtectionAllowlistManager).start(anyLong());
+ verify(mMockContentProtectionAllowlistManager).stop();
+ verifyZeroInteractions(mMockContentProtectionConsentManager);
+ }
+
+ @Test
+ public void setFineTuneParamsFromDeviceConfig_contentProtection_disabled_componentNameBlank() {
+ mDevCfgEnableContentProtectionReceiver = true;
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+ mDevCfgEnableContentProtectionReceiver = false;
+ mConfigDefaultContentProtectionService = " ";
+
+ mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig();
+
+ assertThat(mContentProtectionAllowlistManagersCreated).isEqualTo(1);
+ assertThat(mContentProtectionConsentManagersCreated).isEqualTo(1);
+ assertThat(mContentProtectionServiceInfosCreated).isEqualTo(0);
+ verify(mMockContentProtectionAllowlistManager).start(anyLong());
+ verify(mMockContentProtectionAllowlistManager).stop();
verifyZeroInteractions(mMockContentProtectionConsentManager);
}
@Test
public void getOptions_contentCaptureDisabled_contentProtectionDisabled() {
- mDevCfgEnableContentProtectionReceiver = true;
- mContentCaptureManagerService = new TestContentCaptureManagerService();
-
ContentCaptureOptions actual =
mContentCaptureManagerService.mGlobalContentCaptureOptions.getOptions(
USER_ID, PACKAGE_NAME);
assertThat(actual).isNull();
- verify(mMockContentProtectionConsentManager).isConsentGranted(USER_ID);
+ verify(mMockContentProtectionConsentManager, never()).isConsentGranted(anyInt());
verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
}
@@ -210,8 +301,6 @@
@Test
public void getOptions_contentCaptureEnabled_contentProtectionDisabled() {
- mDevCfgEnableContentProtectionReceiver = true;
- mContentCaptureManagerService = new TestContentCaptureManagerService();
mContentCaptureManagerService.mGlobalContentCaptureOptions.setWhitelist(
USER_ID, ImmutableList.of(PACKAGE_NAME), /* components= */ null);
@@ -224,7 +313,7 @@
assertThat(actual.contentProtectionOptions).isNotNull();
assertThat(actual.contentProtectionOptions.enableReceiver).isFalse();
assertThat(actual.whitelistedComponents).isNull();
- verify(mMockContentProtectionConsentManager).isConsentGranted(USER_ID);
+ verify(mMockContentProtectionConsentManager, never()).isConsentGranted(anyInt());
verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
}
@@ -249,31 +338,14 @@
}
@Test
- public void isWhitelisted_packageName_contentCaptureDisabled_contentProtectionNotGranted() {
- mDevCfgEnableContentProtectionReceiver = true;
- mContentCaptureManagerService = new TestContentCaptureManagerService();
-
- boolean actual =
- mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted(
- USER_ID, PACKAGE_NAME);
-
- assertThat(actual).isFalse();
- verify(mMockContentProtectionConsentManager).isConsentGranted(USER_ID);
- verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
- }
-
- @Test
public void isWhitelisted_packageName_contentCaptureDisabled_contentProtectionDisabled() {
- when(mMockContentProtectionConsentManager.isConsentGranted(USER_ID)).thenReturn(true);
- mDevCfgEnableContentProtectionReceiver = true;
- mContentCaptureManagerService = new TestContentCaptureManagerService();
-
boolean actual =
mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted(
USER_ID, PACKAGE_NAME);
assertThat(actual).isFalse();
- verify(mMockContentProtectionAllowlistManager).isAllowed(PACKAGE_NAME);
+ verify(mMockContentProtectionConsentManager, never()).isConsentGranted(anyInt());
+ verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
}
@Test
@@ -291,7 +363,21 @@
}
@Test
- public void isWhitelisted_packageName_contentCaptureEnabled_contentProtectionNotChecked() {
+ public void isWhitelisted_packageName_contentCaptureEnabled_contentProtectionDisabled() {
+ mContentCaptureManagerService.mGlobalContentCaptureOptions.setWhitelist(
+ USER_ID, ImmutableList.of(PACKAGE_NAME), /* components= */ null);
+
+ boolean actual =
+ mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted(
+ USER_ID, PACKAGE_NAME);
+
+ assertThat(actual).isTrue();
+ verify(mMockContentProtectionConsentManager, never()).isConsentGranted(anyInt());
+ verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
+ }
+
+ @Test
+ public void isWhitelisted_packageName_contentCaptureEnabled_contentProtectionEnabled() {
mDevCfgEnableContentProtectionReceiver = true;
mContentCaptureManagerService = new TestContentCaptureManagerService();
mContentCaptureManagerService.mGlobalContentCaptureOptions.setWhitelist(
@@ -307,31 +393,14 @@
}
@Test
- public void isWhitelisted_componentName_contentCaptureDisabled_contentProtectionNotGranted() {
- mDevCfgEnableContentProtectionReceiver = true;
- mContentCaptureManagerService = new TestContentCaptureManagerService();
-
- boolean actual =
- mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted(
- USER_ID, COMPONENT_NAME);
-
- assertThat(actual).isFalse();
- verify(mMockContentProtectionConsentManager).isConsentGranted(USER_ID);
- verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
- }
-
- @Test
public void isWhitelisted_componentName_contentCaptureDisabled_contentProtectionDisabled() {
- when(mMockContentProtectionConsentManager.isConsentGranted(USER_ID)).thenReturn(true);
- mDevCfgEnableContentProtectionReceiver = true;
- mContentCaptureManagerService = new TestContentCaptureManagerService();
-
boolean actual =
mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted(
USER_ID, COMPONENT_NAME);
assertThat(actual).isFalse();
- verify(mMockContentProtectionAllowlistManager).isAllowed(PACKAGE_NAME);
+ verify(mMockContentProtectionConsentManager, never()).isConsentGranted(anyInt());
+ verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
}
@Test
@@ -349,7 +418,21 @@
}
@Test
- public void isWhitelisted_componentName_contentCaptureEnabled_contentProtectionNotChecked() {
+ public void isWhitelisted_componentName_contentCaptureEnabled_contentProtectionDisabled() {
+ mContentCaptureManagerService.mGlobalContentCaptureOptions.setWhitelist(
+ USER_ID, /* packageNames= */ null, ImmutableList.of(COMPONENT_NAME));
+
+ boolean actual =
+ mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted(
+ USER_ID, COMPONENT_NAME);
+
+ assertThat(actual).isTrue();
+ verify(mMockContentProtectionConsentManager, never()).isConsentGranted(anyInt());
+ verify(mMockContentProtectionAllowlistManager, never()).isAllowed(anyString());
+ }
+
+ @Test
+ public void isWhitelisted_componentName_contentCaptureEnabled_contentProtectionEnabled() {
mDevCfgEnableContentProtectionReceiver = true;
mContentCaptureManagerService = new TestContentCaptureManagerService();
mContentCaptureManagerService.mGlobalContentCaptureOptions.setWhitelist(
@@ -544,8 +627,6 @@
TestContentCaptureManagerService() {
super(sContext);
- this.mDevCfgEnableContentProtectionReceiver =
- ContentCaptureManagerServiceTest.this.mDevCfgEnableContentProtectionReceiver;
this.mDevCfgContentProtectionRequiredGroups =
ContentCaptureManagerServiceTest.this.mDevCfgContentProtectionRequiredGroups;
this.mDevCfgContentProtectionOptionalGroups =
@@ -553,12 +634,13 @@
}
@Override
- protected boolean getEnableContentProtectionReceiverLocked() {
+ protected boolean getDeviceConfigEnableContentProtectionReceiver() {
return ContentCaptureManagerServiceTest.this.mDevCfgEnableContentProtectionReceiver;
}
@Override
- protected ContentProtectionAllowlistManager createContentProtectionAllowlistManager() {
+ protected ContentProtectionAllowlistManager createContentProtectionAllowlistManager(
+ long timeoutMs) {
mContentProtectionAllowlistManagersCreated++;
return mMockContentProtectionAllowlistManager;
}
@@ -570,7 +652,7 @@
@Override
protected ContentCaptureServiceInfo createContentProtectionServiceInfo(
- @NonNull ComponentName componentName) throws PackageManager.NameNotFoundException {
+ @NonNull ComponentName componentName) {
mContentProtectionServiceInfosCreated++;
if (mContentProtectionServiceInfoConstructorShouldThrow) {
throw new RuntimeException("TEST RUNTIME EXCEPTION");
diff --git a/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionAllowlistManagerTest.java b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionAllowlistManagerTest.java
index 6767a85..dc38f2b 100644
--- a/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionAllowlistManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/contentprotection/ContentProtectionAllowlistManagerTest.java
@@ -16,15 +16,35 @@
package com.android.server.contentprotection;
+import static android.view.contentprotection.flags.Flags.FLAG_BLOCKLIST_UPDATE_ENABLED;
+
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+import android.os.UserHandle;
+import android.os.test.TestLooper;
+import android.platform.test.flag.junit.SetFlagsRule;
+
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.internal.content.PackageMonitor;
+import com.android.server.contentcapture.ContentCaptureManagerService;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -40,13 +60,236 @@
private static final String PACKAGE_NAME = "com.test.package.name";
+ private static final long TIMEOUT_MS = 111_111_111L;
+
+ private static final long DELAY_MS = 222_222_222L;
+
@Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+ @Mock private ContentCaptureManagerService mMockContentCaptureManagerService;
+
+ @Mock private PackageMonitor mMockPackageMonitor;
+
+ @Mock private RemoteContentProtectionService mMockRemoteContentProtectionService;
+
+ private final TestLooper mTestLooper = new TestLooper();
+
+ private Handler mHandler;
+
private ContentProtectionAllowlistManager mContentProtectionAllowlistManager;
@Before
public void setup() {
- mContentProtectionAllowlistManager = new ContentProtectionAllowlistManager();
+ mHandler = new Handler(mTestLooper.getLooper());
+ mContentProtectionAllowlistManager = new TestContentProtectionAllowlistManager();
+ }
+
+ @Test
+ public void constructor() {
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verifyZeroInteractions(mMockPackageMonitor);
+ }
+
+ @Test
+ public void start_updateEnabled_firstTime_beforeDelay() {
+ mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isTrue();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verifyZeroInteractions(mMockPackageMonitor);
+ }
+
+ @Test
+ public void start_updateEnabled_firstTime_afterDelay() {
+ mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.moveTimeForward(DELAY_MS);
+ mTestLooper.dispatchNext();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verify(mMockContentCaptureManagerService).createRemoteContentProtectionService();
+ verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
+ verify(mMockPackageMonitor, never()).unregister();
+ }
+
+ @Test
+ public void start_updateEnabled_secondTime() {
+ mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.moveTimeForward(DELAY_MS);
+ mTestLooper.dispatchNext();
+
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verify(mMockContentCaptureManagerService).createRemoteContentProtectionService();
+ verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
+ verify(mMockPackageMonitor, never()).unregister();
+ }
+
+ @Test
+ public void start_updateDisabled_firstTime_beforeDelay() {
+ mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isTrue();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verifyZeroInteractions(mMockPackageMonitor);
+ }
+
+ @Test
+ public void start_updateDisabled_firstTime_afterDelay() {
+ mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.moveTimeForward(DELAY_MS);
+ mTestLooper.dispatchNext();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
+ verify(mMockPackageMonitor, never()).unregister();
+ }
+
+ @Test
+ public void start_updateDisabled_secondTime() {
+ mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.moveTimeForward(DELAY_MS);
+ mTestLooper.dispatchNext();
+
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
+ verify(mMockPackageMonitor, never()).unregister();
+ }
+
+ @Test
+ public void stop_updateEnabled_notStarted() {
+ mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ doThrow(new IllegalStateException("NOT REGISTERED")).when(mMockPackageMonitor).unregister();
+
+ mContentProtectionAllowlistManager.stop();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verify(mMockPackageMonitor, never()).register(any(), any(), any());
+ verify(mMockPackageMonitor).unregister();
+ }
+
+ @Test
+ public void stop_updateEnabled_started_beforeDelay() {
+ mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ doThrow(new IllegalStateException("NOT REGISTERED")).when(mMockPackageMonitor).unregister();
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.dispatchAll();
+
+ mContentProtectionAllowlistManager.stop();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verify(mMockPackageMonitor, never()).register(any(), any(), any());
+ verify(mMockPackageMonitor).unregister();
+ }
+
+ @Test
+ public void stop_updateEnabled_started_afterDelay() {
+ mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.moveTimeForward(DELAY_MS);
+ mTestLooper.dispatchNext();
+
+ mContentProtectionAllowlistManager.stop();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verify(mMockContentCaptureManagerService).createRemoteContentProtectionService();
+ verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
+ verify(mMockPackageMonitor).unregister();
+ }
+
+ @Test
+ public void stop_updateDisabled_notStarted() {
+ mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ doThrow(new IllegalStateException("NOT REGISTERED")).when(mMockPackageMonitor).unregister();
+
+ mContentProtectionAllowlistManager.stop();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verify(mMockPackageMonitor, never()).register(any(), any(), any());
+ verify(mMockPackageMonitor).unregister();
+ }
+
+ @Test
+ public void stop_updateDisabled_started_beforeDelay() {
+ mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ doThrow(new IllegalStateException("NOT REGISTERED")).when(mMockPackageMonitor).unregister();
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.dispatchAll();
+
+ mContentProtectionAllowlistManager.stop();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verify(mMockPackageMonitor, never()).register(any(), any(), any());
+ verify(mMockPackageMonitor).unregister();
+ }
+
+ @Test
+ public void stop_updateDisabled_started_afterDelay() {
+ mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.moveTimeForward(DELAY_MS);
+ mTestLooper.dispatchNext();
+
+ mContentProtectionAllowlistManager.stop();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
+ verify(mMockPackageMonitor).unregister();
+ }
+
+ @Test
+ public void start_afterStop_beforeDelay() {
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.dispatchAll();
+ mContentProtectionAllowlistManager.stop();
+
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.moveTimeForward(DELAY_MS);
+ mTestLooper.dispatchNext();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verify(mMockPackageMonitor).register(any(), eq(UserHandle.ALL), eq(mHandler));
+ verify(mMockPackageMonitor).unregister();
+ }
+
+ @Test
+ public void start_afterStop_afterDelay() {
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.moveTimeForward(DELAY_MS);
+ mTestLooper.dispatchNext();
+ mContentProtectionAllowlistManager.stop();
+
+ mContentProtectionAllowlistManager.start(DELAY_MS);
+ mTestLooper.moveTimeForward(DELAY_MS);
+ mTestLooper.dispatchNext();
+
+ assertThat(mHandler.hasMessagesOrCallbacks()).isFalse();
+ verify(mMockPackageMonitor, times(2)).register(any(), eq(UserHandle.ALL), eq(mHandler));
+ verify(mMockPackageMonitor).unregister();
}
@Test
@@ -54,5 +297,86 @@
boolean actual = mContentProtectionAllowlistManager.isAllowed(PACKAGE_NAME);
assertThat(actual).isFalse();
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ verifyZeroInteractions(mMockPackageMonitor);
+ }
+
+ @Test
+ public void handleUpdate_updateDisabled() {
+ mSetFlagsRule.disableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ ContentProtectionAllowlistManager manager =
+ new ContentProtectionAllowlistManager(
+ mMockContentCaptureManagerService, mHandler, TIMEOUT_MS);
+
+ manager.mPackageMonitor.onSomePackagesChanged();
+
+ verifyZeroInteractions(mMockContentCaptureManagerService);
+ }
+
+ @Test
+ public void handleUpdate_updateEnabled() {
+ mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ ContentProtectionAllowlistManager manager =
+ new ContentProtectionAllowlistManager(
+ mMockContentCaptureManagerService, mHandler, TIMEOUT_MS);
+
+ manager.mPackageMonitor.onSomePackagesChanged();
+
+ verify(mMockContentCaptureManagerService).createRemoteContentProtectionService();
+ }
+
+ @Test
+ public void handleUpdate_rateLimit_noService() {
+ mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ ContentProtectionAllowlistManager manager =
+ new ContentProtectionAllowlistManager(
+ mMockContentCaptureManagerService, mHandler, TIMEOUT_MS);
+
+ manager.mPackageMonitor.onSomePackagesChanged();
+ manager.mPackageMonitor.onSomePackagesChanged();
+
+ verify(mMockContentCaptureManagerService, times(2)).createRemoteContentProtectionService();
+ }
+
+ @Test
+ public void handleUpdate_rateLimit_beforeTimeout() {
+ mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ ContentProtectionAllowlistManager manager =
+ new ContentProtectionAllowlistManager(
+ mMockContentCaptureManagerService, mHandler, TIMEOUT_MS);
+ when(mMockContentCaptureManagerService.createRemoteContentProtectionService())
+ .thenReturn(mMockRemoteContentProtectionService);
+
+ manager.mPackageMonitor.onSomePackagesChanged();
+ manager.mPackageMonitor.onSomePackagesChanged();
+
+ verify(mMockContentCaptureManagerService).createRemoteContentProtectionService();
+ }
+
+ @Test
+ public void handleUpdate_rateLimit_afterTimeout() {
+ mSetFlagsRule.enableFlags(FLAG_BLOCKLIST_UPDATE_ENABLED);
+ ContentProtectionAllowlistManager manager =
+ new ContentProtectionAllowlistManager(
+ mMockContentCaptureManagerService, mHandler, /* timeoutMs= */ 0L);
+ when(mMockContentCaptureManagerService.createRemoteContentProtectionService())
+ .thenReturn(mMockRemoteContentProtectionService);
+
+ manager.mPackageMonitor.onSomePackagesChanged();
+ manager.mPackageMonitor.onSomePackagesChanged();
+
+ verify(mMockContentCaptureManagerService, times(2)).createRemoteContentProtectionService();
+ }
+
+ private class TestContentProtectionAllowlistManager extends ContentProtectionAllowlistManager {
+
+ TestContentProtectionAllowlistManager() {
+ super(mMockContentCaptureManagerService, mHandler, TIMEOUT_MS);
+ }
+
+ @Override
+ protected PackageMonitor createPackageMonitor() {
+ return mMockPackageMonitor;
+ }
}
}