| /* |
| * Copyright (C) 2022 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.adservices.service.consent; |
| |
| import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_SETTINGS_USAGE_REPORTED; |
| import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_SETTINGS_USAGE_REPORTED__ACTION__OPT_IN_SELECTED; |
| import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_SETTINGS_USAGE_REPORTED__REGION__EU; |
| import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_SETTINGS_USAGE_REPORTED__REGION__ROW; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertThrows; |
| import static org.junit.Assert.assertTrue; |
| import static org.mockito.ArgumentMatchers.any; |
| import static org.mockito.ArgumentMatchers.anyBoolean; |
| import static org.mockito.ArgumentMatchers.eq; |
| import static org.mockito.Mockito.doNothing; |
| import static org.mockito.Mockito.doReturn; |
| import static org.mockito.Mockito.doThrow; |
| import static org.mockito.Mockito.spy; |
| import static org.mockito.Mockito.times; |
| import static org.mockito.Mockito.verify; |
| import static org.mockito.Mockito.verifyNoMoreInteractions; |
| import static org.mockito.Mockito.when; |
| |
| import android.app.job.JobScheduler; |
| import android.content.Context; |
| import android.content.pm.ApplicationInfo; |
| import android.content.pm.PackageManager; |
| import android.os.SystemClock; |
| |
| import androidx.test.core.app.ApplicationProvider; |
| import androidx.test.core.content.pm.ApplicationInfoBuilder; |
| import androidx.test.filters.SmallTest; |
| |
| import com.android.adservices.data.DbHelper; |
| import com.android.adservices.data.DbTestUtil; |
| import com.android.adservices.data.common.BooleanFileDatastore; |
| import com.android.adservices.data.consent.AppConsentDao; |
| import com.android.adservices.data.consent.AppConsentDaoFixture; |
| import com.android.adservices.data.customaudience.CustomAudienceDao; |
| import com.android.adservices.data.enrollment.EnrollmentDao; |
| import com.android.adservices.data.topics.Topic; |
| import com.android.adservices.data.topics.TopicsTables; |
| import com.android.adservices.download.MddJobService; |
| import com.android.adservices.service.AdServicesConfig; |
| import com.android.adservices.service.Flags; |
| import com.android.adservices.service.FlagsFactory; |
| import com.android.adservices.service.MaintenanceJobService; |
| import com.android.adservices.service.common.BackgroundJobsManager; |
| import com.android.adservices.service.measurement.AsyncRegistrationQueueJobService; |
| import com.android.adservices.service.measurement.DeleteExpiredJobService; |
| import com.android.adservices.service.measurement.DeleteUninstalledJobService; |
| import com.android.adservices.service.measurement.MeasurementImpl; |
| import com.android.adservices.service.measurement.attribution.AttributionJobService; |
| import com.android.adservices.service.measurement.reporting.AggregateFallbackReportingJobService; |
| import com.android.adservices.service.measurement.reporting.AggregateReportingJobService; |
| import com.android.adservices.service.measurement.reporting.EventFallbackReportingJobService; |
| import com.android.adservices.service.measurement.reporting.EventReportingJobService; |
| import com.android.adservices.service.stats.AdServicesLoggerImpl; |
| import com.android.adservices.service.stats.UIStats; |
| import com.android.adservices.service.topics.AppUpdateManager; |
| import com.android.adservices.service.topics.BlockedTopicsManager; |
| import com.android.adservices.service.topics.CacheManager; |
| import com.android.adservices.service.topics.EpochJobService; |
| import com.android.adservices.service.topics.EpochManager; |
| import com.android.adservices.service.topics.TopicsWorker; |
| import com.android.dx.mockito.inline.extended.ExtendedMockito; |
| |
| import com.google.common.collect.ImmutableList; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.mockito.Mock; |
| import org.mockito.MockitoAnnotations; |
| import org.mockito.MockitoSession; |
| import org.mockito.Spy; |
| import org.mockito.quality.Strictness; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.stream.Collectors; |
| |
| @SmallTest |
| public class ConsentManagerTest { |
| @Spy private final Context mContextSpy = ApplicationProvider.getApplicationContext(); |
| |
| private BooleanFileDatastore mDatastore; |
| private ConsentManager mConsentManager; |
| private AppConsentDao mAppConsentDao; |
| private EnrollmentDao mEnrollmentDao; |
| private DbHelper mDbHelper; |
| |
| @Mock private PackageManager mPackageManagerMock; |
| @Mock private TopicsWorker mTopicsWorker; |
| @Mock private MeasurementImpl mMeasurementImpl; |
| @Mock private AdServicesLoggerImpl mAdServicesLoggerImpl; |
| @Mock private CustomAudienceDao mCustomAudienceDaoMock; |
| |
| @Mock private AppUpdateManager mAppUpdateManager; |
| @Mock private CacheManager mCacheManager; |
| @Mock private BlockedTopicsManager mBlockedTopicsManager; |
| @Mock private EpochManager mMockEpochManager; |
| @Mock private Flags mMockFlags; |
| @Mock private JobScheduler mJobSchedulerMock; |
| private MockitoSession mStaticMockSession = null; |
| |
| @Before |
| public void setup() throws IOException { |
| MockitoAnnotations.initMocks(this); |
| |
| mStaticMockSession = |
| ExtendedMockito.mockitoSession() |
| .spyStatic(AggregateReportingJobService.class) |
| .spyStatic(AggregateFallbackReportingJobService.class) |
| .spyStatic(AttributionJobService.class) |
| .spyStatic(BackgroundJobsManager.class) |
| .spyStatic(EpochJobService.class) |
| .spyStatic(EventReportingJobService.class) |
| .spyStatic(EventFallbackReportingJobService.class) |
| .spyStatic(DeleteExpiredJobService.class) |
| .spyStatic(DeleteUninstalledJobService.class) |
| .spyStatic(FlagsFactory.class) |
| .spyStatic(MaintenanceJobService.class) |
| .spyStatic(MddJobService.class) |
| .spyStatic(DeviceRegionProvider.class) |
| .spyStatic(AsyncRegistrationQueueJobService.class) |
| .strictness(Strictness.WARN) |
| .initMocks(this) |
| .startMocking(); |
| |
| mDatastore = |
| new BooleanFileDatastore(mContextSpy, AppConsentDaoFixture.TEST_DATASTORE_NAME, 1); |
| mAppConsentDao = spy(new AppConsentDao(mDatastore, mPackageManagerMock)); |
| mDbHelper = DbTestUtil.getDbHelperForTest(); |
| mEnrollmentDao = spy(new EnrollmentDao(mContextSpy, mDbHelper)); |
| |
| mConsentManager = |
| new ConsentManager( |
| mContextSpy, |
| mTopicsWorker, |
| mAppConsentDao, |
| mEnrollmentDao, |
| mMeasurementImpl, |
| mAdServicesLoggerImpl, |
| mCustomAudienceDaoMock, |
| mMockFlags); |
| |
| ExtendedMockito.doReturn(mMockFlags).when(FlagsFactory::getFlags); |
| ExtendedMockito.doReturn(true) |
| .when(() -> EpochJobService.scheduleIfNeeded(any(Context.class), eq(false))); |
| ExtendedMockito.doReturn(true) |
| .when(() -> MaintenanceJobService.scheduleIfNeeded(any(Context.class), eq(false))); |
| ExtendedMockito.doReturn(true) |
| .when(() -> MddJobService.scheduleIfNeeded(any(Context.class), eq(false))); |
| ExtendedMockito.doNothing() |
| .when(() -> AggregateReportingJobService.scheduleIfNeeded(any(), anyBoolean())); |
| ExtendedMockito.doNothing() |
| .when( |
| () -> |
| AggregateFallbackReportingJobService.scheduleIfNeeded( |
| any(), anyBoolean())); |
| ExtendedMockito.doNothing() |
| .when(() -> AttributionJobService.scheduleIfNeeded(any(), anyBoolean())); |
| ExtendedMockito.doReturn(true) |
| .when(() -> EpochJobService.scheduleIfNeeded(any(), anyBoolean())); |
| ExtendedMockito.doReturn(true) |
| .when(() -> MddJobService.scheduleIfNeeded(any(), anyBoolean())); |
| ExtendedMockito.doNothing() |
| .when(() -> EventReportingJobService.scheduleIfNeeded(any(), anyBoolean())); |
| ExtendedMockito.doNothing() |
| .when(() -> EventFallbackReportingJobService.scheduleIfNeeded(any(), anyBoolean())); |
| ExtendedMockito.doNothing() |
| .when(() -> DeleteExpiredJobService.scheduleIfNeeded(any(), anyBoolean())); |
| ExtendedMockito.doNothing() |
| .when(() -> DeleteUninstalledJobService.scheduleIfNeeded(any(), anyBoolean())); |
| ExtendedMockito.doReturn(true) |
| .when(() -> MaintenanceJobService.scheduleIfNeeded(any(), anyBoolean())); |
| ExtendedMockito.doNothing() |
| .when(() -> AsyncRegistrationQueueJobService.scheduleIfNeeded(any(), anyBoolean())); |
| } |
| |
| @After |
| public void teardown() throws IOException { |
| mDatastore.clear(); |
| if (mStaticMockSession != null) { |
| mStaticMockSession.finishMocking(); |
| } |
| } |
| |
| @Test |
| public void testConsentIsGivenAfterEnabling() { |
| mConsentManager.enable(mContextSpy); |
| |
| assertTrue(mConsentManager.getConsent().isGiven()); |
| } |
| |
| @Test |
| public void testConsentIsRevokedAfterDisabling() { |
| doReturn(mPackageManagerMock).when(mContextSpy).getPackageManager(); |
| mConsentManager.disable(mContextSpy); |
| |
| assertFalse(mConsentManager.getConsent().isGiven()); |
| } |
| |
| @Test |
| public void testJobsAreScheduledAfterEnablingKillSwitchOff() { |
| doReturn(mPackageManagerMock).when(mContextSpy).getPackageManager(); |
| doReturn(false).when(mMockFlags).getTopicsKillSwitch(); |
| doReturn(false).when(mMockFlags).getFledgeSelectAdsKillSwitch(); |
| doReturn(false).when(mMockFlags).getMeasurementKillSwitch(); |
| doReturn(false).when(mMockFlags).getMddBackgroundTaskKillSwitch(); |
| |
| mConsentManager.enable(mContextSpy); |
| |
| ExtendedMockito.verify( |
| () -> BackgroundJobsManager.scheduleAllBackgroundJobs(any(Context.class))); |
| ExtendedMockito.verify( |
| () -> EpochJobService.scheduleIfNeeded(any(Context.class), eq(false))); |
| ExtendedMockito.verify(() -> MddJobService.scheduleIfNeeded(any(Context.class), eq(false))); |
| ExtendedMockito.verify( |
| () -> MaintenanceJobService.scheduleIfNeeded(any(Context.class), eq(false)), |
| times(2)); |
| ExtendedMockito.verify( |
| () -> AggregateReportingJobService.scheduleIfNeeded(any(Context.class), eq(false))); |
| ExtendedMockito.verify( |
| () -> |
| AggregateFallbackReportingJobService.scheduleIfNeeded( |
| any(Context.class), eq(false))); |
| ExtendedMockito.verify( |
| () -> AttributionJobService.scheduleIfNeeded(any(Context.class), eq(false))); |
| ExtendedMockito.verify( |
| () -> EventReportingJobService.scheduleIfNeeded(any(Context.class), eq(false))); |
| ExtendedMockito.verify( |
| () -> |
| EventFallbackReportingJobService.scheduleIfNeeded( |
| any(Context.class), eq(false))); |
| ExtendedMockito.verify( |
| () -> DeleteExpiredJobService.scheduleIfNeeded(any(Context.class), eq(false))); |
| ExtendedMockito.verify( |
| () -> DeleteUninstalledJobService.scheduleIfNeeded(any(Context.class), eq(false))); |
| ExtendedMockito.verify( |
| () -> |
| AsyncRegistrationQueueJobService.scheduleIfNeeded( |
| any(Context.class), eq(false))); |
| } |
| |
| @Test |
| public void testJobsAreNotScheduledAfterEnablingKillSwitchOn() { |
| doReturn(mPackageManagerMock).when(mContextSpy).getPackageManager(); |
| doReturn(true).when(mMockFlags).getTopicsKillSwitch(); |
| doReturn(true).when(mMockFlags).getFledgeSelectAdsKillSwitch(); |
| doReturn(true).when(mMockFlags).getMeasurementKillSwitch(); |
| doReturn(true).when(mMockFlags).getMddBackgroundTaskKillSwitch(); |
| |
| mConsentManager.enable(mContextSpy); |
| |
| ExtendedMockito.verify( |
| () -> BackgroundJobsManager.scheduleAllBackgroundJobs(any(Context.class))); |
| ExtendedMockito.verify( |
| () -> EpochJobService.scheduleIfNeeded(any(Context.class), eq(false)), |
| ExtendedMockito.never()); |
| ExtendedMockito.verify( |
| () -> MaintenanceJobService.scheduleIfNeeded(any(Context.class), eq(false)), |
| ExtendedMockito.never()); |
| ExtendedMockito.verify( |
| () -> MddJobService.scheduleIfNeeded(any(Context.class), eq(false)), |
| ExtendedMockito.never()); |
| ExtendedMockito.verify( |
| () -> AggregateReportingJobService.scheduleIfNeeded(any(Context.class), eq(false)), |
| ExtendedMockito.never()); |
| ExtendedMockito.verify( |
| () -> |
| AggregateFallbackReportingJobService.scheduleIfNeeded( |
| any(Context.class), eq(false)), |
| ExtendedMockito.never()); |
| ExtendedMockito.verify( |
| () -> AttributionJobService.scheduleIfNeeded(any(Context.class), eq(false)), |
| ExtendedMockito.never()); |
| ExtendedMockito.verify( |
| () -> EventReportingJobService.scheduleIfNeeded(any(Context.class), eq(false)), |
| ExtendedMockito.never()); |
| ExtendedMockito.verify( |
| () -> |
| EventFallbackReportingJobService.scheduleIfNeeded( |
| any(Context.class), eq(false)), |
| ExtendedMockito.never()); |
| ExtendedMockito.verify( |
| () -> DeleteExpiredJobService.scheduleIfNeeded(any(Context.class), eq(false)), |
| ExtendedMockito.never()); |
| ExtendedMockito.verify( |
| () -> DeleteUninstalledJobService.scheduleIfNeeded(any(Context.class), eq(false)), |
| ExtendedMockito.never()); |
| ExtendedMockito.verify( |
| () -> |
| AsyncRegistrationQueueJobService.scheduleIfNeeded( |
| any(Context.class), eq(false)), |
| ExtendedMockito.never()); |
| } |
| |
| @Test |
| public void testJobsAreUnscheduledAfterDisabling() { |
| doReturn(mPackageManagerMock).when(mContextSpy).getPackageManager(); |
| doReturn(mJobSchedulerMock).when(mContextSpy).getSystemService(JobScheduler.class); |
| mConsentManager.disable(mContextSpy); |
| |
| verify(mJobSchedulerMock).cancel(AdServicesConfig.MAINTENANCE_JOB_ID); |
| verify(mJobSchedulerMock).cancel(AdServicesConfig.TOPICS_EPOCH_JOB_ID); |
| verify(mJobSchedulerMock).cancel(AdServicesConfig.MEASUREMENT_EVENT_MAIN_REPORTING_JOB_ID); |
| verify(mJobSchedulerMock).cancel(AdServicesConfig.MEASUREMENT_DELETE_EXPIRED_JOB_ID); |
| verify(mJobSchedulerMock).cancel(AdServicesConfig.MEASUREMENT_DELETE_UNINSTALLED_JOB_ID); |
| verify(mJobSchedulerMock).cancel(AdServicesConfig.MEASUREMENT_ATTRIBUTION_JOB_ID); |
| verify(mJobSchedulerMock) |
| .cancel(AdServicesConfig.MEASUREMENT_EVENT_FALLBACK_REPORTING_JOB_ID); |
| verify(mJobSchedulerMock) |
| .cancel(AdServicesConfig.MEASUREMENT_AGGREGATE_MAIN_REPORTING_JOB_ID); |
| verify(mJobSchedulerMock) |
| .cancel(AdServicesConfig.MEASUREMENT_AGGREGATE_FALLBACK_REPORTING_JOB_ID); |
| verify(mJobSchedulerMock).cancel(AdServicesConfig.ASYNC_REGISTRATION_QUEUE_JOB_ID); |
| verify(mJobSchedulerMock).cancel(AdServicesConfig.FLEDGE_BACKGROUND_FETCH_JOB_ID); |
| verify(mJobSchedulerMock).cancel(AdServicesConfig.CONSENT_NOTIFICATION_JOB_ID); |
| verify(mJobSchedulerMock).cancel(AdServicesConfig.MDD_MAINTENANCE_PERIODIC_TASK_JOB_ID); |
| verify(mJobSchedulerMock).cancel(AdServicesConfig.MDD_CHARGING_PERIODIC_TASK_JOB_ID); |
| verify(mJobSchedulerMock) |
| .cancel(AdServicesConfig.MDD_CELLULAR_CHARGING_PERIODIC_TASK_JOB_ID); |
| verify(mJobSchedulerMock).cancel(AdServicesConfig.MDD_WIFI_CHARGING_PERIODIC_TASK_JOB_ID); |
| |
| verifyNoMoreInteractions(mJobSchedulerMock); |
| } |
| |
| @Test |
| public void testDataIsResetAfterConsentIsRevoked() throws IOException { |
| doReturn(mPackageManagerMock).when(mContextSpy).getPackageManager(); |
| mConsentManager.disable(mContextSpy); |
| |
| SystemClock.sleep(1000); |
| verify(mTopicsWorker, times(1)).clearAllTopicsData(any()); |
| // TODO(b/240988406): change to test for correct method call |
| verify(mAppConsentDao, times(1)).clearAllConsentData(); |
| verify(mEnrollmentDao, times(1)).deleteAll(); |
| verify(mMeasurementImpl, times(1)).deleteAllMeasurementData(any()); |
| verify(mCustomAudienceDaoMock).deleteAllCustomAudienceData(); |
| } |
| |
| @Test |
| public void testIsFledgeConsentRevokedForAppWithFullApiConsent() |
| throws IOException, PackageManager.NameNotFoundException { |
| mConsentManager.enable(mContextSpy); |
| assertTrue(mConsentManager.getConsent().isGiven()); |
| |
| doReturn(AppConsentDaoFixture.APP10_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP10_PACKAGE_NAME), any()); |
| doReturn(AppConsentDaoFixture.APP20_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP20_PACKAGE_NAME), any()); |
| doReturn(AppConsentDaoFixture.APP30_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP30_PACKAGE_NAME), any()); |
| |
| mDatastore.put(AppConsentDaoFixture.APP10_DATASTORE_KEY, false); |
| mDatastore.put(AppConsentDaoFixture.APP20_DATASTORE_KEY, true); |
| |
| assertFalse( |
| mConsentManager.isFledgeConsentRevokedForApp( |
| AppConsentDaoFixture.APP10_PACKAGE_NAME)); |
| assertTrue( |
| mConsentManager.isFledgeConsentRevokedForApp( |
| AppConsentDaoFixture.APP20_PACKAGE_NAME)); |
| assertFalse( |
| mConsentManager.isFledgeConsentRevokedForApp( |
| AppConsentDaoFixture.APP30_PACKAGE_NAME)); |
| } |
| |
| @Test |
| public void testIsFledgeConsentRevokedForAppWithoutPrivacySandboxConsent() |
| throws PackageManager.NameNotFoundException { |
| doReturn(mPackageManagerMock).when(mContextSpy).getPackageManager(); |
| mConsentManager.disable(mContextSpy); |
| assertFalse(mConsentManager.getConsent().isGiven()); |
| |
| doReturn(AppConsentDaoFixture.APP10_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP10_PACKAGE_NAME), any()); |
| doReturn(AppConsentDaoFixture.APP20_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP20_PACKAGE_NAME), any()); |
| |
| assertTrue( |
| mConsentManager.isFledgeConsentRevokedForApp( |
| AppConsentDaoFixture.APP10_PACKAGE_NAME)); |
| assertTrue( |
| mConsentManager.isFledgeConsentRevokedForApp( |
| AppConsentDaoFixture.APP20_PACKAGE_NAME)); |
| } |
| |
| @Test |
| public void testIsFledgeConsentRevokedForNotFoundAppThrows() |
| throws PackageManager.NameNotFoundException { |
| mConsentManager.enable(mContextSpy); |
| assertTrue(mConsentManager.getConsent().isGiven()); |
| |
| doThrow(PackageManager.NameNotFoundException.class) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP_NOT_FOUND_PACKAGE_NAME), any()); |
| |
| assertThrows( |
| IllegalArgumentException.class, |
| () -> |
| mConsentManager.isFledgeConsentRevokedForApp( |
| AppConsentDaoFixture.APP_NOT_FOUND_PACKAGE_NAME)); |
| } |
| |
| @Test |
| public void testIsFledgeConsentRevokedForAppAfterSettingFledgeUseWithFullApiConsent() |
| throws IOException, PackageManager.NameNotFoundException { |
| mConsentManager.enable(mContextSpy); |
| assertTrue(mConsentManager.getConsent().isGiven()); |
| |
| doReturn(AppConsentDaoFixture.APP10_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP10_PACKAGE_NAME), any()); |
| doReturn(AppConsentDaoFixture.APP20_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP20_PACKAGE_NAME), any()); |
| doReturn(AppConsentDaoFixture.APP30_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP30_PACKAGE_NAME), any()); |
| |
| mDatastore.put(AppConsentDaoFixture.APP10_DATASTORE_KEY, false); |
| mDatastore.put(AppConsentDaoFixture.APP20_DATASTORE_KEY, true); |
| |
| assertFalse( |
| mConsentManager.isFledgeConsentRevokedForAppAfterSettingFledgeUse( |
| AppConsentDaoFixture.APP10_PACKAGE_NAME)); |
| assertTrue( |
| mConsentManager.isFledgeConsentRevokedForAppAfterSettingFledgeUse( |
| AppConsentDaoFixture.APP20_PACKAGE_NAME)); |
| assertFalse( |
| mConsentManager.isFledgeConsentRevokedForAppAfterSettingFledgeUse( |
| AppConsentDaoFixture.APP30_PACKAGE_NAME)); |
| } |
| |
| @Test |
| public void testIsFledgeConsentRevokedForAppAfterSettingFledgeUseWithoutPrivacySandboxConsent() |
| throws PackageManager.NameNotFoundException { |
| doReturn(mPackageManagerMock).when(mContextSpy).getPackageManager(); |
| mConsentManager.disable(mContextSpy); |
| assertFalse(mConsentManager.getConsent().isGiven()); |
| |
| doReturn(AppConsentDaoFixture.APP10_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP10_PACKAGE_NAME), any()); |
| doReturn(AppConsentDaoFixture.APP20_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP20_PACKAGE_NAME), any()); |
| |
| assertTrue( |
| mConsentManager.isFledgeConsentRevokedForAppAfterSettingFledgeUse( |
| AppConsentDaoFixture.APP10_PACKAGE_NAME)); |
| assertTrue( |
| mConsentManager.isFledgeConsentRevokedForAppAfterSettingFledgeUse( |
| AppConsentDaoFixture.APP20_PACKAGE_NAME)); |
| } |
| |
| @Test |
| public void testIsFledgeConsentRevokedForAppAfterSettingFledgeUseThrows() |
| throws PackageManager.NameNotFoundException { |
| mConsentManager.enable(mContextSpy); |
| assertTrue(mConsentManager.getConsent().isGiven()); |
| |
| doThrow(PackageManager.NameNotFoundException.class) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP_NOT_FOUND_PACKAGE_NAME), any()); |
| |
| assertThrows( |
| IllegalArgumentException.class, |
| () -> |
| mConsentManager.isFledgeConsentRevokedForAppAfterSettingFledgeUse( |
| AppConsentDaoFixture.APP_NOT_FOUND_PACKAGE_NAME)); |
| } |
| |
| @Test |
| public void testGetKnownAppsWithConsent() |
| throws IOException, PackageManager.NameNotFoundException { |
| mConsentManager.enable(mContextSpy); |
| assertTrue(mConsentManager.getConsent().isGiven()); |
| doReturn(AppConsentDaoFixture.APP10_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP10_PACKAGE_NAME), any()); |
| doReturn(AppConsentDaoFixture.APP20_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP20_PACKAGE_NAME), any()); |
| doReturn(AppConsentDaoFixture.APP30_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP30_PACKAGE_NAME), any()); |
| mDatastore.put(AppConsentDaoFixture.APP10_DATASTORE_KEY, false); |
| mDatastore.put(AppConsentDaoFixture.APP20_DATASTORE_KEY, false); |
| mDatastore.put(AppConsentDaoFixture.APP30_DATASTORE_KEY, false); |
| List<ApplicationInfo> applicationsInstalled = |
| Arrays.asList( |
| ApplicationInfoBuilder.newBuilder() |
| .setPackageName(AppConsentDaoFixture.APP10_PACKAGE_NAME) |
| .build(), |
| ApplicationInfoBuilder.newBuilder() |
| .setPackageName(AppConsentDaoFixture.APP20_PACKAGE_NAME) |
| .build(), |
| ApplicationInfoBuilder.newBuilder() |
| .setPackageName(AppConsentDaoFixture.APP30_PACKAGE_NAME) |
| .build()); |
| doReturn(applicationsInstalled) |
| .when(mPackageManagerMock) |
| .getInstalledApplications(any(PackageManager.ApplicationInfoFlags.class)); |
| |
| ImmutableList<App> knownAppsWithConsent = mConsentManager.getKnownAppsWithConsent(); |
| ImmutableList<App> appsWithRevokedConsent = mConsentManager.getAppsWithRevokedConsent(); |
| |
| // all apps have received a consent |
| assertThat(knownAppsWithConsent).hasSize(3); |
| assertThat(appsWithRevokedConsent).isEmpty(); |
| } |
| |
| @Test |
| public void testGetKnownAppsWithConsentAfterConsentForOneOfThemWasRevoked() |
| throws IOException, PackageManager.NameNotFoundException, InterruptedException { |
| doNothing().when(mCustomAudienceDaoMock).deleteCustomAudienceDataByOwner(any()); |
| |
| mConsentManager.enable(mContextSpy); |
| assertTrue(mConsentManager.getConsent().isGiven()); |
| doReturn(AppConsentDaoFixture.APP10_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP10_PACKAGE_NAME), any()); |
| doReturn(AppConsentDaoFixture.APP20_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP20_PACKAGE_NAME), any()); |
| doReturn(AppConsentDaoFixture.APP30_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP30_PACKAGE_NAME), any()); |
| mDatastore.put(AppConsentDaoFixture.APP10_DATASTORE_KEY, false); |
| mDatastore.put(AppConsentDaoFixture.APP20_DATASTORE_KEY, false); |
| mDatastore.put(AppConsentDaoFixture.APP30_DATASTORE_KEY, false); |
| List<ApplicationInfo> applicationsInstalled = |
| Arrays.asList( |
| ApplicationInfoBuilder.newBuilder() |
| .setPackageName(AppConsentDaoFixture.APP10_PACKAGE_NAME) |
| .build(), |
| ApplicationInfoBuilder.newBuilder() |
| .setPackageName(AppConsentDaoFixture.APP20_PACKAGE_NAME) |
| .build(), |
| ApplicationInfoBuilder.newBuilder() |
| .setPackageName(AppConsentDaoFixture.APP30_PACKAGE_NAME) |
| .build()); |
| doReturn(applicationsInstalled) |
| .when(mPackageManagerMock) |
| .getInstalledApplications(any(PackageManager.ApplicationInfoFlags.class)); |
| App app = App.create(AppConsentDaoFixture.APP10_PACKAGE_NAME); |
| |
| // revoke consent for first app |
| mConsentManager.revokeConsentForApp(app); |
| ImmutableList<App> knownAppsWithConsent = mConsentManager.getKnownAppsWithConsent(); |
| ImmutableList<App> appsWithRevokedConsent = mConsentManager.getAppsWithRevokedConsent(); |
| |
| // all apps have received a consent |
| assertThat(knownAppsWithConsent).hasSize(2); |
| assertThat(appsWithRevokedConsent).hasSize(1); |
| App appWithRevokedConsent = appsWithRevokedConsent.get(0); |
| assertThat(appWithRevokedConsent.getPackageName()).isEqualTo(app.getPackageName()); |
| |
| SystemClock.sleep(1000); |
| verify(mCustomAudienceDaoMock).deleteCustomAudienceDataByOwner(app.getPackageName()); |
| } |
| |
| @Test |
| public void testGetKnownAppsWithConsentAfterConsentForOneOfThemWasRevokedAndRestored() |
| throws IOException, PackageManager.NameNotFoundException, InterruptedException { |
| doNothing().when(mCustomAudienceDaoMock).deleteCustomAudienceDataByOwner(any()); |
| |
| mConsentManager.enable(mContextSpy); |
| assertTrue(mConsentManager.getConsent().isGiven()); |
| doReturn(AppConsentDaoFixture.APP10_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP10_PACKAGE_NAME), any()); |
| doReturn(AppConsentDaoFixture.APP20_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP20_PACKAGE_NAME), any()); |
| doReturn(AppConsentDaoFixture.APP30_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP30_PACKAGE_NAME), any()); |
| mDatastore.put(AppConsentDaoFixture.APP10_DATASTORE_KEY, false); |
| mDatastore.put(AppConsentDaoFixture.APP20_DATASTORE_KEY, false); |
| mDatastore.put(AppConsentDaoFixture.APP30_DATASTORE_KEY, false); |
| App app = App.create(AppConsentDaoFixture.APP10_PACKAGE_NAME); |
| List<ApplicationInfo> applicationsInstalled = |
| Arrays.asList( |
| ApplicationInfoBuilder.newBuilder() |
| .setPackageName(AppConsentDaoFixture.APP10_PACKAGE_NAME) |
| .build(), |
| ApplicationInfoBuilder.newBuilder() |
| .setPackageName(AppConsentDaoFixture.APP20_PACKAGE_NAME) |
| .build(), |
| ApplicationInfoBuilder.newBuilder() |
| .setPackageName(AppConsentDaoFixture.APP30_PACKAGE_NAME) |
| .build()); |
| doReturn(applicationsInstalled) |
| .when(mPackageManagerMock) |
| .getInstalledApplications(any(PackageManager.ApplicationInfoFlags.class)); |
| |
| // revoke consent for first app |
| mConsentManager.revokeConsentForApp(app); |
| ImmutableList<App> knownAppsWithConsent = mConsentManager.getKnownAppsWithConsent(); |
| ImmutableList<App> appsWithRevokedConsent = mConsentManager.getAppsWithRevokedConsent(); |
| |
| // all apps have received a consent |
| assertThat(knownAppsWithConsent).hasSize(2); |
| assertThat(appsWithRevokedConsent).hasSize(1); |
| App appWithRevokedConsent = appsWithRevokedConsent.get(0); |
| assertThat(appWithRevokedConsent.getPackageName()).isEqualTo(app.getPackageName()); |
| |
| SystemClock.sleep(1000); |
| verify(mCustomAudienceDaoMock).deleteCustomAudienceDataByOwner(app.getPackageName()); |
| |
| // restore consent for first app |
| mConsentManager.restoreConsentForApp(app); |
| knownAppsWithConsent = mConsentManager.getKnownAppsWithConsent(); |
| appsWithRevokedConsent = mConsentManager.getAppsWithRevokedConsent(); |
| |
| // all apps have received a consent |
| assertThat(knownAppsWithConsent).hasSize(3); |
| assertThat(appsWithRevokedConsent).isEmpty(); |
| } |
| |
| @Test |
| public void testGetKnownTopicsWithConsent() { |
| long taxonomyVersion = 1L; |
| long modelVersion = 1L; |
| Topic topic1 = Topic.create(1, taxonomyVersion, modelVersion); |
| Topic topic2 = Topic.create(2, taxonomyVersion, modelVersion); |
| ImmutableList<Topic> expectedKnownTopicsWithConsent = ImmutableList.of(topic1, topic2); |
| doReturn(expectedKnownTopicsWithConsent).when(mTopicsWorker).getKnownTopicsWithConsent(); |
| |
| ImmutableList<Topic> knownTopicsWithConsent = mConsentManager.getKnownTopicsWithConsent(); |
| |
| assertThat(knownTopicsWithConsent) |
| .containsExactlyElementsIn(expectedKnownTopicsWithConsent); |
| } |
| |
| @Test |
| public void testGetTopicsWithRevokedConsent() { |
| long taxonomyVersion = 1L; |
| long modelVersion = 1L; |
| Topic topic1 = Topic.create(1, taxonomyVersion, modelVersion); |
| Topic topic2 = Topic.create(2, taxonomyVersion, modelVersion); |
| ImmutableList<Topic> expectedTopicsWithRevokedConsent = ImmutableList.of(topic1, topic2); |
| doReturn(expectedTopicsWithRevokedConsent) |
| .when(mTopicsWorker) |
| .getTopicsWithRevokedConsent(); |
| |
| ImmutableList<Topic> topicsWithRevokedConsent = |
| mConsentManager.getTopicsWithRevokedConsent(); |
| |
| assertThat(topicsWithRevokedConsent) |
| .containsExactlyElementsIn(expectedTopicsWithRevokedConsent); |
| } |
| |
| @Test |
| public void testResetAllAppConsentAndAppData() |
| throws IOException, PackageManager.NameNotFoundException { |
| doNothing().when(mCustomAudienceDaoMock).deleteAllCustomAudienceData(); |
| |
| // Prepopulate with consent data for some apps |
| mConsentManager.enable(mContextSpy); |
| assertTrue(mConsentManager.getConsent().isGiven()); |
| doReturn(AppConsentDaoFixture.APP10_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP10_PACKAGE_NAME), any()); |
| doReturn(AppConsentDaoFixture.APP20_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP20_PACKAGE_NAME), any()); |
| doReturn(AppConsentDaoFixture.APP30_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP30_PACKAGE_NAME), any()); |
| mDatastore.put(AppConsentDaoFixture.APP10_DATASTORE_KEY, false); |
| mDatastore.put(AppConsentDaoFixture.APP20_DATASTORE_KEY, true); |
| mDatastore.put(AppConsentDaoFixture.APP30_DATASTORE_KEY, false); |
| List<ApplicationInfo> applicationsInstalled = |
| Arrays.asList( |
| ApplicationInfoBuilder.newBuilder() |
| .setPackageName(AppConsentDaoFixture.APP10_PACKAGE_NAME) |
| .build(), |
| ApplicationInfoBuilder.newBuilder() |
| .setPackageName(AppConsentDaoFixture.APP20_PACKAGE_NAME) |
| .build(), |
| ApplicationInfoBuilder.newBuilder() |
| .setPackageName(AppConsentDaoFixture.APP30_PACKAGE_NAME) |
| .build()); |
| doReturn(applicationsInstalled) |
| .when(mPackageManagerMock) |
| .getInstalledApplications(any(PackageManager.ApplicationInfoFlags.class)); |
| |
| // Verify population was successful |
| ImmutableList<App> knownAppsWithConsent = mConsentManager.getKnownAppsWithConsent(); |
| ImmutableList<App> appsWithRevokedConsent = mConsentManager.getAppsWithRevokedConsent(); |
| assertThat(knownAppsWithConsent).hasSize(2); |
| assertThat(appsWithRevokedConsent).hasSize(1); |
| |
| mConsentManager.resetAppsAndBlockedApps(); |
| |
| // All app consent data was deleted |
| knownAppsWithConsent = mConsentManager.getKnownAppsWithConsent(); |
| appsWithRevokedConsent = mConsentManager.getAppsWithRevokedConsent(); |
| assertThat(knownAppsWithConsent).isEmpty(); |
| assertThat(appsWithRevokedConsent).isEmpty(); |
| |
| SystemClock.sleep(1000); |
| verify(mCustomAudienceDaoMock).deleteAllCustomAudienceData(); |
| } |
| |
| @Test |
| public void testResetAllowedAppConsentAndAppData() |
| throws IOException, PackageManager.NameNotFoundException { |
| doNothing().when(mCustomAudienceDaoMock).deleteAllCustomAudienceData(); |
| |
| // Prepopulate with consent data for some apps |
| mConsentManager.enable(mContextSpy); |
| assertTrue(mConsentManager.getConsent().isGiven()); |
| doReturn(AppConsentDaoFixture.APP10_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP10_PACKAGE_NAME), any()); |
| doReturn(AppConsentDaoFixture.APP20_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP20_PACKAGE_NAME), any()); |
| doReturn(AppConsentDaoFixture.APP30_UID) |
| .when(mPackageManagerMock) |
| .getPackageUid(eq(AppConsentDaoFixture.APP30_PACKAGE_NAME), any()); |
| mDatastore.put(AppConsentDaoFixture.APP10_DATASTORE_KEY, false); |
| mDatastore.put(AppConsentDaoFixture.APP20_DATASTORE_KEY, true); |
| mDatastore.put(AppConsentDaoFixture.APP30_DATASTORE_KEY, false); |
| List<ApplicationInfo> applicationsInstalled = |
| Arrays.asList( |
| ApplicationInfoBuilder.newBuilder() |
| .setPackageName(AppConsentDaoFixture.APP10_PACKAGE_NAME) |
| .build(), |
| ApplicationInfoBuilder.newBuilder() |
| .setPackageName(AppConsentDaoFixture.APP20_PACKAGE_NAME) |
| .build(), |
| ApplicationInfoBuilder.newBuilder() |
| .setPackageName(AppConsentDaoFixture.APP30_PACKAGE_NAME) |
| .build()); |
| doReturn(applicationsInstalled) |
| .when(mPackageManagerMock) |
| .getInstalledApplications(any(PackageManager.ApplicationInfoFlags.class)); |
| |
| // Verify population was successful |
| ImmutableList<App> knownAppsWithConsentBeforeReset = |
| mConsentManager.getKnownAppsWithConsent(); |
| ImmutableList<App> appsWithRevokedConsentBeforeReset = |
| mConsentManager.getAppsWithRevokedConsent(); |
| assertThat(knownAppsWithConsentBeforeReset).hasSize(2); |
| assertThat(appsWithRevokedConsentBeforeReset).hasSize(1); |
| mConsentManager.resetApps(); |
| |
| // Known apps with consent were cleared; revoked apps were not deleted |
| ImmutableList<App> knownAppsWithConsentAfterReset = |
| mConsentManager.getKnownAppsWithConsent(); |
| ImmutableList<App> appsWithRevokedConsentAfterReset = |
| mConsentManager.getAppsWithRevokedConsent(); |
| assertThat(knownAppsWithConsentAfterReset).isEmpty(); |
| assertThat(appsWithRevokedConsentAfterReset).hasSize(1); |
| assertThat( |
| appsWithRevokedConsentAfterReset.stream() |
| .map(App::getPackageName) |
| .collect(Collectors.toList())) |
| .containsExactlyElementsIn( |
| appsWithRevokedConsentBeforeReset.stream() |
| .map(App::getPackageName) |
| .collect(Collectors.toList())); |
| |
| SystemClock.sleep(1000); |
| verify(mCustomAudienceDaoMock).deleteAllCustomAudienceData(); |
| } |
| |
| @Test |
| public void testNotificationDisplayedRecorded() { |
| Boolean wasNotificationDisplayed = mConsentManager.wasNotificationDisplayed(); |
| |
| assertThat(wasNotificationDisplayed).isFalse(); |
| |
| mConsentManager.recordNotificationDisplayed(); |
| wasNotificationDisplayed = mConsentManager.wasNotificationDisplayed(); |
| |
| assertThat(wasNotificationDisplayed).isTrue(); |
| } |
| |
| @Test |
| public void testTopicsProxyCalls() { |
| Topic topic = Topic.create(1, 1, 1); |
| ArrayList<String> tablesToBlock = new ArrayList<>(); |
| tablesToBlock.add(TopicsTables.BlockedTopicsContract.TABLE); |
| |
| TopicsWorker topicsWorker = |
| spy( |
| new TopicsWorker( |
| mMockEpochManager, |
| mCacheManager, |
| mBlockedTopicsManager, |
| mAppUpdateManager, |
| mMockFlags)); |
| // Enable TopicContributors feature |
| when(mMockEpochManager.supportsTopicContributorFeature()).thenReturn(true); |
| |
| ConsentManager consentManager = |
| new ConsentManager( |
| mContextSpy, |
| topicsWorker, |
| mAppConsentDao, |
| mEnrollmentDao, |
| mMeasurementImpl, |
| mAdServicesLoggerImpl, |
| mCustomAudienceDaoMock, |
| mMockFlags); |
| doNothing().when(mBlockedTopicsManager).blockTopic(any()); |
| doNothing().when(mBlockedTopicsManager).unblockTopic(any()); |
| // The actual usage is to invoke clearAllTopicsData() from TopicsWorker |
| doNothing().when(topicsWorker).clearAllTopicsData(any()); |
| |
| consentManager.revokeConsentForTopic(topic); |
| consentManager.restoreConsentForTopic(topic); |
| consentManager.resetTopics(); |
| |
| verify(mBlockedTopicsManager).blockTopic(topic); |
| verify(mBlockedTopicsManager).unblockTopic(topic); |
| verify(topicsWorker).clearAllTopicsData(tablesToBlock); |
| } |
| |
| @Test |
| public void testLoggingSettingsUsageReportedOptInSelectedRow() { |
| ExtendedMockito.doReturn(false) |
| .when(() -> DeviceRegionProvider.isEuDevice(any(Context.class))); |
| ConsentManager temporalConsentManager = |
| new ConsentManager( |
| mContextSpy, |
| mTopicsWorker, |
| mAppConsentDao, |
| mEnrollmentDao, |
| mMeasurementImpl, |
| mAdServicesLoggerImpl, |
| mCustomAudienceDaoMock, |
| mMockFlags); |
| |
| temporalConsentManager.enable(mContextSpy); |
| |
| UIStats expectedUIStats = |
| new UIStats.Builder() |
| .setCode(AD_SERVICES_SETTINGS_USAGE_REPORTED) |
| .setRegion(AD_SERVICES_SETTINGS_USAGE_REPORTED__REGION__ROW) |
| .setAction(AD_SERVICES_SETTINGS_USAGE_REPORTED__ACTION__OPT_IN_SELECTED) |
| .build(); |
| |
| verify(mAdServicesLoggerImpl, times(1)).logUIStats(any()); |
| verify(mAdServicesLoggerImpl, times(1)).logUIStats(expectedUIStats); |
| } |
| |
| @Test |
| public void testLoggingSettingsUsageReportedOptInSelectedEu() { |
| ExtendedMockito.doReturn(true) |
| .when(() -> DeviceRegionProvider.isEuDevice(any(Context.class))); |
| ConsentManager temporalConsentManager = |
| new ConsentManager( |
| mContextSpy, |
| mTopicsWorker, |
| mAppConsentDao, |
| mEnrollmentDao, |
| mMeasurementImpl, |
| mAdServicesLoggerImpl, |
| mCustomAudienceDaoMock, |
| mMockFlags); |
| |
| temporalConsentManager.enable(mContextSpy); |
| |
| UIStats expectedUIStats = |
| new UIStats.Builder() |
| .setCode(AD_SERVICES_SETTINGS_USAGE_REPORTED) |
| .setRegion(AD_SERVICES_SETTINGS_USAGE_REPORTED__REGION__EU) |
| .setAction(AD_SERVICES_SETTINGS_USAGE_REPORTED__ACTION__OPT_IN_SELECTED) |
| .build(); |
| |
| verify(mAdServicesLoggerImpl, times(1)).logUIStats(any()); |
| verify(mAdServicesLoggerImpl, times(1)).logUIStats(expectedUIStats); |
| } |
| |
| @Test |
| public void testGetInitializedConsentPerApi_aggregatedConsentInitializedAndGiven() { |
| mConsentManager.enable(mContextSpy); |
| |
| assertTrue(mConsentManager.getConsent(AdServicesApiType.TOPICS).isGiven()); |
| assertTrue(mConsentManager.getConsent(AdServicesApiType.MEASUREMENTS).isGiven()); |
| assertTrue(mConsentManager.getConsent(AdServicesApiType.FLEDGE).isGiven()); |
| } |
| |
| @Test |
| public void testGetInitializedConsentPerApi_aggregatedConsentInitializedAndRevoked() { |
| mConsentManager.disable(mContextSpy); |
| |
| assertFalse(mConsentManager.getConsent(AdServicesApiType.TOPICS).isGiven()); |
| assertFalse(mConsentManager.getConsent(AdServicesApiType.MEASUREMENTS).isGiven()); |
| assertFalse(mConsentManager.getConsent(AdServicesApiType.FLEDGE).isGiven()); |
| } |
| |
| @Test |
| public void testGetInitializedConsentPerApi_aggregatedConsentNotInitialized() { |
| assertFalse(mConsentManager.getConsent(AdServicesApiType.TOPICS).isGiven()); |
| assertFalse(mConsentManager.getConsent(AdServicesApiType.MEASUREMENTS).isGiven()); |
| assertFalse(mConsentManager.getConsent(AdServicesApiType.FLEDGE).isGiven()); |
| } |
| } |