Loading services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java +84 −10 Original line number Diff line number Diff line Loading @@ -88,11 +88,14 @@ import android.view.contentcapture.IContentCaptureOptionsCallback; import android.view.contentcapture.IDataShareWriteAdapter; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.infra.AbstractRemoteService; import com.android.internal.infra.GlobalWhitelistState; import com.android.internal.os.IResultReceiver; import com.android.internal.util.DumpUtils; import com.android.server.LocalServices; import com.android.server.contentprotection.ContentProtectionBlocklistManager; import com.android.server.contentprotection.ContentProtectionPackageManager; import com.android.server.infra.AbstractMasterSystemService; import com.android.server.infra.FrameworkResourcesServiceNameResolver; Loading @@ -117,7 +120,7 @@ import java.util.concurrent.atomic.AtomicBoolean; * with other sources to provide contextual data in other areas of the system * such as Autofill. */ public final class ContentCaptureManagerService extends public class ContentCaptureManagerService extends AbstractMasterSystemService<ContentCaptureManagerService, ContentCapturePerUserService> { private static final String TAG = ContentCaptureManagerService.class.getSimpleName(); Loading Loading @@ -205,6 +208,8 @@ public final class ContentCaptureManagerService extends final GlobalContentCaptureOptions mGlobalContentCaptureOptions = new GlobalContentCaptureOptions(); @Nullable private final ContentProtectionBlocklistManager mContentProtectionBlocklistManager; public ContentCaptureManagerService(@NonNull Context context) { super(context, new FrameworkResourcesServiceNameResolver(context, com.android.internal.R.string.config_defaultContentCaptureService), Loading Loading @@ -242,6 +247,14 @@ public final class ContentCaptureManagerService extends mServiceNameResolver.getServiceName(userId), mServiceNameResolver.isTemporary(userId)); } if (getEnableContentProtectionReceiverLocked()) { mContentProtectionBlocklistManager = createContentProtectionBlocklistManager(context); mContentProtectionBlocklistManager.updateBlocklist( mDevCfgContentProtectionAppsBlocklistSize); } else { mContentProtectionBlocklistManager = null; } } @Override // from AbstractMasterSystemService Loading Loading @@ -397,7 +410,9 @@ public final class ContentCaptureManagerService extends } } private void setFineTuneParamsFromDeviceConfig() { /** @hide */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected void setFineTuneParamsFromDeviceConfig() { synchronized (mLock) { mDevCfgMaxBufferSize = DeviceConfig.getInt( Loading Loading @@ -443,6 +458,8 @@ public final class ContentCaptureManagerService extends ContentCaptureManager .DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_APPS_BLOCKLIST_SIZE, ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_APPS_BLOCKLIST_SIZE); // mContentProtectionBlocklistManager.updateBlocklist not called on purpose here to keep // it immutable at this point mDevCfgContentProtectionBufferSize = DeviceConfig.getInt( DeviceConfig.NAMESPACE_CONTENT_CAPTURE, Loading Loading @@ -754,6 +771,25 @@ public final class ContentCaptureManagerService extends mGlobalContentCaptureOptions.dump(prefix2, pw); } /** * Used by the constructor in order to be able to override the value in the tests. * * @hide */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) @GuardedBy("mLock") protected boolean getEnableContentProtectionReceiverLocked() { return mDevCfgEnableContentProtectionReceiver; } /** @hide */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) @NonNull protected ContentProtectionBlocklistManager createContentProtectionBlocklistManager( @NonNull Context context) { return new ContentProtectionBlocklistManager(new ContentProtectionPackageManager(context)); } final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub { @Override Loading Loading @@ -1075,14 +1111,21 @@ public final class ContentCaptureManagerService extends @GuardedBy("mGlobalWhitelistStateLock") public ContentCaptureOptions getOptions(@UserIdInt int userId, @NonNull String packageName) { boolean packageWhitelisted; boolean isContentCaptureReceiverEnabled; boolean isContentProtectionReceiverEnabled; ArraySet<ComponentName> whitelistedComponents = null; synchronized (mGlobalWhitelistStateLock) { packageWhitelisted = isWhitelisted(userId, packageName); if (!packageWhitelisted) { // Full package is not allowlisted: check individual components first isContentCaptureReceiverEnabled = isContentCaptureReceiverEnabled(userId, packageName); isContentProtectionReceiverEnabled = isContentProtectionReceiverEnabled(packageName); if (!isContentCaptureReceiverEnabled) { // Full package is not allowlisted: check individual components next whitelistedComponents = getWhitelistedComponents(userId, packageName); if (whitelistedComponents == null if (!isContentProtectionReceiverEnabled && whitelistedComponents == null && packageName.equals(mServicePackages.get(userId))) { // No components allowlisted either, but let it go because it's the // service's own package Loading @@ -1101,7 +1144,9 @@ public final class ContentCaptureManagerService extends } } if (!packageWhitelisted && whitelistedComponents == null) { if (!isContentCaptureReceiverEnabled && !isContentProtectionReceiverEnabled && whitelistedComponents == null) { // No can do! if (verbose) { Slog.v(TAG, "getOptionsForPackage(" + packageName + "): not whitelisted"); Loading @@ -1118,9 +1163,9 @@ public final class ContentCaptureManagerService extends mDevCfgTextChangeFlushingFrequencyMs, mDevCfgLogHistorySize, mDevCfgDisableFlushForViewTreeAppearing, /* enableReceiver= */ true, isContentCaptureReceiverEnabled || whitelistedComponents != null, new ContentCaptureOptions.ContentProtectionOptions( mDevCfgEnableContentProtectionReceiver, isContentProtectionReceiverEnabled, mDevCfgContentProtectionBufferSize), whitelistedComponents); if (verbose) Slog.v(TAG, "getOptionsForPackage(" + packageName + "): " + options); Loading @@ -1141,6 +1186,35 @@ public final class ContentCaptureManagerService extends } } } @Override // from GlobalWhitelistState public boolean isWhitelisted(@UserIdInt int userId, @NonNull String packageName) { return isContentCaptureReceiverEnabled(userId, packageName) || isContentProtectionReceiverEnabled(packageName); } @Override // from GlobalWhitelistState public boolean isWhitelisted(@UserIdInt int userId, @NonNull ComponentName componentName) { return super.isWhitelisted(userId, componentName) || isContentProtectionReceiverEnabled(componentName.getPackageName()); } private boolean isContentCaptureReceiverEnabled( @UserIdInt int userId, @NonNull String packageName) { return super.isWhitelisted(userId, packageName); } private boolean isContentProtectionReceiverEnabled(@NonNull String packageName) { if (mContentProtectionBlocklistManager == null) { return false; } synchronized (mLock) { if (!mDevCfgEnableContentProtectionReceiver) { return false; } } return mContentProtectionBlocklistManager.isAllowed(packageName); } } private static class DataShareCallbackDelegate extends IDataShareCallback.Stub { Loading services/contentcapture/java/com/android/server/contentprotection/ContentProtectionBlocklistManager.java +2 −2 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ import java.util.stream.Collectors; * * @hide */ class ContentProtectionBlocklistManager { public class ContentProtectionBlocklistManager { private static final String TAG = "ContentProtectionBlocklistManager"; Loading @@ -46,7 +46,7 @@ class ContentProtectionBlocklistManager { @Nullable private Set<String> mPackageNameBlocklist; protected ContentProtectionBlocklistManager( public ContentProtectionBlocklistManager( @NonNull ContentProtectionPackageManager contentProtectionPackageManager) { mContentProtectionPackageManager = contentProtectionPackageManager; } Loading services/contentcapture/java/com/android/server/contentprotection/ContentProtectionPackageManager.java +1 −1 Original line number Diff line number Diff line Loading @@ -43,7 +43,7 @@ public class ContentProtectionPackageManager { @NonNull private final PackageManager mPackageManager; ContentProtectionPackageManager(@NonNull Context context) { public ContentProtectionPackageManager(@NonNull Context context) { mPackageManager = context.getPackageManager(); } Loading services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java +212 −5 Original line number Diff line number Diff line Loading @@ -18,8 +18,16 @@ package com.android.server.contentcapture; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.content.ComponentName; import android.content.ContentCaptureOptions; import android.content.Context; import android.content.pm.UserInfo; Loading @@ -29,6 +37,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.server.LocalServices; import com.android.server.contentprotection.ContentProtectionBlocklistManager; import com.android.server.pm.UserManagerInternal; import com.google.common.collect.ImmutableList; Loading Loading @@ -56,12 +65,21 @@ public class ContentCaptureManagerServiceTest { private static final String PACKAGE_NAME = "com.test.package"; private static final ComponentName COMPONENT_NAME = new ComponentName(PACKAGE_NAME, "TestClass"); private static final Context sContext = ApplicationProvider.getApplicationContext(); @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); @Mock private UserManagerInternal mMockUserManagerInternal; @Mock private ContentProtectionBlocklistManager mMockContentProtectionBlocklistManager; private boolean mDevCfgEnableContentProtectionReceiver; private int mContentProtectionBlocklistManagersCreated; private ContentCaptureManagerService mContentCaptureManagerService; @Before Loading @@ -69,20 +87,77 @@ public class ContentCaptureManagerServiceTest { when(mMockUserManagerInternal.getUserInfos()).thenReturn(new UserInfo[0]); LocalServices.removeServiceForTest(UserManagerInternal.class); LocalServices.addService(UserManagerInternal.class, mMockUserManagerInternal); mContentCaptureManagerService = new ContentCaptureManagerService(sContext); mContentCaptureManagerService = new TestContentCaptureManagerService(); } @Test public void constructor_default_doesNotCreateContentProtectionBlocklistManager() { assertThat(mContentProtectionBlocklistManagersCreated).isEqualTo(0); verifyZeroInteractions(mMockContentProtectionBlocklistManager); } @Test public void constructor_flagDisabled_doesNotContentProtectionBlocklistManager() { assertThat(mContentProtectionBlocklistManagersCreated).isEqualTo(0); verifyZeroInteractions(mMockContentProtectionBlocklistManager); } @Test public void constructor_flagEnabled_createsContentProtectionBlocklistManager() { mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); assertThat(mContentProtectionBlocklistManagersCreated).isEqualTo(1); verify(mMockContentProtectionBlocklistManager).updateBlocklist(anyInt()); } @Test public void getOptions_notAllowlisted() { public void setFineTuneParamsFromDeviceConfig_doesNotUpdateContentProtectionBlocklist() { mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); mContentCaptureManagerService.mDevCfgContentProtectionAppsBlocklistSize += 100; verify(mMockContentProtectionBlocklistManager).updateBlocklist(anyInt()); mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig(); verifyNoMoreInteractions(mMockContentProtectionBlocklistManager); } @Test public void getOptions_contentCaptureDisabled_contentProtectionDisabled() { mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); ContentCaptureOptions actual = mContentCaptureManagerService.mGlobalContentCaptureOptions.getOptions( USER_ID, PACKAGE_NAME); assertThat(actual).isNull(); verify(mMockContentProtectionBlocklistManager).isAllowed(PACKAGE_NAME); } @Test public void getOptions_contentCaptureDisabled_contentProtectionEnabled() { when(mMockContentProtectionBlocklistManager.isAllowed(PACKAGE_NAME)).thenReturn(true); mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); ContentCaptureOptions actual = mContentCaptureManagerService.mGlobalContentCaptureOptions.getOptions( USER_ID, PACKAGE_NAME); assertThat(actual).isNotNull(); assertThat(actual.enableReceiver).isFalse(); assertThat(actual.contentProtectionOptions).isNotNull(); assertThat(actual.contentProtectionOptions.enableReceiver).isTrue(); assertThat(actual.whitelistedComponents).isNull(); } @Test public void getOptions_allowlisted_contentCaptureReceiver() { public void getOptions_contentCaptureEnabled_contentProtectionDisabled() { mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); mContentCaptureManagerService.mGlobalContentCaptureOptions.setWhitelist( USER_ID, ImmutableList.of(PACKAGE_NAME), /* components= */ null); Loading @@ -92,13 +167,17 @@ public class ContentCaptureManagerServiceTest { assertThat(actual).isNotNull(); assertThat(actual.enableReceiver).isTrue(); assertThat(actual.contentProtectionOptions).isNotNull(); assertThat(actual.contentProtectionOptions.enableReceiver).isFalse(); assertThat(actual.whitelistedComponents).isNull(); verify(mMockContentProtectionBlocklistManager).isAllowed(PACKAGE_NAME); } @Test public void getOptions_allowlisted_bothReceivers() { mContentCaptureManagerService.mDevCfgEnableContentProtectionReceiver = true; public void getOptions_contentCaptureEnabled_contentProtectionEnabled() { when(mMockContentProtectionBlocklistManager.isAllowed(PACKAGE_NAME)).thenReturn(true); mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); mContentCaptureManagerService.mGlobalContentCaptureOptions.setWhitelist( USER_ID, ImmutableList.of(PACKAGE_NAME), /* components= */ null); Loading @@ -108,7 +187,135 @@ public class ContentCaptureManagerServiceTest { assertThat(actual).isNotNull(); assertThat(actual.enableReceiver).isTrue(); assertThat(actual.contentProtectionOptions).isNotNull(); assertThat(actual.contentProtectionOptions.enableReceiver).isTrue(); assertThat(actual.whitelistedComponents).isNull(); } @Test public void isWhitelisted_packageName_contentCaptureDisabled_contentProtectionDisabled() { mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); boolean actual = mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted( USER_ID, PACKAGE_NAME); assertThat(actual).isFalse(); verify(mMockContentProtectionBlocklistManager).isAllowed(PACKAGE_NAME); } @Test public void isWhitelisted_packageName_contentCaptureDisabled_contentProtectionEnabled() { when(mMockContentProtectionBlocklistManager.isAllowed(PACKAGE_NAME)).thenReturn(true); mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); boolean actual = mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted( USER_ID, PACKAGE_NAME); assertThat(actual).isTrue(); } @Test public void isWhitelisted_packageName_contentCaptureEnabled_contentProtectionNotChecked() { mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); mContentCaptureManagerService.mGlobalContentCaptureOptions.setWhitelist( USER_ID, ImmutableList.of(PACKAGE_NAME), /* components= */ null); boolean actual = mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted( USER_ID, PACKAGE_NAME); assertThat(actual).isTrue(); verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString()); } @Test public void isWhitelisted_componentName_contentCaptureDisabled_contentProtectionDisabled() { mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); boolean actual = mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted( USER_ID, COMPONENT_NAME); assertThat(actual).isFalse(); verify(mMockContentProtectionBlocklistManager).isAllowed(PACKAGE_NAME); } @Test public void isWhitelisted_componentName_contentCaptureDisabled_contentProtectionEnabled() { when(mMockContentProtectionBlocklistManager.isAllowed(PACKAGE_NAME)).thenReturn(true); mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); boolean actual = mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted( USER_ID, COMPONENT_NAME); assertThat(actual).isTrue(); } @Test public void isWhitelisted_componentName_contentCaptureEnabled_contentProtectionNotChecked() { mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); mContentCaptureManagerService.mGlobalContentCaptureOptions.setWhitelist( USER_ID, /* packageNames= */ null, ImmutableList.of(COMPONENT_NAME)); boolean actual = mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted( USER_ID, COMPONENT_NAME); assertThat(actual).isTrue(); verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString()); } @Test public void isContentProtectionReceiverEnabled_withoutBlocklistManager() { boolean actual = mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted( USER_ID, PACKAGE_NAME); assertThat(actual).isFalse(); verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString()); } @Test public void isContentProtectionReceiverEnabled_disabledWithFlag() { mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); mContentCaptureManagerService.mDevCfgEnableContentProtectionReceiver = false; boolean actual = mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted( USER_ID, PACKAGE_NAME); assertThat(actual).isFalse(); verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString()); } private class TestContentCaptureManagerService extends ContentCaptureManagerService { TestContentCaptureManagerService() { super(sContext); this.mDevCfgEnableContentProtectionReceiver = ContentCaptureManagerServiceTest.this.mDevCfgEnableContentProtectionReceiver; } @Override protected boolean getEnableContentProtectionReceiverLocked() { return ContentCaptureManagerServiceTest.this.mDevCfgEnableContentProtectionReceiver; } @Override protected ContentProtectionBlocklistManager createContentProtectionBlocklistManager( @NonNull Context context) { mContentProtectionBlocklistManagersCreated++; return mMockContentProtectionBlocklistManager; } } } Loading
services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java +84 −10 Original line number Diff line number Diff line Loading @@ -88,11 +88,14 @@ import android.view.contentcapture.IContentCaptureOptionsCallback; import android.view.contentcapture.IDataShareWriteAdapter; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.infra.AbstractRemoteService; import com.android.internal.infra.GlobalWhitelistState; import com.android.internal.os.IResultReceiver; import com.android.internal.util.DumpUtils; import com.android.server.LocalServices; import com.android.server.contentprotection.ContentProtectionBlocklistManager; import com.android.server.contentprotection.ContentProtectionPackageManager; import com.android.server.infra.AbstractMasterSystemService; import com.android.server.infra.FrameworkResourcesServiceNameResolver; Loading @@ -117,7 +120,7 @@ import java.util.concurrent.atomic.AtomicBoolean; * with other sources to provide contextual data in other areas of the system * such as Autofill. */ public final class ContentCaptureManagerService extends public class ContentCaptureManagerService extends AbstractMasterSystemService<ContentCaptureManagerService, ContentCapturePerUserService> { private static final String TAG = ContentCaptureManagerService.class.getSimpleName(); Loading Loading @@ -205,6 +208,8 @@ public final class ContentCaptureManagerService extends final GlobalContentCaptureOptions mGlobalContentCaptureOptions = new GlobalContentCaptureOptions(); @Nullable private final ContentProtectionBlocklistManager mContentProtectionBlocklistManager; public ContentCaptureManagerService(@NonNull Context context) { super(context, new FrameworkResourcesServiceNameResolver(context, com.android.internal.R.string.config_defaultContentCaptureService), Loading Loading @@ -242,6 +247,14 @@ public final class ContentCaptureManagerService extends mServiceNameResolver.getServiceName(userId), mServiceNameResolver.isTemporary(userId)); } if (getEnableContentProtectionReceiverLocked()) { mContentProtectionBlocklistManager = createContentProtectionBlocklistManager(context); mContentProtectionBlocklistManager.updateBlocklist( mDevCfgContentProtectionAppsBlocklistSize); } else { mContentProtectionBlocklistManager = null; } } @Override // from AbstractMasterSystemService Loading Loading @@ -397,7 +410,9 @@ public final class ContentCaptureManagerService extends } } private void setFineTuneParamsFromDeviceConfig() { /** @hide */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected void setFineTuneParamsFromDeviceConfig() { synchronized (mLock) { mDevCfgMaxBufferSize = DeviceConfig.getInt( Loading Loading @@ -443,6 +458,8 @@ public final class ContentCaptureManagerService extends ContentCaptureManager .DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_APPS_BLOCKLIST_SIZE, ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_APPS_BLOCKLIST_SIZE); // mContentProtectionBlocklistManager.updateBlocklist not called on purpose here to keep // it immutable at this point mDevCfgContentProtectionBufferSize = DeviceConfig.getInt( DeviceConfig.NAMESPACE_CONTENT_CAPTURE, Loading Loading @@ -754,6 +771,25 @@ public final class ContentCaptureManagerService extends mGlobalContentCaptureOptions.dump(prefix2, pw); } /** * Used by the constructor in order to be able to override the value in the tests. * * @hide */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) @GuardedBy("mLock") protected boolean getEnableContentProtectionReceiverLocked() { return mDevCfgEnableContentProtectionReceiver; } /** @hide */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) @NonNull protected ContentProtectionBlocklistManager createContentProtectionBlocklistManager( @NonNull Context context) { return new ContentProtectionBlocklistManager(new ContentProtectionPackageManager(context)); } final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub { @Override Loading Loading @@ -1075,14 +1111,21 @@ public final class ContentCaptureManagerService extends @GuardedBy("mGlobalWhitelistStateLock") public ContentCaptureOptions getOptions(@UserIdInt int userId, @NonNull String packageName) { boolean packageWhitelisted; boolean isContentCaptureReceiverEnabled; boolean isContentProtectionReceiverEnabled; ArraySet<ComponentName> whitelistedComponents = null; synchronized (mGlobalWhitelistStateLock) { packageWhitelisted = isWhitelisted(userId, packageName); if (!packageWhitelisted) { // Full package is not allowlisted: check individual components first isContentCaptureReceiverEnabled = isContentCaptureReceiverEnabled(userId, packageName); isContentProtectionReceiverEnabled = isContentProtectionReceiverEnabled(packageName); if (!isContentCaptureReceiverEnabled) { // Full package is not allowlisted: check individual components next whitelistedComponents = getWhitelistedComponents(userId, packageName); if (whitelistedComponents == null if (!isContentProtectionReceiverEnabled && whitelistedComponents == null && packageName.equals(mServicePackages.get(userId))) { // No components allowlisted either, but let it go because it's the // service's own package Loading @@ -1101,7 +1144,9 @@ public final class ContentCaptureManagerService extends } } if (!packageWhitelisted && whitelistedComponents == null) { if (!isContentCaptureReceiverEnabled && !isContentProtectionReceiverEnabled && whitelistedComponents == null) { // No can do! if (verbose) { Slog.v(TAG, "getOptionsForPackage(" + packageName + "): not whitelisted"); Loading @@ -1118,9 +1163,9 @@ public final class ContentCaptureManagerService extends mDevCfgTextChangeFlushingFrequencyMs, mDevCfgLogHistorySize, mDevCfgDisableFlushForViewTreeAppearing, /* enableReceiver= */ true, isContentCaptureReceiverEnabled || whitelistedComponents != null, new ContentCaptureOptions.ContentProtectionOptions( mDevCfgEnableContentProtectionReceiver, isContentProtectionReceiverEnabled, mDevCfgContentProtectionBufferSize), whitelistedComponents); if (verbose) Slog.v(TAG, "getOptionsForPackage(" + packageName + "): " + options); Loading @@ -1141,6 +1186,35 @@ public final class ContentCaptureManagerService extends } } } @Override // from GlobalWhitelistState public boolean isWhitelisted(@UserIdInt int userId, @NonNull String packageName) { return isContentCaptureReceiverEnabled(userId, packageName) || isContentProtectionReceiverEnabled(packageName); } @Override // from GlobalWhitelistState public boolean isWhitelisted(@UserIdInt int userId, @NonNull ComponentName componentName) { return super.isWhitelisted(userId, componentName) || isContentProtectionReceiverEnabled(componentName.getPackageName()); } private boolean isContentCaptureReceiverEnabled( @UserIdInt int userId, @NonNull String packageName) { return super.isWhitelisted(userId, packageName); } private boolean isContentProtectionReceiverEnabled(@NonNull String packageName) { if (mContentProtectionBlocklistManager == null) { return false; } synchronized (mLock) { if (!mDevCfgEnableContentProtectionReceiver) { return false; } } return mContentProtectionBlocklistManager.isAllowed(packageName); } } private static class DataShareCallbackDelegate extends IDataShareCallback.Stub { Loading
services/contentcapture/java/com/android/server/contentprotection/ContentProtectionBlocklistManager.java +2 −2 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ import java.util.stream.Collectors; * * @hide */ class ContentProtectionBlocklistManager { public class ContentProtectionBlocklistManager { private static final String TAG = "ContentProtectionBlocklistManager"; Loading @@ -46,7 +46,7 @@ class ContentProtectionBlocklistManager { @Nullable private Set<String> mPackageNameBlocklist; protected ContentProtectionBlocklistManager( public ContentProtectionBlocklistManager( @NonNull ContentProtectionPackageManager contentProtectionPackageManager) { mContentProtectionPackageManager = contentProtectionPackageManager; } Loading
services/contentcapture/java/com/android/server/contentprotection/ContentProtectionPackageManager.java +1 −1 Original line number Diff line number Diff line Loading @@ -43,7 +43,7 @@ public class ContentProtectionPackageManager { @NonNull private final PackageManager mPackageManager; ContentProtectionPackageManager(@NonNull Context context) { public ContentProtectionPackageManager(@NonNull Context context) { mPackageManager = context.getPackageManager(); } Loading
services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java +212 −5 Original line number Diff line number Diff line Loading @@ -18,8 +18,16 @@ package com.android.server.contentcapture; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.content.ComponentName; import android.content.ContentCaptureOptions; import android.content.Context; import android.content.pm.UserInfo; Loading @@ -29,6 +37,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.server.LocalServices; import com.android.server.contentprotection.ContentProtectionBlocklistManager; import com.android.server.pm.UserManagerInternal; import com.google.common.collect.ImmutableList; Loading Loading @@ -56,12 +65,21 @@ public class ContentCaptureManagerServiceTest { private static final String PACKAGE_NAME = "com.test.package"; private static final ComponentName COMPONENT_NAME = new ComponentName(PACKAGE_NAME, "TestClass"); private static final Context sContext = ApplicationProvider.getApplicationContext(); @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); @Mock private UserManagerInternal mMockUserManagerInternal; @Mock private ContentProtectionBlocklistManager mMockContentProtectionBlocklistManager; private boolean mDevCfgEnableContentProtectionReceiver; private int mContentProtectionBlocklistManagersCreated; private ContentCaptureManagerService mContentCaptureManagerService; @Before Loading @@ -69,20 +87,77 @@ public class ContentCaptureManagerServiceTest { when(mMockUserManagerInternal.getUserInfos()).thenReturn(new UserInfo[0]); LocalServices.removeServiceForTest(UserManagerInternal.class); LocalServices.addService(UserManagerInternal.class, mMockUserManagerInternal); mContentCaptureManagerService = new ContentCaptureManagerService(sContext); mContentCaptureManagerService = new TestContentCaptureManagerService(); } @Test public void constructor_default_doesNotCreateContentProtectionBlocklistManager() { assertThat(mContentProtectionBlocklistManagersCreated).isEqualTo(0); verifyZeroInteractions(mMockContentProtectionBlocklistManager); } @Test public void constructor_flagDisabled_doesNotContentProtectionBlocklistManager() { assertThat(mContentProtectionBlocklistManagersCreated).isEqualTo(0); verifyZeroInteractions(mMockContentProtectionBlocklistManager); } @Test public void constructor_flagEnabled_createsContentProtectionBlocklistManager() { mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); assertThat(mContentProtectionBlocklistManagersCreated).isEqualTo(1); verify(mMockContentProtectionBlocklistManager).updateBlocklist(anyInt()); } @Test public void getOptions_notAllowlisted() { public void setFineTuneParamsFromDeviceConfig_doesNotUpdateContentProtectionBlocklist() { mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); mContentCaptureManagerService.mDevCfgContentProtectionAppsBlocklistSize += 100; verify(mMockContentProtectionBlocklistManager).updateBlocklist(anyInt()); mContentCaptureManagerService.setFineTuneParamsFromDeviceConfig(); verifyNoMoreInteractions(mMockContentProtectionBlocklistManager); } @Test public void getOptions_contentCaptureDisabled_contentProtectionDisabled() { mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); ContentCaptureOptions actual = mContentCaptureManagerService.mGlobalContentCaptureOptions.getOptions( USER_ID, PACKAGE_NAME); assertThat(actual).isNull(); verify(mMockContentProtectionBlocklistManager).isAllowed(PACKAGE_NAME); } @Test public void getOptions_contentCaptureDisabled_contentProtectionEnabled() { when(mMockContentProtectionBlocklistManager.isAllowed(PACKAGE_NAME)).thenReturn(true); mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); ContentCaptureOptions actual = mContentCaptureManagerService.mGlobalContentCaptureOptions.getOptions( USER_ID, PACKAGE_NAME); assertThat(actual).isNotNull(); assertThat(actual.enableReceiver).isFalse(); assertThat(actual.contentProtectionOptions).isNotNull(); assertThat(actual.contentProtectionOptions.enableReceiver).isTrue(); assertThat(actual.whitelistedComponents).isNull(); } @Test public void getOptions_allowlisted_contentCaptureReceiver() { public void getOptions_contentCaptureEnabled_contentProtectionDisabled() { mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); mContentCaptureManagerService.mGlobalContentCaptureOptions.setWhitelist( USER_ID, ImmutableList.of(PACKAGE_NAME), /* components= */ null); Loading @@ -92,13 +167,17 @@ public class ContentCaptureManagerServiceTest { assertThat(actual).isNotNull(); assertThat(actual.enableReceiver).isTrue(); assertThat(actual.contentProtectionOptions).isNotNull(); assertThat(actual.contentProtectionOptions.enableReceiver).isFalse(); assertThat(actual.whitelistedComponents).isNull(); verify(mMockContentProtectionBlocklistManager).isAllowed(PACKAGE_NAME); } @Test public void getOptions_allowlisted_bothReceivers() { mContentCaptureManagerService.mDevCfgEnableContentProtectionReceiver = true; public void getOptions_contentCaptureEnabled_contentProtectionEnabled() { when(mMockContentProtectionBlocklistManager.isAllowed(PACKAGE_NAME)).thenReturn(true); mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); mContentCaptureManagerService.mGlobalContentCaptureOptions.setWhitelist( USER_ID, ImmutableList.of(PACKAGE_NAME), /* components= */ null); Loading @@ -108,7 +187,135 @@ public class ContentCaptureManagerServiceTest { assertThat(actual).isNotNull(); assertThat(actual.enableReceiver).isTrue(); assertThat(actual.contentProtectionOptions).isNotNull(); assertThat(actual.contentProtectionOptions.enableReceiver).isTrue(); assertThat(actual.whitelistedComponents).isNull(); } @Test public void isWhitelisted_packageName_contentCaptureDisabled_contentProtectionDisabled() { mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); boolean actual = mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted( USER_ID, PACKAGE_NAME); assertThat(actual).isFalse(); verify(mMockContentProtectionBlocklistManager).isAllowed(PACKAGE_NAME); } @Test public void isWhitelisted_packageName_contentCaptureDisabled_contentProtectionEnabled() { when(mMockContentProtectionBlocklistManager.isAllowed(PACKAGE_NAME)).thenReturn(true); mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); boolean actual = mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted( USER_ID, PACKAGE_NAME); assertThat(actual).isTrue(); } @Test public void isWhitelisted_packageName_contentCaptureEnabled_contentProtectionNotChecked() { mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); mContentCaptureManagerService.mGlobalContentCaptureOptions.setWhitelist( USER_ID, ImmutableList.of(PACKAGE_NAME), /* components= */ null); boolean actual = mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted( USER_ID, PACKAGE_NAME); assertThat(actual).isTrue(); verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString()); } @Test public void isWhitelisted_componentName_contentCaptureDisabled_contentProtectionDisabled() { mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); boolean actual = mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted( USER_ID, COMPONENT_NAME); assertThat(actual).isFalse(); verify(mMockContentProtectionBlocklistManager).isAllowed(PACKAGE_NAME); } @Test public void isWhitelisted_componentName_contentCaptureDisabled_contentProtectionEnabled() { when(mMockContentProtectionBlocklistManager.isAllowed(PACKAGE_NAME)).thenReturn(true); mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); boolean actual = mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted( USER_ID, COMPONENT_NAME); assertThat(actual).isTrue(); } @Test public void isWhitelisted_componentName_contentCaptureEnabled_contentProtectionNotChecked() { mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); mContentCaptureManagerService.mGlobalContentCaptureOptions.setWhitelist( USER_ID, /* packageNames= */ null, ImmutableList.of(COMPONENT_NAME)); boolean actual = mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted( USER_ID, COMPONENT_NAME); assertThat(actual).isTrue(); verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString()); } @Test public void isContentProtectionReceiverEnabled_withoutBlocklistManager() { boolean actual = mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted( USER_ID, PACKAGE_NAME); assertThat(actual).isFalse(); verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString()); } @Test public void isContentProtectionReceiverEnabled_disabledWithFlag() { mDevCfgEnableContentProtectionReceiver = true; mContentCaptureManagerService = new TestContentCaptureManagerService(); mContentCaptureManagerService.mDevCfgEnableContentProtectionReceiver = false; boolean actual = mContentCaptureManagerService.mGlobalContentCaptureOptions.isWhitelisted( USER_ID, PACKAGE_NAME); assertThat(actual).isFalse(); verify(mMockContentProtectionBlocklistManager, never()).isAllowed(anyString()); } private class TestContentCaptureManagerService extends ContentCaptureManagerService { TestContentCaptureManagerService() { super(sContext); this.mDevCfgEnableContentProtectionReceiver = ContentCaptureManagerServiceTest.this.mDevCfgEnableContentProtectionReceiver; } @Override protected boolean getEnableContentProtectionReceiverLocked() { return ContentCaptureManagerServiceTest.this.mDevCfgEnableContentProtectionReceiver; } @Override protected ContentProtectionBlocklistManager createContentProtectionBlocklistManager( @NonNull Context context) { mContentProtectionBlocklistManagersCreated++; return mMockContentProtectionBlocklistManager; } } }