• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.adservices.service.consent;
18 
19 import static android.adservices.common.AdServicesCommonManager.MODULE_MEASUREMENT;
20 import static android.adservices.common.AdServicesCommonManager.MODULE_ON_DEVICE_PERSONALIZATION;
21 import static android.adservices.common.AdServicesCommonManager.MODULE_PROTECTED_APP_SIGNALS;
22 import static android.adservices.common.AdServicesCommonManager.MODULE_PROTECTED_AUDIENCE;
23 import static android.adservices.common.AdServicesCommonManager.MODULE_STATE_DISABLED;
24 import static android.adservices.common.AdServicesCommonManager.MODULE_STATE_ENABLED;
25 import static android.adservices.common.AdServicesCommonManager.MODULE_STATE_UNKNOWN;
26 import static android.adservices.common.AdServicesCommonManager.MODULE_TOPICS;
27 import static android.adservices.common.AdServicesCommonManager.ModuleState;
28 import static android.adservices.common.AdServicesModuleUserChoice.USER_CHOICE_OPTED_IN;
29 import static android.adservices.common.AdServicesModuleUserChoice.USER_CHOICE_OPTED_OUT;
30 import static android.adservices.common.AdServicesModuleUserChoice.USER_CHOICE_UNKNOWN;
31 import static android.adservices.common.Module.MEASUREMENT;
32 import static android.adservices.common.Module.ON_DEVICE_PERSONALIZATION;
33 import static android.adservices.common.Module.PROTECTED_APP_SIGNALS;
34 import static android.adservices.common.Module.PROTECTED_AUDIENCE;
35 import static android.adservices.common.Module.TOPICS;
36 
37 import static com.android.adservices.AdServicesCommon.ADEXTSERVICES_PACKAGE_NAME_SUFFIX;
38 import static com.android.adservices.service.profiling.RbATraceProvider.FeatureNames.CONSENT_MANAGER;
39 import static com.android.adservices.service.profiling.TracingNames.CLASS_NAME_CONSENT_MANAGER;
40 import static com.android.adservices.service.profiling.TracingNames.METHOD_NAME_CONSTRUCTOR;
41 import static com.android.adservices.service.profiling.TracingNames.METHOD_NAME_CREATE_AND_INIT_DATASTORE;
42 import static com.android.adservices.service.profiling.TracingNames.METHOD_NAME_GET_AD_SERVICES_MANAGER;
43 import static com.android.adservices.service.profiling.TracingNames.METHOD_NAME_GET_CONSENT;
44 import static com.android.adservices.service.profiling.TracingNames.METHOD_NAME_MIGRATION_ENROLLMENT_DATA;
45 import static com.android.adservices.service.profiling.TracingNames.METHOD_NAME_MIGRATION_FROM_APP_SEARCH;
46 import static com.android.adservices.service.profiling.TracingNames.METHOD_NAME_MIGRATION_FROM_PPAPI;
47 import static com.android.adservices.service.profiling.TracingNames.METHOD_NAME_SET_CONSENT;
48 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__APP_SEARCH_DATA_MIGRATION_FAILURE;
49 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__DATASTORE_EXCEPTION_WHILE_RECORDING_DEFAULT_CONSENT;
50 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__DATASTORE_EXCEPTION_WHILE_RECORDING_MANUAL_CONSENT_INTERACTION;
51 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__DATASTORE_EXCEPTION_WHILE_RECORDING_NOTIFICATION;
52 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ERROR_WHILE_GET_CONSENT;
53 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__FLEDGE_CONSENT_MANAGER_INVALID_CONSENT_SOURCE_OF_TRUTH;
54 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__FLEDGE_CONSENT_MANAGER_PPAPI_AND_SYSTEM_SERVER_FLEDGE_CONSENT_CHECK_FAILED;
55 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__FLEDGE_CONSENT_MANAGER_PPAPI_ONLY_FLEDGE_CONSENT_CHECK_FAILED;
56 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__PRIVACY_SANDBOX_SAVE_FAILURE;
57 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__SHARED_PREF_RESET_FAILURE;
58 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__SHARED_PREF_UPDATE_FAILURE;
59 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__FLEDGE;
60 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__UX;
61 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_MEASUREMENT_WIPEOUT;
62 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_SETTINGS_USAGE_REPORTED__REGION__EU;
63 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_SETTINGS_USAGE_REPORTED__REGION__ROW;
64 import static com.android.adservices.service.ui.ux.collection.PrivacySandboxUxCollection.GA_UX;
65 import static com.android.adservices.service.ui.ux.collection.PrivacySandboxUxCollection.U18_UX;
66 import static com.android.adservices.service.ui.ux.collection.PrivacySandboxUxCollection.UNSUPPORTED_UX;
67 
68 import android.adservices.common.AdServicesModuleUserChoice;
69 import android.adservices.common.AdServicesModuleUserChoice.ModuleUserChoiceCode;
70 import android.adservices.common.Module.ModuleCode;
71 import android.annotation.IntDef;
72 import android.annotation.Nullable;
73 import android.annotation.SuppressLint;
74 import android.app.adservices.AdServicesManager;
75 import android.app.adservices.consent.ConsentParcel;
76 import android.app.job.JobScheduler;
77 import android.content.Context;
78 import android.content.SharedPreferences;
79 import android.os.Build;
80 import android.os.SystemClock;
81 import android.util.SparseIntArray;
82 
83 import androidx.annotation.RequiresApi;
84 
85 import com.android.adservices.LogUtil;
86 import com.android.adservices.concurrency.AdServicesExecutors;
87 import com.android.adservices.data.adselection.AppInstallDao;
88 import com.android.adservices.data.adselection.FrequencyCapDao;
89 import com.android.adservices.data.adselection.SharedStorageDatabase;
90 import com.android.adservices.data.common.LegacyAtomicFileDatastoreFactory;
91 import com.android.adservices.data.consent.AppConsentDao;
92 import com.android.adservices.data.customaudience.CustomAudienceDao;
93 import com.android.adservices.data.customaudience.CustomAudienceDatabase;
94 import com.android.adservices.data.enrollment.EnrollmentDao;
95 import com.android.adservices.data.signals.EncodedPayloadDao;
96 import com.android.adservices.data.signals.ProtectedSignalsDao;
97 import com.android.adservices.data.signals.ProtectedSignalsDatabase;
98 import com.android.adservices.data.topics.Topic;
99 import com.android.adservices.data.topics.TopicsTables;
100 import com.android.adservices.errorlogging.AdServicesErrorLoggerImpl;
101 import com.android.adservices.errorlogging.ErrorLogUtil;
102 import com.android.adservices.service.DebugFlags;
103 import com.android.adservices.service.Flags;
104 import com.android.adservices.service.Flags.ConsentSourceOfTruth;
105 import com.android.adservices.service.FlagsFactory;
106 import com.android.adservices.service.appsearch.AppSearchConsentManager;
107 import com.android.adservices.service.common.BackgroundJobsManager;
108 import com.android.adservices.service.common.UserProfileIdManager;
109 import com.android.adservices.service.common.feature.PrivacySandboxFeatureType;
110 import com.android.adservices.service.consent.ConsentConstants.EndUserUx;
111 import com.android.adservices.service.measurement.MeasurementImpl;
112 import com.android.adservices.service.measurement.WipeoutStatus;
113 import com.android.adservices.service.profiling.RbATraceProvider;
114 import com.android.adservices.service.stats.AdServicesLoggerImpl;
115 import com.android.adservices.service.stats.ConsentMigrationStats;
116 import com.android.adservices.service.stats.MeasurementWipeoutStats;
117 import com.android.adservices.service.stats.StatsdAdServicesLogger;
118 import com.android.adservices.service.stats.UiStatsLogger;
119 import com.android.adservices.service.topics.TopicsWorker;
120 import com.android.adservices.service.ui.data.UxStatesDao;
121 import com.android.adservices.service.ui.enrollment.collection.PrivacySandboxEnrollmentChannelCollection;
122 import com.android.adservices.service.ui.util.EnrollmentData;
123 import com.android.adservices.service.ui.ux.collection.PrivacySandboxUxCollection;
124 import com.android.adservices.shared.common.ApplicationContextSingleton;
125 import com.android.adservices.shared.errorlogging.AdServicesErrorLogger;
126 import com.android.adservices.shared.storage.AtomicFileDatastore;
127 import com.android.internal.annotations.VisibleForTesting;
128 import com.android.internal.util.Preconditions;
129 import com.android.modules.utils.build.SdkLevel;
130 
131 import com.google.common.base.Supplier;
132 import com.google.common.collect.ImmutableList;
133 
134 import java.io.IOException;
135 import java.io.PrintWriter;
136 import java.lang.annotation.Retention;
137 import java.lang.annotation.RetentionPolicy;
138 import java.util.ArrayList;
139 import java.util.Collections;
140 import java.util.List;
141 import java.util.Objects;
142 import java.util.concurrent.locks.ReadWriteLock;
143 import java.util.concurrent.locks.ReentrantReadWriteLock;
144 import java.util.stream.Collectors;
145 import java.util.stream.Stream;
146 
147 /**
148  * Manager to handle user's consent.
149  *
150  * <p>For Beta the consent is given for all {@link AdServicesApiType} or for none.
151  *
152  * <p>Currently there are three types of source of truth to store consent data,
153  *
154  * <ul>
155  *   <li>SYSTEM_SERVER_ONLY: Write and read consent from system server only.
156  *   <li>PPAPI_ONLY: Write and read consent from PPAPI only.
157  *   <li>PPAPI_AND_SYSTEM_SERVER: Write consent to both PPAPI and system server. Read consent from
158  *       system server only.
159  * </ul>
160  *
161  * IMPORTANT: Until ConsentManagerV2 is launched, keep in sync with ConsentManagerV2
162  */
163 // TODO(b/259791134): Add a CTS/UI test to test the Consent Migration
164 // TODO(b/279042385): move UI logs to UI.
165 @RequiresApi(Build.VERSION_CODES.S)
166 public final class ConsentManager {
167 
168     // Used on dump() / log only
169     private static int sDataMigrationDurationMs;
170     private static int sInstantiationDurationMs;
171 
172     private static volatile ConsentManager sConsentManager;
173 
174     @IntDef(value = {NO_MANUAL_INTERACTIONS_RECORDED, UNKNOWN, MANUAL_INTERACTIONS_RECORDED})
175     @Retention(RetentionPolicy.SOURCE)
176     public @interface UserManualInteraction {}
177 
178     public static final int NO_MANUAL_INTERACTIONS_RECORDED = -1;
179     public static final int UNKNOWN = 0;
180     public static final int MANUAL_INTERACTIONS_RECORDED = 1;
181 
182     private final Flags mFlags;
183     private final DebugFlags mDebugFlags;
184     private final Supplier<TopicsWorker> mTopicsWorkerSupplier;
185     private final AtomicFileDatastore mDatastore;
186     private final Supplier<AppConsentDao> mAppConsentDaoSupplier;
187     private final Supplier<EnrollmentDao> mEnrollmentDaoSupplier;
188     private final Supplier<MeasurementImpl> mMeasurementSupplier;
189     private final CustomAudienceDao mCustomAudienceDao;
190     private final AppInstallDao mAppInstallDao;
191     private final ProtectedSignalsDao mProtectedSignalsDao;
192     private final FrequencyCapDao mFrequencyCapDao;
193     private final EncodedPayloadDao mEncodedPayloadDao;
194     private final AdServicesManager mAdServicesManager;
195     private final @ConsentSourceOfTruth int mConsentSourceOfTruth;
196     private final AppSearchConsentManager mAppSearchConsentManager;
197     private final UserProfileIdManager mUserProfileIdManager;
198     private final UxStatesDao mUxStatesDao;
199 
200     private static final Object LOCK = new Object();
201     private final ReadWriteLock mReadWriteLock = new ReentrantReadWriteLock();
202 
ConsentManager( Supplier<TopicsWorker> topicsWorkerSupplier, Supplier<AppConsentDao> appConsentDaoSupplier, Supplier<EnrollmentDao> enrollmentDaoSupplier, Supplier<MeasurementImpl> measurementSupplier, CustomAudienceDao customAudienceDao, AppInstallDao appInstallDao, ProtectedSignalsDao protectedSignalsDao, FrequencyCapDao frequencyCapDao, EncodedPayloadDao encodedPayloadDao, AdServicesManager adServicesManager, AtomicFileDatastore atomicFileDatastore, AppSearchConsentManager appSearchConsentManager, UserProfileIdManager userProfileIdManager, UxStatesDao uxStatesDao, Flags flags, DebugFlags debugFlags, @ConsentSourceOfTruth int consentSourceOfTruth, boolean enableAppsearchConsentData)203     ConsentManager(
204             Supplier<TopicsWorker> topicsWorkerSupplier,
205             Supplier<AppConsentDao> appConsentDaoSupplier,
206             Supplier<EnrollmentDao> enrollmentDaoSupplier,
207             Supplier<MeasurementImpl> measurementSupplier,
208             CustomAudienceDao customAudienceDao,
209             AppInstallDao appInstallDao,
210             ProtectedSignalsDao protectedSignalsDao,
211             FrequencyCapDao frequencyCapDao,
212             EncodedPayloadDao encodedPayloadDao,
213             AdServicesManager adServicesManager,
214             AtomicFileDatastore atomicFileDatastore,
215             AppSearchConsentManager appSearchConsentManager,
216             UserProfileIdManager userProfileIdManager,
217             UxStatesDao uxStatesDao,
218             Flags flags,
219             DebugFlags debugFlags,
220             @ConsentSourceOfTruth int consentSourceOfTruth,
221             boolean enableAppsearchConsentData) {
222         mTopicsWorkerSupplier =
223                 Objects.requireNonNull(topicsWorkerSupplier, "topicsWorker cannot be null");
224         mAppConsentDaoSupplier =
225                 Objects.requireNonNull(appConsentDaoSupplier, "appConsentDao cannot be null");
226         mMeasurementSupplier =
227                 Objects.requireNonNull(measurementSupplier, "measurementImpl cannot be null");
228         mCustomAudienceDao =
229                 Objects.requireNonNull(customAudienceDao, "customAudienceDao cannot be null");
230         mAppInstallDao = Objects.requireNonNull(appInstallDao, "appInstallDao cannot be null");
231         mProtectedSignalsDao =
232                 Objects.requireNonNull(protectedSignalsDao, "protectedSignalsDao cannot be null");
233         mFrequencyCapDao =
234                 Objects.requireNonNull(frequencyCapDao, "frequencyCapDao cannot be null");
235         mEncodedPayloadDao =
236                 Objects.requireNonNull(encodedPayloadDao, "encodedPayloadDao cannot be null");
237         mDatastore =
238                 Objects.requireNonNull(atomicFileDatastore, "atomicFileDatastore cannot be null");
239         mUserProfileIdManager =
240                 Objects.requireNonNull(userProfileIdManager, "userProfileIdManager cannot be null");
241 
242         if (consentSourceOfTruth == Flags.SYSTEM_SERVER_ONLY
243                 || consentSourceOfTruth == Flags.PPAPI_AND_SYSTEM_SERVER) {
244             Objects.requireNonNull(adServicesManager, "adServicesManager cannot be null");
245         }
246 
247         if (enableAppsearchConsentData) {
248             Objects.requireNonNull(
249                     appSearchConsentManager, "appSearchConsentManager cannot be null");
250         }
251 
252         mAdServicesManager = adServicesManager;
253         mEnrollmentDaoSupplier = enrollmentDaoSupplier;
254         mUxStatesDao = uxStatesDao;
255         mAppSearchConsentManager = appSearchConsentManager;
256         mFlags = flags;
257         mDebugFlags = debugFlags;
258         mConsentSourceOfTruth = consentSourceOfTruth;
259     }
260 
261     /**
262      * Gets an instance of {@link ConsentManager} to be used.
263      *
264      * <p>If no instance has been initialized yet, a new one will be created. Otherwise, the
265      * existing instance will be returned.
266      */
getInstance()267     public static ConsentManager getInstance() {
268         Context context = ApplicationContextSingleton.get();
269 
270         Flags flags = FlagsFactory.getFlags();
271         RbATraceProvider.beginSection(
272                 CONSENT_MANAGER, CLASS_NAME_CONSENT_MANAGER, METHOD_NAME_CONSTRUCTOR, flags);
273         if (sConsentManager == null) {
274             synchronized (LOCK) {
275                 if (sConsentManager == null) {
276                     long startedTime = SystemClock.uptimeMillis();
277                     // Execute one-time consent migration if needed.
278                     LogUtil.d("start consent manager initialization");
279                     int consentSourceOfTruth = flags.getConsentSourceOfTruth();
280                     AtomicFileDatastore datastore =
281                             createAndInitializeDataStore(
282                                     context, AdServicesErrorLoggerImpl.getInstance());
283 
284                     RbATraceProvider.beginSection(
285                             CONSENT_MANAGER,
286                             CLASS_NAME_CONSENT_MANAGER,
287                             METHOD_NAME_GET_AD_SERVICES_MANAGER,
288                             flags);
289                     AdServicesManager adServicesManager = AdServicesManager.getInstance(context);
290                     RbATraceProvider.endSection(flags);
291 
292                     Supplier<AppConsentDao> appConsentDaoSupplier =
293                             AppConsentDao.getSingletonSupplier();
294 
295                     // It is possible that the old value of the flag lingers after OTA until the
296                     // first PH sync. In that case, we should not use the stale value, but use the
297                     // default instead. The next PH sync will restore the T+ value.
298                     if (SdkLevel.isAtLeastT() && consentSourceOfTruth == Flags.APPSEARCH_ONLY) {
299                         consentSourceOfTruth = Flags.DEFAULT_CONSENT_SOURCE_OF_TRUTH;
300                     }
301                     AppSearchConsentManager appSearchConsentManager = null;
302                     StatsdAdServicesLogger statsdAdServicesLogger =
303                             StatsdAdServicesLogger.getInstance();
304                     // Flag enable_appsearch_consent_data is true on S- and T+ only when we want to
305                     // use AppSearch to write to or read from.
306                     boolean enableAppsearchConsentData = flags.getEnableAppsearchConsentData();
307                     if (enableAppsearchConsentData) {
308                         appSearchConsentManager = AppSearchConsentManager.getInstance();
309                         handleConsentMigrationFromAppSearchIfNeeded(
310                                 context,
311                                 datastore,
312                                 appConsentDaoSupplier.get(),
313                                 appSearchConsentManager,
314                                 adServicesManager,
315                                 statsdAdServicesLogger);
316                     }
317 
318                     // Attempt to migrate consent data from PPAPI to System server if needed.
319                     handleConsentMigrationIfNeeded(
320                             context,
321                             datastore,
322                             adServicesManager,
323                             statsdAdServicesLogger,
324                             consentSourceOfTruth);
325                     long postDataMigrationTime = SystemClock.uptimeMillis();
326                     sDataMigrationDurationMs = (int) (postDataMigrationTime - startedTime);
327                     sConsentManager =
328                             new ConsentManager(
329                                     TopicsWorker.getSingletonSupplier(),
330                                     appConsentDaoSupplier,
331                                     EnrollmentDao.getSingletonSupplier(),
332                                     MeasurementImpl.getSingletonSupplier(),
333                                     CustomAudienceDatabase.getInstance().customAudienceDao(),
334                                     SharedStorageDatabase.getInstance().appInstallDao(),
335                                     ProtectedSignalsDatabase.getInstance().protectedSignalsDao(),
336                                     SharedStorageDatabase.getInstance().frequencyCapDao(),
337                                     ProtectedSignalsDatabase.getInstance().getEncodedPayloadDao(),
338                                     adServicesManager,
339                                     datastore,
340                                     appSearchConsentManager,
341                                     UserProfileIdManager.getInstance(),
342                                     // TODO(b/260601944): Remove Flag Instance.
343                                     UxStatesDao.getInstance(),
344                                     flags,
345                                     DebugFlags.getInstance(),
346                                     consentSourceOfTruth,
347                                     enableAppsearchConsentData);
348 
349                     boolean businessLogicMigrationEnabled =
350                             flags.getAdServicesConsentBusinessLogicMigrationEnabled();
351                     if (businessLogicMigrationEnabled) {
352                         RbATraceProvider.beginSection(
353                                 CONSENT_MANAGER,
354                                 CLASS_NAME_CONSENT_MANAGER,
355                                 METHOD_NAME_MIGRATION_ENROLLMENT_DATA,
356                                 flags);
357                         // Attempt to migrate old enrollment data to new format
358                         handleEnrollmentDataMigrationIfNeeded(sConsentManager);
359                         RbATraceProvider.endSection(flags);
360                     }
361 
362                     sInstantiationDurationMs =
363                             (int) (SystemClock.uptimeMillis() - postDataMigrationTime);
364                     LogUtil.d(
365                             "finished consent manager initialization: data migration in %dms,"
366                                     + " instantiation in %dms",
367                             sDataMigrationDurationMs, sInstantiationDurationMs);
368                 }
369             }
370         }
371         RbATraceProvider.endSection(flags);
372 
373         return sConsentManager;
374     }
375 
376     /**
377      * Enables all PP API services. It gives consent to Topics, Fledge and Measurements services.
378      *
379      * <p>To write consent to PPAPI if consent source of truth is PPAPI_ONLY or dual sources. To
380      * write to system server consent if source of truth is system server or dual sources.
381      */
enable(Context context)382     public void enable(Context context) {
383         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
384             ConsentManagerV2.getInstance().enable(context);
385             return;
386         }
387         Objects.requireNonNull(context, "context cannot be null");
388 
389         // Check current value, if it is already enabled, skip this enable process. so that the Api
390         // won't be reset. Only add this logic to "enable" not "disable", since if it already
391         // disabled, there is no harm to reset the api again.
392         if (mFlags.getConsentManagerLazyEnableMode() && getConsentFromSourceOfTruth()) {
393             LogUtil.d("CONSENT_KEY already enable. Skipping enable process.");
394             return;
395         }
396         UiStatsLogger.logOptInSelected();
397 
398         BackgroundJobsManager.scheduleAllBackgroundJobs(context);
399 
400         try {
401             // reset all state data which should be removed
402             resetTopicsAndBlockedTopics();
403             resetAppsAndBlockedApps();
404             resetMeasurement();
405             resetUserProfileId();
406             mUserProfileIdManager.getOrCreateId();
407         } catch (IOException e) {
408             throw new RuntimeException(ConsentConstants.ERROR_MESSAGE_WHILE_SET_CONTENT, e);
409         }
410 
411         setConsentToSourceOfTruth(/* isGiven */ true);
412     }
413 
414     /**
415      * Disables all PP API services. It revokes consent to Topics, Fledge and Measurements services.
416      *
417      * <p>To write consent to PPAPI if consent source of truth is PPAPI_ONLY or dual sources. To
418      * write to system server consent if source of truth is system server or dual sources.
419      */
disable(Context context)420     public void disable(Context context) {
421         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
422             ConsentManagerV2.getInstance().disable(context);
423             return;
424         }
425         Objects.requireNonNull(context, "context cannot be null");
426 
427         UiStatsLogger.logOptOutSelected();
428         // Disable all the APIs
429         try {
430             // reset all data
431             resetTopicsAndBlockedTopics();
432             resetAppsAndBlockedApps();
433             resetMeasurement();
434             resetEnrollment();
435             resetUserProfileId();
436 
437             BackgroundJobsManager.unscheduleAllBackgroundJobs(
438                     context.getSystemService(JobScheduler.class));
439         } catch (IOException e) {
440             throw new RuntimeException(ConsentConstants.ERROR_MESSAGE_WHILE_SET_CONTENT, e);
441         }
442 
443         setConsentToSourceOfTruth(/* isGiven */ false);
444     }
445 
446     /**
447      * Enables the {@code apiType} PP API service. It gives consent to an API which is provided in
448      * the parameter.
449      *
450      * <p>To write consent to PPAPI if consent source of truth is PPAPI_ONLY or dual sources. To
451      * write to system server consent if source of truth is system server or dual sources.
452      *
453      * @param context Context of the application.
454      * @param apiType Type of the API (Topics, Fledge, Measurement) which should be enabled.
455      */
enable(Context context, AdServicesApiType apiType)456     public void enable(Context context, AdServicesApiType apiType) {
457         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
458             ConsentManagerV2.getInstance().enable(context, apiType);
459             return;
460         }
461         Objects.requireNonNull(context, "context cannot be null");
462         // Check current value, if it is already enabled, skip this enable process. so that the Api
463         // won't be reset.
464         if (mFlags.getConsentManagerLazyEnableMode()
465                 && getPerApiConsentFromSourceOfTruth(apiType)) {
466             LogUtil.d(
467                     "ApiType: is %s already enable. Skipping enable process.",
468                     apiType.toPpApiDatastoreKey());
469             return;
470         }
471 
472         UiStatsLogger.logOptInSelected(apiType);
473 
474         BackgroundJobsManager.scheduleJobsPerApi(context, apiType);
475 
476         try {
477             // reset all state data which should be removed
478             resetByApi(apiType);
479 
480             if (AdServicesApiType.FLEDGE == apiType) {
481                 mUserProfileIdManager.getOrCreateId();
482             }
483         } catch (IOException e) {
484             throw new RuntimeException(ConsentConstants.ERROR_MESSAGE_WHILE_SET_CONTENT, e);
485         }
486 
487         setPerApiConsentToSourceOfTruth(/* isGiven */ true, apiType);
488     }
489 
490     /**
491      * Disables {@code apiType} PP API service. It revokes consent to an API which is provided in
492      * the parameter.
493      *
494      * <p>To write consent to PPAPI if consent source of truth is PPAPI_ONLY or dual sources. To
495      * write to system server consent if source of truth is system server or dual sources.
496      */
disable(Context context, AdServicesApiType apiType)497     public void disable(Context context, AdServicesApiType apiType) {
498         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
499             ConsentManagerV2.getInstance().disable(context, apiType);
500             return;
501         }
502         Objects.requireNonNull(context, "context cannot be null");
503 
504         UiStatsLogger.logOptOutSelected(apiType);
505 
506         try {
507             resetByApi(apiType);
508             BackgroundJobsManager.unscheduleJobsPerApi(
509                     context.getSystemService(JobScheduler.class), apiType);
510         } catch (IOException e) {
511             throw new RuntimeException(ConsentConstants.ERROR_MESSAGE_WHILE_SET_CONTENT, e);
512         }
513 
514         setPerApiConsentToSourceOfTruth(/* isGiven */ false, apiType);
515 
516         if (areAllApisDisabled()) {
517             BackgroundJobsManager.unscheduleAllBackgroundJobs(
518                     context.getSystemService(JobScheduler.class));
519         }
520     }
521 
522     /** Returns true if all APIs are disabled. */
areAllApisDisabled()523     public boolean areAllApisDisabled() {
524         return !getConsent(AdServicesApiType.TOPICS).isGiven()
525                 && !getConsent(AdServicesApiType.MEASUREMENTS).isGiven()
526                 && !getConsent(AdServicesApiType.FLEDGE).isGiven();
527     }
528 
529     /**
530      * Retrieves the consent for all PP API services.
531      *
532      * <p>To read from PPAPI consent if source of truth is PPAPI. To read from system server consent
533      * if source of truth is system server or dual sources.
534      *
535      * @return AdServicesApiConsent the consent
536      */
getConsent()537     public AdServicesApiConsent getConsent() {
538         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
539             return ConsentManagerV2.getInstance().getConsent();
540         }
541         if (mDebugFlags.getConsentManagerDebugMode()) {
542             return AdServicesApiConsent.GIVEN;
543         }
544 
545         return executeGettersByConsentSourceOfTruth(
546                 /* defaultReturn= */ AdServicesApiConsent.REVOKED,
547                 () ->
548                         AdServicesApiConsent.getConsent(
549                                 mDatastore.getBoolean(ConsentConstants.CONSENT_KEY)),
550                 () ->
551                         AdServicesApiConsent.getConsent(
552                                 mAdServicesManager.getConsent(ConsentParcel.ALL_API).isIsGiven()),
553                 () ->
554                         AdServicesApiConsent.getConsent(
555                                 mAppSearchConsentManager.getConsent(
556                                         ConsentConstants.CONSENT_KEY_FOR_ALL)),
557                 (e) ->
558                         ErrorLogUtil.e(
559                                 e,
560                                 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ERROR_WHILE_GET_CONSENT,
561                                 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__UX));
562     }
563 
564     /**
565      * Retrieves the consent per API.
566      *
567      * @param apiType apiType for which the consent should be provided
568      * @return {@link AdServicesApiConsent} providing information whether the consent was given or
569      *     revoked.
570      */
getConsent(AdServicesApiType apiType)571     public AdServicesApiConsent getConsent(AdServicesApiType apiType) {
572         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
573             return ConsentManagerV2.getInstance().getConsent(apiType);
574         }
575         if (mDebugFlags.getConsentManagerDebugMode()) {
576             return AdServicesApiConsent.GIVEN;
577         }
578         if (mFlags.getAdServicesConsentBusinessLogicMigrationEnabled()) {
579             return getUserChoice(apiType);
580         }
581 
582         return executeGettersByConsentSourceOfTruth(
583                 /* defaultReturn= */ AdServicesApiConsent.REVOKED,
584                 () ->
585                         AdServicesApiConsent.getConsent(
586                                 mDatastore.getBoolean(apiType.toPpApiDatastoreKey())),
587                 () ->
588                         AdServicesApiConsent.getConsent(
589                                 mAdServicesManager
590                                         .getConsent(apiType.toConsentApiType())
591                                         .isIsGiven()),
592                 () ->
593                         AdServicesApiConsent.getConsent(
594                                 mAppSearchConsentManager.getConsent(apiType.toPpApiDatastoreKey())),
595                 (e) ->
596                         ErrorLogUtil.e(
597                                 e,
598                                 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ERROR_WHILE_GET_CONSENT,
599                                 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__UX));
600     }
601 
602     /**
603      * Retrieves the nullable consent per API.
604      *
605      * @param apiType apiType for which the consent should be provided
606      * @return Boolean indicating consent is given (true) or revoked (false). null if unknown.
607      */
608     @SuppressLint("MissingPermission")
getConsentNullable(AdServicesApiType apiType)609     public Boolean getConsentNullable(AdServicesApiType apiType) {
610         return executeGettersByConsentSourceOfTruth(
611                 /* defaultReturn= */ null,
612                 () -> mDatastore.getBoolean(apiType.toPpApiDatastoreKey()),
613                 () -> {
614                     ConsentParcel parcel =
615                             mAdServicesManager.getConsent(apiType.toConsentApiType());
616                     if (parcel == null) {
617                         return null;
618                     }
619                     return parcel.isIsGiven();
620                 },
621                 () -> mAppSearchConsentManager.getConsentNullable(apiType.toPpApiDatastoreKey()),
622                 (e) ->
623                         ErrorLogUtil.e(
624                                 e,
625                                 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ERROR_WHILE_GET_CONSENT,
626                                 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__UX));
627     }
628 
629     /**
630      * Proxy call to {@link TopicsWorker} to get {@link ImmutableList} of {@link Topic}s which could
631      * be returned to the {@link TopicsWorker} clients.
632      *
633      * @return {@link ImmutableList} of {@link Topic}s.
634      */
getKnownTopicsWithConsent()635     public ImmutableList<Topic> getKnownTopicsWithConsent() {
636         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
637             return ConsentManagerV2.getInstance().getKnownTopicsWithConsent();
638         }
639         return mTopicsWorkerSupplier.get().getKnownTopicsWithConsent();
640     }
641 
642     /**
643      * Proxy call to {@link TopicsWorker} to get {@link ImmutableList} of {@link Topic}s which were
644      * blocked by the user.
645      *
646      * @return {@link ImmutableList} of blocked {@link Topic}s.
647      */
getTopicsWithRevokedConsent()648     public ImmutableList<Topic> getTopicsWithRevokedConsent() {
649         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
650             return ConsentManagerV2.getInstance().getTopicsWithRevokedConsent();
651         }
652         return mTopicsWorkerSupplier.get().getTopicsWithRevokedConsent();
653     }
654 
655     /**
656      * Proxy call to {@link TopicsWorker} to revoke consent for provided {@link Topic} (block
657      * topic).
658      *
659      * @param topic {@link Topic} to block.
660      */
revokeConsentForTopic(Topic topic)661     public void revokeConsentForTopic(Topic topic) {
662         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
663             ConsentManagerV2.getInstance().revokeConsentForTopic(topic);
664             return;
665         }
666         mTopicsWorkerSupplier.get().revokeConsentForTopic(topic);
667     }
668 
669     /**
670      * Proxy call to {@link TopicsWorker} to restore consent for provided {@link Topic} (unblock the
671      * topic).
672      *
673      * @param topic {@link Topic} to restore consent for.
674      */
restoreConsentForTopic(Topic topic)675     public void restoreConsentForTopic(Topic topic) {
676         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
677             ConsentManagerV2.getInstance().restoreConsentForTopic(topic);
678             return;
679         }
680         mTopicsWorkerSupplier.get().restoreConsentForTopic(topic);
681     }
682 
683     /** Wipes out all the data gathered by Topics API but blocked topics. */
resetTopics()684     public void resetTopics() {
685         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
686             ConsentManagerV2.getInstance().resetTopics();
687             return;
688         }
689         ArrayList<String> tablesToBlock = new ArrayList<>();
690         tablesToBlock.add(TopicsTables.BlockedTopicsContract.TABLE);
691         mTopicsWorkerSupplier.get().clearAllTopicsData(tablesToBlock);
692     }
693 
694     /** Wipes out all the data gathered by Topics API. */
resetTopicsAndBlockedTopics()695     public void resetTopicsAndBlockedTopics() {
696         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
697             ConsentManagerV2.getInstance().resetTopicsAndBlockedTopics();
698             return;
699         }
700         mTopicsWorkerSupplier.get().clearAllTopicsData(new ArrayList<>());
701     }
702 
703     /**
704      * @return an {@link ImmutableList} of all known apps in the database that have not had user
705      *     consent revoked
706      */
getKnownAppsWithConsent()707     public ImmutableList<App> getKnownAppsWithConsent() {
708         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
709             return ConsentManagerV2.getInstance().getKnownAppsWithConsent();
710         }
711         return executeGettersByConsentSourceOfTruth(
712                 /* defaultReturn= */ ImmutableList.of(),
713                 () ->
714                         ImmutableList.copyOf(
715                                 mAppConsentDaoSupplier.get().getKnownAppsWithConsent().stream()
716                                         .map(App::create)
717                                         .collect(Collectors.toList())),
718                 () ->
719                         ImmutableList.copyOf(
720                                 mAdServicesManager
721                                         .getKnownAppsWithConsent(
722                                                 new ArrayList<>(
723                                                         mAppConsentDaoSupplier
724                                                                 .get()
725                                                                 .getInstalledPackages()))
726                                         .stream()
727                                         .map(App::create)
728                                         .collect(Collectors.toList())),
729                 () -> mAppSearchConsentManager.getKnownAppsWithConsent(),
730                 /* errorLogger= */ null);
731     }
732 
733     /**
734      * @return an {@link ImmutableList} of all known apps in the database that have had user consent
735      *     revoked
736      */
getAppsWithRevokedConsent()737     public ImmutableList<App> getAppsWithRevokedConsent() {
738         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
739             return ConsentManagerV2.getInstance().getAppsWithRevokedConsent();
740         }
741         return executeGettersByConsentSourceOfTruth(
742                 /* defaultReturn= */ ImmutableList.of(),
743                 () ->
744                         ImmutableList.copyOf(
745                                 mAppConsentDaoSupplier.get().getAppsWithRevokedConsent().stream()
746                                         .map(App::create)
747                                         .collect(Collectors.toList())),
748                 () ->
749                         ImmutableList.copyOf(
750                                 mAdServicesManager
751                                         .getAppsWithRevokedConsent(
752                                                 new ArrayList<>(
753                                                         mAppConsentDaoSupplier
754                                                                 .get()
755                                                                 .getInstalledPackages()))
756                                         .stream()
757                                         .map(App::create)
758                                         .collect(Collectors.toList())),
759                 () -> mAppSearchConsentManager.getAppsWithRevokedConsent(),
760                 /* errorLogger= */ null);
761     }
762 
763     /**
764      * Proxy call to {@link AppConsentDao} to revoke consent for provided {@link App}.
765      *
766      * <p>Also clears all app data related to the provided {@link App}.
767      *
768      * @param app {@link App} to block.
769      * @throws IOException if the operation fails
770      */
revokeConsentForApp(App app)771     public void revokeConsentForApp(App app) throws IOException {
772         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
773             ConsentManagerV2.getInstance().revokeConsentForApp(app);
774             return;
775         }
776         executeSettersByConsentSourceOfTruth(
777                 () -> mAppConsentDaoSupplier.get().setConsentForApp(app.getPackageName(), true),
778                 () ->
779                         mAdServicesManager.setConsentForApp(
780                                 app.getPackageName(),
781                                 mAppConsentDaoSupplier
782                                         .get()
783                                         .getUidForInstalledPackageName(app.getPackageName()),
784                                 true),
785                 () -> mAppSearchConsentManager.revokeConsentForApp(app),
786                 /* errorLogger= */ null);
787 
788         asyncExecute(
789                 () ->
790                         mCustomAudienceDao.deleteCustomAudienceDataByOwner(
791                                 app.getPackageName(),
792                                 mFlags.getFledgeScheduleCustomAudienceUpdateEnabled()));
793         if (mFlags.getFledgeFrequencyCapFilteringEnabled()) {
794             asyncExecute(
795                     () -> mFrequencyCapDao.deleteHistogramDataBySourceApp(app.getPackageName()));
796         }
797         if (mFlags.getFledgeAppInstallFilteringEnabled()) {
798             asyncExecute(() -> mAppInstallDao.deleteByPackageName(app.getPackageName()));
799         }
800         if (mFlags.getProtectedSignalsCleanupEnabled()) {
801             asyncExecute(
802                     () ->
803                             mProtectedSignalsDao.deleteSignalsByPackage(
804                                     Collections.singletonList(app.getPackageName())));
805         }
806     }
807 
808     /**
809      * Proxy call to {@link AppConsentDao} to restore consent for provided {@link App}.
810      *
811      * @param app {@link App} to restore consent for.
812      * @throws IOException if the operation fails
813      */
restoreConsentForApp(App app)814     public void restoreConsentForApp(App app) throws IOException {
815         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
816             ConsentManagerV2.getInstance().restoreConsentForApp(app);
817             return;
818         }
819         executeSettersByConsentSourceOfTruth(
820                 () -> mAppConsentDaoSupplier.get().setConsentForApp(app.getPackageName(), false),
821                 () ->
822                         mAdServicesManager.setConsentForApp(
823                                 app.getPackageName(),
824                                 mAppConsentDaoSupplier
825                                         .get()
826                                         .getUidForInstalledPackageName(app.getPackageName()),
827                                 false),
828                 () -> mAppSearchConsentManager.restoreConsentForApp(app),
829                 /* errorLogger= */ null);
830     }
831 
832     /**
833      * Deletes all app consent data and all app data gathered or generated by the Privacy Sandbox.
834      *
835      * <p>This should be called when the Privacy Sandbox has been disabled.
836      *
837      * @throws IOException if the operation fails
838      */
resetAppsAndBlockedApps()839     public void resetAppsAndBlockedApps() throws IOException {
840         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
841             ConsentManagerV2.getInstance().resetAppsAndBlockedApps();
842             return;
843         }
844         executeSettersByConsentSourceOfTruth(
845                 () -> mAppConsentDaoSupplier.get().clearAllConsentData(),
846                 () -> mAdServicesManager.clearAllAppConsentData(),
847                 () -> mAppSearchConsentManager.clearAllAppConsentData(),
848                 /* errorLogger= */ null);
849 
850         asyncExecute(
851                 () ->
852                         mCustomAudienceDao.deleteAllCustomAudienceData(
853                                 mFlags.getFledgeScheduleCustomAudienceUpdateEnabled()));
854         if (mFlags.getFledgeFrequencyCapFilteringEnabled()) {
855             asyncExecute(mFrequencyCapDao::deleteAllHistogramData);
856         }
857         if (mFlags.getFledgeAppInstallFilteringEnabled()) {
858             asyncExecute(mAppInstallDao::deleteAllAppInstallData);
859         }
860         if (mFlags.getProtectedSignalsCleanupEnabled()) {
861             asyncExecute(mProtectedSignalsDao::deleteAllSignals);
862             asyncExecute(mEncodedPayloadDao::deleteAllEncodedPayloads);
863         }
864     }
865 
866     /**
867      * Deletes the list of known allowed apps as well as all app data from the Privacy Sandbox.
868      *
869      * <p>The list of blocked apps is not reset.
870      *
871      * @throws IOException if the operation fails
872      */
resetApps()873     public void resetApps() throws IOException {
874         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
875             ConsentManagerV2.getInstance().resetApps();
876             return;
877         }
878         executeSettersByConsentSourceOfTruth(
879                 () -> mAppConsentDaoSupplier.get().clearKnownAppsWithConsent(),
880                 () -> mAdServicesManager.clearKnownAppsWithConsent(),
881                 () -> mAppSearchConsentManager.clearKnownAppsWithConsent(),
882                 /* errorLogger= */ null);
883 
884         asyncExecute(
885                 () ->
886                         mCustomAudienceDao.deleteAllCustomAudienceData(
887                                 mFlags.getFledgeScheduleCustomAudienceUpdateEnabled()));
888         if (mFlags.getFledgeFrequencyCapFilteringEnabled()) {
889             asyncExecute(mFrequencyCapDao::deleteAllHistogramData);
890         }
891         if (mFlags.getFledgeAppInstallFilteringEnabled()) {
892             asyncExecute(mAppInstallDao::deleteAllAppInstallData);
893         }
894         if (mFlags.getProtectedSignalsCleanupEnabled()) {
895             asyncExecute(mProtectedSignalsDao::deleteAllSignals);
896             asyncExecute(mEncodedPayloadDao::deleteAllEncodedPayloads);
897         }
898     }
899 
900     /**
901      * Checks whether a single given installed application (identified by its package name) has had
902      * user consent to use the FLEDGE APIs revoked.
903      *
904      * <p>This method also checks whether a user has opted out of the FLEDGE Privacy Sandbox
905      * initiative.
906      *
907      * @param packageName String package name that uniquely identifies an installed application to
908      *     check
909      * @return {@code true} if either the FLEDGE Privacy Sandbox initiative has been opted out or if
910      *     the user has revoked consent for the given application to use the FLEDGE APIs
911      * @throws IllegalArgumentException if the package name is invalid or not found as an installed
912      *     application
913      */
isFledgeConsentRevokedForApp(String packageName)914     public boolean isFledgeConsentRevokedForApp(String packageName)
915             throws IllegalArgumentException {
916         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
917             return ConsentManagerV2.getInstance().isFledgeConsentRevokedForApp(packageName);
918         }
919         AdServicesApiConsent consent = getConsent(AdServicesApiType.FLEDGE);
920 
921         if (!consent.isGiven()) {
922             return true;
923         }
924 
925         synchronized (LOCK) {
926             switch (mConsentSourceOfTruth) {
927                 case Flags.PPAPI_ONLY:
928                     try {
929                         return mAppConsentDaoSupplier.get().isConsentRevokedForApp(packageName);
930                     } catch (IOException exception) {
931                         LogUtil.e(exception, "FLEDGE consent check failed due to IOException");
932                         ErrorLogUtil.e(
933                                 exception,
934                                 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__FLEDGE_CONSENT_MANAGER_PPAPI_ONLY_FLEDGE_CONSENT_CHECK_FAILED,
935                                 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__FLEDGE);
936                     }
937                     return true;
938                 case Flags.SYSTEM_SERVER_ONLY:
939                     // Intentional fallthrough
940                 case Flags.PPAPI_AND_SYSTEM_SERVER:
941                     return mAdServicesManager.isConsentRevokedForApp(
942                             packageName,
943                             mAppConsentDaoSupplier
944                                     .get()
945                                     .getUidForInstalledPackageName(packageName));
946                 case Flags.APPSEARCH_ONLY:
947                     if (mFlags.getEnableAppsearchConsentData()) {
948                         return mAppSearchConsentManager.isFledgeConsentRevokedForApp(packageName);
949                     }
950                 default:
951                     LogUtil.e(ConsentConstants.ERROR_MESSAGE_INVALID_CONSENT_SOURCE_OF_TRUTH);
952                     ErrorLogUtil.e(
953                             AD_SERVICES_ERROR_REPORTED__ERROR_CODE__FLEDGE_CONSENT_MANAGER_INVALID_CONSENT_SOURCE_OF_TRUTH,
954                             AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__FLEDGE);
955                     return true;
956             }
957         }
958     }
959 
960     /**
961      * Persists the use of a FLEDGE API by a single given installed application (identified by its
962      * package name) if the app has not already had its consent revoked.
963      *
964      * <p>This method also checks whether a user has opted out of the FLEDGE Privacy Sandbox
965      * initiative.
966      *
967      * <p>This is only meant to be called by the FLEDGE APIs.
968      *
969      * @param packageName String package name that uniquely identifies an installed application that
970      *     has used a FLEDGE API
971      * @return {@code true} if user consent has been revoked for the application or API, {@code
972      *     false} otherwise
973      * @throws IllegalArgumentException if the package name is invalid or not found as an installed
974      *     application
975      */
isFledgeConsentRevokedForAppAfterSettingFledgeUse(String packageName)976     public boolean isFledgeConsentRevokedForAppAfterSettingFledgeUse(String packageName)
977             throws IllegalArgumentException {
978         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
979             return ConsentManagerV2.getInstance()
980                     .isFledgeConsentRevokedForAppAfterSettingFledgeUse(packageName);
981         }
982         AdServicesApiConsent consent = getConsent(AdServicesApiType.FLEDGE);
983 
984         if (!consent.isGiven()) {
985             return true;
986         }
987 
988         synchronized (LOCK) {
989             switch (mConsentSourceOfTruth) {
990                 case Flags.PPAPI_ONLY:
991                     try {
992                         return mAppConsentDaoSupplier
993                                 .get()
994                                 .setConsentForAppIfNew(packageName, false);
995                     } catch (IOException exception) {
996                         LogUtil.e(exception, "FLEDGE consent check failed due to IOException");
997                         ErrorLogUtil.e(
998                                 exception,
999                                 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__FLEDGE_CONSENT_MANAGER_PPAPI_ONLY_FLEDGE_CONSENT_CHECK_FAILED,
1000                                 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__FLEDGE);
1001                         return true;
1002                     }
1003                 case Flags.SYSTEM_SERVER_ONLY:
1004                     return mAdServicesManager.setConsentForAppIfNew(
1005                             packageName,
1006                             mAppConsentDaoSupplier.get().getUidForInstalledPackageName(packageName),
1007                             false);
1008                 case Flags.PPAPI_AND_SYSTEM_SERVER:
1009                     try {
1010                         mAppConsentDaoSupplier.get().setConsentForAppIfNew(packageName, false);
1011                     } catch (IOException exception) {
1012                         LogUtil.e(exception, "FLEDGE consent check failed due to IOException");
1013                         ErrorLogUtil.e(
1014                                 exception,
1015                                 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__FLEDGE_CONSENT_MANAGER_PPAPI_AND_SYSTEM_SERVER_FLEDGE_CONSENT_CHECK_FAILED,
1016                                 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__FLEDGE);
1017                         return true;
1018                     }
1019                     return mAdServicesManager.setConsentForAppIfNew(
1020                             packageName,
1021                             mAppConsentDaoSupplier.get().getUidForInstalledPackageName(packageName),
1022                             false);
1023                 case Flags.APPSEARCH_ONLY:
1024                     if (mFlags.getEnableAppsearchConsentData()) {
1025                         return mAppSearchConsentManager
1026                                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(packageName);
1027                     }
1028                 default:
1029                     LogUtil.e(ConsentConstants.ERROR_MESSAGE_INVALID_CONSENT_SOURCE_OF_TRUTH);
1030                     ErrorLogUtil.e(
1031                             AD_SERVICES_ERROR_REPORTED__ERROR_CODE__FLEDGE_CONSENT_MANAGER_INVALID_CONSENT_SOURCE_OF_TRUTH,
1032                             AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__FLEDGE);
1033                     return true;
1034             }
1035         }
1036     }
1037 
1038     /**
1039      * Clear consent data after an app was uninstalled.
1040      *
1041      * @param packageName the package name that had been uninstalled.
1042      * @param packageUid the package uid that had been uninstalled.
1043      */
clearConsentForUninstalledApp(String packageName, int packageUid)1044     public void clearConsentForUninstalledApp(String packageName, int packageUid) {
1045         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1046             ConsentManagerV2.getInstance().clearConsentForUninstalledApp(packageName, packageUid);
1047             return;
1048         }
1049         executeSettersByConsentSourceOfTruth(
1050                 () ->
1051                         mAppConsentDaoSupplier
1052                                 .get()
1053                                 .clearConsentForUninstalledApp(packageName, packageUid),
1054                 () -> mAdServicesManager.clearConsentForUninstalledApp(packageName, packageUid),
1055                 () -> mAppSearchConsentManager.clearConsentForUninstalledApp(packageName),
1056                 /* errorLogger= */ null);
1057     }
1058 
1059     /**
1060      * Clear consent data after an app was uninstalled, but the package Uid is unavailable. This
1061      * could happen because the INTERACT_ACROSS_USERS_FULL permission is not available on Android
1062      * versions prior to T.
1063      *
1064      * <p><strong>This method should only be used for R/S back-compat scenarios.</strong>
1065      *
1066      * @param packageName the package name that had been uninstalled.
1067      */
clearConsentForUninstalledApp(String packageName)1068     public void clearConsentForUninstalledApp(String packageName) {
1069         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1070             ConsentManagerV2.getInstance().clearConsentForUninstalledApp(packageName);
1071             return;
1072         }
1073         Objects.requireNonNull(packageName);
1074         Preconditions.checkStringNotEmpty(packageName, "Package name should not be empty");
1075 
1076         executeSettersByConsentSourceOfTruth(
1077                 () -> mAppConsentDaoSupplier.get().clearConsentForUninstalledApp(packageName),
1078                 /* systemServiceSetter= */ null,
1079                 () -> mAppSearchConsentManager.clearConsentForUninstalledApp(packageName),
1080                 /* errorLogger= */ null);
1081     }
1082 
1083     /** Wipes out all the data gathered by Measurement API. */
resetMeasurement()1084     public void resetMeasurement() {
1085         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1086             ConsentManagerV2.getInstance().resetMeasurement();
1087             return;
1088         }
1089         mMeasurementSupplier.get().deleteAllMeasurementData(List.of());
1090         // Log wipeout event triggered by consent flip to delete data of package
1091         WipeoutStatus wipeoutStatus = new WipeoutStatus();
1092         wipeoutStatus.setWipeoutType(WipeoutStatus.WipeoutType.CONSENT_FLIP);
1093         logWipeoutStats(wipeoutStatus);
1094     }
1095 
1096     /** Wipes out all the Enrollment data */
1097     @VisibleForTesting
resetEnrollment()1098     void resetEnrollment() {
1099         mEnrollmentDaoSupplier.get().deleteAll();
1100     }
1101 
1102     /**
1103      * Saves information to the storage that notification was displayed for the first time to the
1104      * user.
1105      */
recordNotificationDisplayed(boolean wasNotificationDisplayed)1106     public void recordNotificationDisplayed(boolean wasNotificationDisplayed) {
1107         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1108             ConsentManagerV2.getInstance().recordNotificationDisplayed(wasNotificationDisplayed);
1109             return;
1110         }
1111         executeSettersByConsentSourceOfTruth(
1112                 () ->
1113                         mDatastore.putBoolean(
1114                                 ConsentConstants.NOTIFICATION_DISPLAYED_ONCE,
1115                                 wasNotificationDisplayed),
1116                 () -> mAdServicesManager.recordNotificationDisplayed(wasNotificationDisplayed),
1117                 () ->
1118                         mAppSearchConsentManager.recordNotificationDisplayed(
1119                                 wasNotificationDisplayed),
1120                 /* errorLogger= */ null);
1121     }
1122 
1123     /**
1124      * Retrieves if notification has been displayed.
1125      *
1126      * @return true if Consent Notification was displayed, otherwise false.
1127      */
wasNotificationDisplayed()1128     public Boolean wasNotificationDisplayed() {
1129         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1130             return ConsentManagerV2.getInstance().wasNotificationDisplayed();
1131         }
1132         return executeGettersByConsentSourceOfTruth(
1133                 /* defaultReturn= */ true,
1134                 () -> mDatastore.getBoolean(ConsentConstants.NOTIFICATION_DISPLAYED_ONCE),
1135                 () -> mAdServicesManager.wasNotificationDisplayed(),
1136                 () -> mAppSearchConsentManager.wasNotificationDisplayed(),
1137                 (e) ->
1138                         ErrorLogUtil.e(
1139                                 e,
1140                                 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__DATASTORE_EXCEPTION_WHILE_RECORDING_NOTIFICATION,
1141                                 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__UX));
1142     }
1143 
1144     /**
1145      * Saves information to the storage that GA UX notification was displayed for the first time to
1146      * the user.
1147      */
recordGaUxNotificationDisplayed(boolean wasGaUxDisplayed)1148     public void recordGaUxNotificationDisplayed(boolean wasGaUxDisplayed) {
1149         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1150             ConsentManagerV2.getInstance().recordGaUxNotificationDisplayed(wasGaUxDisplayed);
1151             return;
1152         }
1153         executeSettersByConsentSourceOfTruth(
1154                 () ->
1155                         mDatastore.putBoolean(
1156                                 ConsentConstants.GA_UX_NOTIFICATION_DISPLAYED_ONCE,
1157                                 wasGaUxDisplayed),
1158                 () -> mAdServicesManager.recordGaUxNotificationDisplayed(wasGaUxDisplayed),
1159                 () -> mAppSearchConsentManager.recordGaUxNotificationDisplayed(wasGaUxDisplayed),
1160                 /* errorLogger= */ null);
1161     }
1162 
1163     /**
1164      * Retrieves if GA UX notification has been displayed.
1165      *
1166      * @return true if GA UX Consent Notification was displayed, otherwise false.
1167      */
wasGaUxNotificationDisplayed()1168     public Boolean wasGaUxNotificationDisplayed() {
1169         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1170             return ConsentManagerV2.getInstance().wasGaUxNotificationDisplayed();
1171         }
1172         return executeGettersByConsentSourceOfTruth(
1173                 /* defaultReturn= */ true,
1174                 () -> mDatastore.getBoolean(ConsentConstants.GA_UX_NOTIFICATION_DISPLAYED_ONCE),
1175                 () -> mAdServicesManager.wasGaUxNotificationDisplayed(),
1176                 () -> mAppSearchConsentManager.wasGaUxNotificationDisplayed(),
1177                 /* errorLogger= */ null);
1178     }
1179 
1180     /**
1181      * Saves information to the storage that PAS UX notification was displayed for the first time to
1182      * the user.
1183      */
recordPasNotificationDisplayed(boolean wasPasDisplayed)1184     public void recordPasNotificationDisplayed(boolean wasPasDisplayed) {
1185         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1186             ConsentManagerV2.getInstance().recordPasNotificationDisplayed(wasPasDisplayed);
1187             return;
1188         }
1189         executeSettersByConsentSourceOfTruth(
1190                 () ->
1191                         mDatastore.putBoolean(
1192                                 ConsentConstants.PAS_NOTIFICATION_DISPLAYED_ONCE, wasPasDisplayed),
1193                 () -> mAdServicesManager.recordPasNotificationDisplayed(wasPasDisplayed),
1194                 () -> {
1195                     // APPSEARCH_ONLY is only set on S which has not implemented PAS updates.
1196                     throw new IllegalStateException(
1197                             getAppSearchExceptionMessage(
1198                                     /* illegalAction */ "store if PAS notification was displayed"));
1199                 },
1200                 /* errorLogger= */ null);
1201     }
1202 
1203     /**
1204      * Retrieves if PAS notification has been displayed.
1205      *
1206      * @return true if PAS Consent Notification was displayed, otherwise false.
1207      */
wasPasNotificationDisplayed()1208     public Boolean wasPasNotificationDisplayed() {
1209         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1210             return ConsentManagerV2.getInstance().wasPasNotificationDisplayed();
1211         }
1212         return executeGettersByConsentSourceOfTruth(
1213                 /* defaultReturn= */ true,
1214                 () -> mDatastore.getBoolean(ConsentConstants.PAS_NOTIFICATION_DISPLAYED_ONCE),
1215                 () -> mAdServicesManager.wasPasNotificationDisplayed(),
1216                 () -> false, // PAS update not supported on S yet
1217                 /* errorLogger= */ null);
1218     }
1219 
1220     /**
1221      * Retrieves the PP API default consent.
1222      *
1223      * @return true if the default consent is true, false otherwise.
1224      */
getDefaultConsent()1225     public Boolean getDefaultConsent() {
1226         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1227             return ConsentManagerV2.getInstance().getDefaultConsent();
1228         }
1229         return executeGettersByConsentSourceOfTruth(
1230                 /* defaultReturn= */ false,
1231                 () -> mDatastore.getBoolean(ConsentConstants.DEFAULT_CONSENT),
1232                 () -> mAdServicesManager.getDefaultConsent(),
1233                 () -> mAppSearchConsentManager.getConsent(ConsentConstants.DEFAULT_CONSENT),
1234                 (e) ->
1235                         ErrorLogUtil.e(
1236                                 e,
1237                                 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__DATASTORE_EXCEPTION_WHILE_RECORDING_DEFAULT_CONSENT,
1238                                 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__UX));
1239     }
1240 
1241     /**
1242      * Retrieves the topics default consent.
1243      *
1244      * @return true if the topics default consent is true, false otherwise.
1245      */
getTopicsDefaultConsent()1246     public Boolean getTopicsDefaultConsent() {
1247         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1248             return ConsentManagerV2.getInstance().getTopicsDefaultConsent();
1249         }
1250         return executeGettersByConsentSourceOfTruth(
1251                 /* defaultReturn= */ false,
1252                 () -> mDatastore.getBoolean(ConsentConstants.TOPICS_DEFAULT_CONSENT),
1253                 () -> mAdServicesManager.getTopicsDefaultConsent(),
1254                 () -> mAppSearchConsentManager.getConsent(ConsentConstants.TOPICS_DEFAULT_CONSENT),
1255                 /* errorLogger= */ null);
1256     }
1257 
1258     /**
1259      * Retrieves the FLEDGE default consent.
1260      *
1261      * @return true if the FLEDGE default consent is true, false otherwise.
1262      */
getFledgeDefaultConsent()1263     public Boolean getFledgeDefaultConsent() {
1264         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1265             return ConsentManagerV2.getInstance().getFledgeDefaultConsent();
1266         }
1267         return executeGettersByConsentSourceOfTruth(
1268                 /* defaultReturn= */ false,
1269                 () -> mDatastore.getBoolean(ConsentConstants.FLEDGE_DEFAULT_CONSENT),
1270                 () -> mAdServicesManager.getFledgeDefaultConsent(),
1271                 () -> mAppSearchConsentManager.getConsent(ConsentConstants.FLEDGE_DEFAULT_CONSENT),
1272                 /* errorLogger= */ null);
1273     }
1274 
1275     /**
1276      * Retrieves the measurement default consent.
1277      *
1278      * @return true if the measurement default consent is true, false otherwise.
1279      */
getMeasurementDefaultConsent()1280     public Boolean getMeasurementDefaultConsent() {
1281         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1282             return ConsentManagerV2.getInstance().getMeasurementDefaultConsent();
1283         }
1284         return executeGettersByConsentSourceOfTruth(
1285                 /* defaultReturn= */ false,
1286                 () -> mDatastore.getBoolean(ConsentConstants.MEASUREMENT_DEFAULT_CONSENT),
1287                 () -> mAdServicesManager.getMeasurementDefaultConsent(),
1288                 () ->
1289                         mAppSearchConsentManager.getConsent(
1290                                 ConsentConstants.MEASUREMENT_DEFAULT_CONSENT),
1291                 /* errorLogger= */ null);
1292     }
1293 
1294     /**
1295      * Retrieves the default AdId state.
1296      *
1297      * @return true if the AdId is enabled by default, false otherwise.
1298      */
getDefaultAdIdState()1299     public Boolean getDefaultAdIdState() {
1300         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1301             return ConsentManagerV2.getInstance().getDefaultAdIdState();
1302         }
1303         return executeGettersByConsentSourceOfTruth(
1304                 /* defaultReturn= */ false,
1305                 () -> mDatastore.getBoolean(ConsentConstants.DEFAULT_AD_ID_STATE),
1306                 () -> mAdServicesManager.getDefaultAdIdState(),
1307                 () -> mAppSearchConsentManager.getConsent(ConsentConstants.DEFAULT_AD_ID_STATE),
1308                 /* errorLogger= */ null);
1309     }
1310 
1311     /** Saves the default consent bit to data stores based on source of truth. */
recordDefaultConsent(boolean defaultConsent)1312     public void recordDefaultConsent(boolean defaultConsent) {
1313         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1314             ConsentManagerV2.getInstance().recordDefaultConsent(defaultConsent);
1315             return;
1316         }
1317         executeSettersByConsentSourceOfTruth(
1318                 () -> mDatastore.putBoolean(ConsentConstants.DEFAULT_CONSENT, defaultConsent),
1319                 () -> mAdServicesManager.recordDefaultConsent(defaultConsent),
1320                 () ->
1321                         mAppSearchConsentManager.setConsent(
1322                                 ConsentConstants.DEFAULT_CONSENT, defaultConsent),
1323                 (e) ->
1324                         ErrorLogUtil.e(
1325                                 e,
1326                                 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__DATASTORE_EXCEPTION_WHILE_RECORDING_DEFAULT_CONSENT,
1327                                 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__UX));
1328     }
1329 
1330     /** Saves the topics default consent bit to data stores based on source of truth. */
recordTopicsDefaultConsent(boolean defaultConsent)1331     public void recordTopicsDefaultConsent(boolean defaultConsent) {
1332         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1333             ConsentManagerV2.getInstance().recordTopicsDefaultConsent(defaultConsent);
1334             return;
1335         }
1336         executeSettersByConsentSourceOfTruth(
1337                 () ->
1338                         mDatastore.putBoolean(
1339                                 ConsentConstants.TOPICS_DEFAULT_CONSENT, defaultConsent),
1340                 () -> mAdServicesManager.recordTopicsDefaultConsent(defaultConsent),
1341                 () ->
1342                         mAppSearchConsentManager.setConsent(
1343                                 ConsentConstants.TOPICS_DEFAULT_CONSENT, defaultConsent),
1344                 /* errorLogger= */ null);
1345     }
1346 
1347     /** Saves the FLEDGE default consent bit to data stores based on source of truth. */
recordFledgeDefaultConsent(boolean defaultConsent)1348     public void recordFledgeDefaultConsent(boolean defaultConsent) {
1349         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1350             ConsentManagerV2.getInstance().recordFledgeDefaultConsent(defaultConsent);
1351             return;
1352         }
1353         executeSettersByConsentSourceOfTruth(
1354                 () ->
1355                         mDatastore.putBoolean(
1356                                 ConsentConstants.FLEDGE_DEFAULT_CONSENT, defaultConsent),
1357                 () -> mAdServicesManager.recordFledgeDefaultConsent(defaultConsent),
1358                 () ->
1359                         mAppSearchConsentManager.setConsent(
1360                                 ConsentConstants.FLEDGE_DEFAULT_CONSENT, defaultConsent),
1361                 /* errorLogger= */ null);
1362     }
1363 
1364     /** Saves the measurement default consent bit to data stores based on source of truth. */
recordMeasurementDefaultConsent(boolean defaultConsent)1365     public void recordMeasurementDefaultConsent(boolean defaultConsent) {
1366         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1367             ConsentManagerV2.getInstance().recordMeasurementDefaultConsent(defaultConsent);
1368             return;
1369         }
1370         executeSettersByConsentSourceOfTruth(
1371                 () ->
1372                         mDatastore.putBoolean(
1373                                 ConsentConstants.MEASUREMENT_DEFAULT_CONSENT, defaultConsent),
1374                 () -> mAdServicesManager.recordMeasurementDefaultConsent(defaultConsent),
1375                 () ->
1376                         mAppSearchConsentManager.setConsent(
1377                                 ConsentConstants.MEASUREMENT_DEFAULT_CONSENT, defaultConsent),
1378                 /* errorLogger= */ null);
1379     }
1380 
1381     /** Saves the default AdId state bit to data stores based on source of truth. */
recordDefaultAdIdState(boolean defaultAdIdState)1382     public void recordDefaultAdIdState(boolean defaultAdIdState) {
1383         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1384             ConsentManagerV2.getInstance().recordDefaultAdIdState(defaultAdIdState);
1385             return;
1386         }
1387         executeSettersByConsentSourceOfTruth(
1388                 () -> mDatastore.putBoolean(ConsentConstants.DEFAULT_AD_ID_STATE, defaultAdIdState),
1389                 () -> mAdServicesManager.recordDefaultAdIdState(defaultAdIdState),
1390                 () ->
1391                         mAppSearchConsentManager.setConsent(
1392                                 ConsentConstants.DEFAULT_AD_ID_STATE, defaultAdIdState),
1393                 /* errorLogger= */ null);
1394     }
1395 
1396     @VisibleForTesting
setPrivacySandboxFeatureTypeInApp(PrivacySandboxFeatureType currentFeatureType)1397     void setPrivacySandboxFeatureTypeInApp(PrivacySandboxFeatureType currentFeatureType)
1398             throws IOException {
1399         if (FlagsFactory.getFlags().getEnableAtomicFileDatastoreBatchUpdateApi()) {
1400             mDatastore.update(
1401                     updateOperation -> {
1402                         for (PrivacySandboxFeatureType featureType :
1403                                 PrivacySandboxFeatureType.values()) {
1404                             if (featureType.name().equals(currentFeatureType.name())) {
1405                                 updateOperation.putBoolean(featureType.name(), true);
1406                             } else {
1407                                 updateOperation.putBoolean(featureType.name(), false);
1408                             }
1409                         }
1410                     });
1411             return;
1412         }
1413 
1414         for (PrivacySandboxFeatureType featureType : PrivacySandboxFeatureType.values()) {
1415             if (featureType.name().equals(currentFeatureType.name())) {
1416                 mDatastore.putBoolean(featureType.name(), true);
1417             } else {
1418                 mDatastore.putBoolean(featureType.name(), false);
1419             }
1420         }
1421     }
1422 
1423     /** Set the current privacy sandbox feature. */
setCurrentPrivacySandboxFeature(PrivacySandboxFeatureType currentFeatureType)1424     public void setCurrentPrivacySandboxFeature(PrivacySandboxFeatureType currentFeatureType) {
1425         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1426             ConsentManagerV2.getInstance().setCurrentPrivacySandboxFeature(currentFeatureType);
1427             return;
1428         }
1429         executeSettersByConsentSourceOfTruth(
1430                 () -> setPrivacySandboxFeatureTypeInApp(currentFeatureType),
1431                 () -> mAdServicesManager.setCurrentPrivacySandboxFeature(currentFeatureType.name()),
1432                 () -> mAppSearchConsentManager.setCurrentPrivacySandboxFeature(currentFeatureType),
1433                 (e) ->
1434                         ErrorLogUtil.e(
1435                                 e,
1436                                 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__PRIVACY_SANDBOX_SAVE_FAILURE,
1437                                 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__UX));
1438     }
1439 
1440     /** Saves information to the storage that user interacted with consent manually. */
recordUserManualInteractionWithConsent(@serManualInteraction int interaction)1441     public void recordUserManualInteractionWithConsent(@UserManualInteraction int interaction) {
1442         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1443             ConsentManagerV2.getInstance().recordUserManualInteractionWithConsent(interaction);
1444             return;
1445         }
1446         executeSettersByConsentSourceOfTruth(
1447                 () -> storeUserManualInteractionToPpApi(interaction, mDatastore),
1448                 () -> mAdServicesManager.recordUserManualInteractionWithConsent(interaction),
1449                 () -> mAppSearchConsentManager.recordUserManualInteractionWithConsent(interaction),
1450                 (e) ->
1451                         ErrorLogUtil.e(
1452                                 e,
1453                                 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__DATASTORE_EXCEPTION_WHILE_RECORDING_MANUAL_CONSENT_INTERACTION,
1454                                 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__UX));
1455     }
1456 
getPrivacySandboxFeatureFromApp()1457     private PrivacySandboxFeatureType getPrivacySandboxFeatureFromApp() throws IOException {
1458         for (PrivacySandboxFeatureType featureType : PrivacySandboxFeatureType.values()) {
1459             if (Boolean.TRUE.equals(mDatastore.getBoolean(featureType.name()))) {
1460                 return featureType;
1461             }
1462         }
1463         return PrivacySandboxFeatureType.PRIVACY_SANDBOX_UNSUPPORTED;
1464     }
1465 
getPrivacySandboxFeatureFromSystemService()1466     private PrivacySandboxFeatureType getPrivacySandboxFeatureFromSystemService() {
1467         for (PrivacySandboxFeatureType featureType : PrivacySandboxFeatureType.values()) {
1468             if (mAdServicesManager.getCurrentPrivacySandboxFeature().equals(featureType.name())) {
1469                 return featureType;
1470             }
1471         }
1472         return PrivacySandboxFeatureType.PRIVACY_SANDBOX_UNSUPPORTED;
1473     }
1474 
1475     /**
1476      * Get the current privacy sandbox feature.
1477      *
1478      * <p>To write to PPAPI if consent source of truth is PPAPI_ONLY or dual sources. To write to
1479      * system server if consent source of truth is SYSTEM_SERVER_ONLY or dual sources.
1480      */
getCurrentPrivacySandboxFeature()1481     public PrivacySandboxFeatureType getCurrentPrivacySandboxFeature() {
1482         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1483             return ConsentManagerV2.getInstance().getCurrentPrivacySandboxFeature();
1484         }
1485         return executeGettersByConsentSourceOfTruth(
1486                 /* defaultReturn= */ PrivacySandboxFeatureType.PRIVACY_SANDBOX_UNSUPPORTED,
1487                 this::getPrivacySandboxFeatureFromApp,
1488                 this::getPrivacySandboxFeatureFromSystemService,
1489                 () -> mAppSearchConsentManager.getCurrentPrivacySandboxFeature(),
1490                 (e) ->
1491                         ErrorLogUtil.e(
1492                                 e,
1493                                 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__PRIVACY_SANDBOX_SAVE_FAILURE,
1494                                 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__UX));
1495     }
1496 
storeUserManualInteractionToPpApi( @serManualInteraction int interaction, AtomicFileDatastore datastore)1497     private static void storeUserManualInteractionToPpApi(
1498             @UserManualInteraction int interaction, AtomicFileDatastore datastore)
1499             throws IOException {
1500         switch (interaction) {
1501             case NO_MANUAL_INTERACTIONS_RECORDED:
1502                 datastore.putBoolean(
1503                         ConsentConstants.MANUAL_INTERACTION_WITH_CONSENT_RECORDED, false);
1504                 break;
1505             case UNKNOWN:
1506                 datastore.remove(ConsentConstants.MANUAL_INTERACTION_WITH_CONSENT_RECORDED);
1507                 break;
1508             case MANUAL_INTERACTIONS_RECORDED:
1509                 datastore.putBoolean(
1510                         ConsentConstants.MANUAL_INTERACTION_WITH_CONSENT_RECORDED, true);
1511                 break;
1512             default:
1513                 throw new IllegalArgumentException(
1514                         String.format("InteractionId < %d > can not be handled.", interaction));
1515         }
1516     }
1517 
getUserManualInteractionWithConsentInternal()1518     private int getUserManualInteractionWithConsentInternal() {
1519         Boolean manualInteractionWithConsent =
1520                 mDatastore.getBoolean(ConsentConstants.MANUAL_INTERACTION_WITH_CONSENT_RECORDED);
1521         if (manualInteractionWithConsent == null) {
1522             return UNKNOWN;
1523         } else if (Boolean.TRUE.equals(manualInteractionWithConsent)) {
1524             return MANUAL_INTERACTIONS_RECORDED;
1525         } else {
1526             return NO_MANUAL_INTERACTIONS_RECORDED;
1527         }
1528     }
1529 
1530     /**
1531      * Returns information whether user interacted with consent manually.
1532      *
1533      * @return true if the user interacted with the consent manually, otherwise false.
1534      */
1535     @SuppressLint("WrongConstant")
getUserManualInteractionWithConsent()1536     public @UserManualInteraction int getUserManualInteractionWithConsent() {
1537         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
1538             return ConsentManagerV2.getInstance().getUserManualInteractionWithConsent();
1539         }
1540         return executeGettersByConsentSourceOfTruth(
1541                 /* defaultReturn= */ UNKNOWN,
1542                 this::getUserManualInteractionWithConsentInternal,
1543                 () -> mAdServicesManager.getUserManualInteractionWithConsent(),
1544                 () -> mAppSearchConsentManager.getUserManualInteractionWithConsent(),
1545                 (e) ->
1546                         ErrorLogUtil.e(
1547                                 e,
1548                                 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__DATASTORE_EXCEPTION_WHILE_RECORDING_MANUAL_CONSENT_INTERACTION,
1549                                 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__UX));
1550     }
1551 
1552     @VisibleForTesting
1553     // TODO(b/311183933): Remove passed in Context from static method.
1554     @SuppressWarnings("AvoidStaticContext")
createAndInitializeDataStore( Context context, AdServicesErrorLogger adServicesErrorLogger)1555     static AtomicFileDatastore createAndInitializeDataStore(
1556             Context context, AdServicesErrorLogger adServicesErrorLogger) {
1557         Flags flags = FlagsFactory.getFlags();
1558 
1559         RbATraceProvider.beginSection(
1560                 CONSENT_MANAGER,
1561                 CLASS_NAME_CONSENT_MANAGER,
1562                 METHOD_NAME_CREATE_AND_INIT_DATASTORE,
1563                 flags);
1564         @SuppressWarnings("deprecation")
1565         AtomicFileDatastore atomicFileDatastore =
1566                 LegacyAtomicFileDatastoreFactory.createAtomicFileDatastore(
1567                         context,
1568                         ConsentConstants.STORAGE_XML_IDENTIFIER,
1569                         ConsentConstants.STORAGE_VERSION,
1570                         adServicesErrorLogger);
1571 
1572         try {
1573             atomicFileDatastore.initialize();
1574             // TODO(b/259607624): implement a method in the datastore which would support
1575             // this exact scenario - if the value is null, return default value provided
1576             // in the parameter (similar to SP apply etc.)
1577             if (flags.getEnableAtomicFileDatastoreBatchUpdateApi()) {
1578                 atomicFileDatastore.update(
1579                         updateOperation -> {
1580                             updateOperation.putBooleanIfNew(
1581                                     ConsentConstants.NOTIFICATION_DISPLAYED_ONCE, false);
1582                             updateOperation.putBooleanIfNew(
1583                                     ConsentConstants.GA_UX_NOTIFICATION_DISPLAYED_ONCE, false);
1584                             updateOperation.putBooleanIfNew(
1585                                     ConsentConstants.WAS_U18_NOTIFICATION_DISPLAYED, false);
1586                             updateOperation.putBooleanIfNew(
1587                                     ConsentConstants.PAS_NOTIFICATION_DISPLAYED_ONCE, false);
1588                             updateOperation.putBooleanIfNew(
1589                                     ConsentConstants.PAS_NOTIFICATION_OPENED, false);
1590                         });
1591                 return atomicFileDatastore;
1592             }
1593 
1594             if (atomicFileDatastore.getBoolean(ConsentConstants.NOTIFICATION_DISPLAYED_ONCE)
1595                     == null) {
1596                 atomicFileDatastore.putBoolean(ConsentConstants.NOTIFICATION_DISPLAYED_ONCE, false);
1597             }
1598             if (atomicFileDatastore.getBoolean(ConsentConstants.GA_UX_NOTIFICATION_DISPLAYED_ONCE)
1599                     == null) {
1600                 atomicFileDatastore.putBoolean(
1601                         ConsentConstants.GA_UX_NOTIFICATION_DISPLAYED_ONCE, false);
1602             }
1603             if (atomicFileDatastore.getBoolean(ConsentConstants.WAS_U18_NOTIFICATION_DISPLAYED)
1604                     == null) {
1605                 atomicFileDatastore.putBoolean(
1606                         ConsentConstants.WAS_U18_NOTIFICATION_DISPLAYED, false);
1607             }
1608             if (atomicFileDatastore.getBoolean(ConsentConstants.PAS_NOTIFICATION_DISPLAYED_ONCE)
1609                     == null) {
1610                 atomicFileDatastore.putBoolean(
1611                         ConsentConstants.PAS_NOTIFICATION_DISPLAYED_ONCE, false);
1612             }
1613             if (atomicFileDatastore.getBoolean(ConsentConstants.PAS_NOTIFICATION_OPENED) == null) {
1614                 atomicFileDatastore.putBoolean(ConsentConstants.PAS_NOTIFICATION_OPENED, false);
1615             }
1616         } catch (IOException | IllegalArgumentException | NullPointerException e) {
1617             throw new RuntimeException("Failed to initialize the File Datastore!", e);
1618         } finally {
1619             RbATraceProvider.endSection(flags);
1620         }
1621 
1622         return atomicFileDatastore;
1623     }
1624 
1625     // Handle different migration requests based on current consent source of Truth
1626     // PPAPI_ONLY: reset the shared preference to reset status of migrating consent from PPAPI to
1627     //             system server.
1628     // PPAPI_AND_SYSTEM_SERVER: migrate consent from PPAPI to system server.
1629     // SYSTEM_SERVER_ONLY: migrate consent from PPAPI to system server and clear PPAPI consent
1630     // TODO(b/311183933): Remove passed in Context from static method.
1631     @SuppressWarnings("AvoidStaticContext")
1632     @VisibleForTesting
handleConsentMigrationIfNeeded( Context context, AtomicFileDatastore datastore, AdServicesManager adServicesManager, StatsdAdServicesLogger statsdAdServicesLogger, @ConsentSourceOfTruth int consentSourceOfTruth)1633     static void handleConsentMigrationIfNeeded(
1634             Context context,
1635             AtomicFileDatastore datastore,
1636             AdServicesManager adServicesManager,
1637             StatsdAdServicesLogger statsdAdServicesLogger,
1638             @ConsentSourceOfTruth int consentSourceOfTruth) {
1639         Objects.requireNonNull(context, "context cannot be null");
1640         // On R/S, handleConsentMigrationIfNeeded should never be executed.
1641         // It is a T+ feature. On T+, this function should only execute if it's within the
1642         // AdServices APK and not ExtServices. So check if it's within ExtServices, and bail out if
1643         // that's the case on any platform.
1644         String packageName = context.getPackageName();
1645         if (packageName != null && packageName.endsWith(ADEXTSERVICES_PACKAGE_NAME_SUFFIX)) {
1646             LogUtil.d("Aborting attempt to migrate consent in ExtServices");
1647             return;
1648         }
1649         Objects.requireNonNull(datastore, "datastore cannot be null");
1650         if (consentSourceOfTruth == Flags.PPAPI_AND_SYSTEM_SERVER
1651                 || consentSourceOfTruth == Flags.SYSTEM_SERVER_ONLY) {
1652             Objects.requireNonNull(adServicesManager, "adServicesManager cannot be null");
1653         }
1654 
1655         switch (consentSourceOfTruth) {
1656             case Flags.PPAPI_ONLY:
1657                 // Technically we only need to reset the SHARED_PREFS_KEY_HAS_MIGRATED bit once.
1658                 // What we need is clearIfSet operation which is not available in SP. So here we
1659                 // always reset the bit since otherwise we need to read the SP to read the value and
1660                 // the clear the value.
1661                 // The only flow we would do are:
1662                 // Case 1: DUAL-> PPAPI if there is a bug in System Server
1663                 // Case 2: DUAL -> SYSTEM_SERVER_ONLY: if everything goes smoothly.
1664                 resetSharedPreference(context, ConsentConstants.SHARED_PREFS_KEY_HAS_MIGRATED);
1665                 break;
1666             case Flags.PPAPI_AND_SYSTEM_SERVER:
1667                 migratePpApiConsentToSystemService(
1668                         context, datastore, adServicesManager, statsdAdServicesLogger);
1669                 break;
1670             case Flags.SYSTEM_SERVER_ONLY:
1671                 migratePpApiConsentToSystemService(
1672                         context, datastore, adServicesManager, statsdAdServicesLogger);
1673                 clearPpApiConsent(context, datastore);
1674                 break;
1675                 // If this is a S device, the consent source of truth is always APPSEARCH_ONLY.
1676             case Flags.APPSEARCH_ONLY:
1677                 break;
1678             default:
1679                 break;
1680         }
1681     }
1682 
1683     @VisibleForTesting
setConsentToPpApi(boolean isGiven)1684     void setConsentToPpApi(boolean isGiven) throws IOException {
1685         mDatastore.putBoolean(ConsentConstants.CONSENT_KEY, isGiven);
1686     }
1687 
1688     @VisibleForTesting
setConsentPerApiToPpApi(AdServicesApiType apiType, boolean isGiven)1689     void setConsentPerApiToPpApi(AdServicesApiType apiType, boolean isGiven) throws IOException {
1690         mDatastore.putBoolean(apiType.toPpApiDatastoreKey(), isGiven);
1691     }
1692 
1693     @VisibleForTesting
getConsentFromPpApi()1694     boolean getConsentFromPpApi() {
1695         return mDatastore.getBoolean(ConsentConstants.CONSENT_KEY);
1696     }
1697 
1698     @VisibleForTesting
getConsentPerApiFromPpApi(AdServicesApiType apiType)1699     boolean getConsentPerApiFromPpApi(AdServicesApiType apiType) {
1700         return Boolean.TRUE.equals(mDatastore.getBoolean(apiType.toPpApiDatastoreKey()));
1701     }
1702 
1703     // Set the aggregated consent so that after the rollback of the module
1704     // and the flag which controls the consent flow everything works as expected.
1705     // The problematic edge case which is covered:
1706     // T1: AdServices is installed in pre-GA UX version and the consent is given
1707     // T2: AdServices got upgraded to GA UX binary and GA UX feature flag is enabled
1708     // T3: Consent for the Topics API got revoked
1709     // T4: AdServices got rolledback and the feature flags which controls consent flow
1710     // (SYSTEM_SERVER_ONLY and DUAL_WRITE) also got rolledback
1711     // T5: Restored consent should be revoked
1712     @VisibleForTesting
setAggregatedConsentToPpApi()1713     void setAggregatedConsentToPpApi() throws IOException {
1714         if (getUx() == U18_UX) {
1715             // The edge case does not apply to U18 UX.
1716             return;
1717         }
1718         if (getConsent(AdServicesApiType.TOPICS).isGiven()
1719                 && getConsent(AdServicesApiType.MEASUREMENTS).isGiven()
1720                 && getConsent(AdServicesApiType.FLEDGE).isGiven()) {
1721             setConsentToPpApi(true);
1722         } else {
1723             setConsentToPpApi(false);
1724         }
1725     }
1726 
1727     // Reset data for the specific AdServicesApiType
1728     @VisibleForTesting
resetByApi(AdServicesApiType apiType)1729     void resetByApi(AdServicesApiType apiType) throws IOException {
1730         switch (apiType) {
1731             case TOPICS:
1732                 resetTopicsAndBlockedTopics();
1733                 break;
1734             case FLEDGE:
1735                 resetAppsAndBlockedApps();
1736                 resetUserProfileId();
1737                 break;
1738             case MEASUREMENTS:
1739                 resetMeasurement();
1740                 break;
1741         }
1742     }
1743 
resetUserProfileId()1744     private void resetUserProfileId() {
1745         mUserProfileIdManager.deleteId();
1746     }
1747 
1748     @VisibleForTesting
setConsentToSystemServer(AdServicesManager adServicesManager, boolean isGiven)1749     static void setConsentToSystemServer(AdServicesManager adServicesManager, boolean isGiven) {
1750         Objects.requireNonNull(adServicesManager, "adServicesManager cannot be null");
1751 
1752         ConsentParcel consentParcel =
1753                 new ConsentParcel.Builder()
1754                         .setConsentApiType(ConsentParcel.ALL_API)
1755                         .setIsGiven(isGiven)
1756                         .build();
1757         adServicesManager.setConsent(consentParcel);
1758     }
1759 
setPerApiConsentToSystemServer( AdServicesManager adServicesManager, @ConsentParcel.ConsentApiType int consentApiType, boolean isGiven)1760     static void setPerApiConsentToSystemServer(
1761             AdServicesManager adServicesManager,
1762             @ConsentParcel.ConsentApiType int consentApiType,
1763             boolean isGiven) {
1764         Objects.requireNonNull(adServicesManager, "adServicesManager cannot be null");
1765 
1766         if (isGiven) {
1767             adServicesManager.setConsent(ConsentParcel.createGivenConsent(consentApiType));
1768         } else {
1769             adServicesManager.setConsent(ConsentParcel.createRevokedConsent(consentApiType));
1770         }
1771     }
1772 
1773     @VisibleForTesting
getPerApiConsentFromSystemServer( AdServicesManager adServicesManager, @ConsentParcel.ConsentApiType int consentApiType)1774     static boolean getPerApiConsentFromSystemServer(
1775             AdServicesManager adServicesManager, @ConsentParcel.ConsentApiType int consentApiType) {
1776         Objects.requireNonNull(adServicesManager, "adServicesManager cannot be null");
1777         return adServicesManager.getConsent(consentApiType).isIsGiven();
1778     }
1779 
1780     @VisibleForTesting
getConsentFromSystemServer(AdServicesManager adServicesManager)1781     static boolean getConsentFromSystemServer(AdServicesManager adServicesManager) {
1782         Objects.requireNonNull(adServicesManager, "adServicesManager cannot be null");
1783         return getPerApiConsentFromSystemServer(adServicesManager, ConsentParcel.ALL_API);
1784     }
1785 
1786     // Perform a one-time migration to migrate existing PPAPI Consent
1787     @VisibleForTesting
1788     @SuppressWarnings({
1789         "NewApi", // Suppress lint warning for context.getUser in R since this code is unused in R
1790         "AvoidStaticContext", // TODO(b/311183933): Remove passed in Context from static method.
1791     })
migratePpApiConsentToSystemService( Context context, AtomicFileDatastore datastore, AdServicesManager adServicesManager, StatsdAdServicesLogger statsdAdServicesLogger)1792     static void migratePpApiConsentToSystemService(
1793             Context context,
1794             AtomicFileDatastore datastore,
1795             AdServicesManager adServicesManager,
1796             StatsdAdServicesLogger statsdAdServicesLogger) {
1797         Flags flags = FlagsFactory.getFlags();
1798         RbATraceProvider.beginSection(
1799                 CONSENT_MANAGER,
1800                 CLASS_NAME_CONSENT_MANAGER,
1801                 METHOD_NAME_MIGRATION_FROM_PPAPI,
1802                 flags);
1803 
1804         Objects.requireNonNull(context, "context cannot be null");
1805         Objects.requireNonNull(datastore, "datastore cannot be null");
1806         Objects.requireNonNull(adServicesManager, "adServicesManager cannot be null");
1807 
1808         AppConsents appConsents = null;
1809         try {
1810             // Exit if migration has happened.
1811             SharedPreferences sharedPreferences = getPrefs(context);
1812             // If we migrated data to system server either from PPAPI or from AppSearch, do not
1813             // attempt another migration of data to system server.
1814             boolean shouldSkipMigration =
1815                     sharedPreferences.getBoolean(
1816                                     ConsentConstants.SHARED_PREFS_KEY_APPSEARCH_HAS_MIGRATED,
1817                                     /* default= */ false)
1818                             || sharedPreferences.getBoolean(
1819                                     ConsentConstants.SHARED_PREFS_KEY_HAS_MIGRATED,
1820                                     /* default= */ false)
1821                             || sharedPreferences.getBoolean(
1822                                     ConsentConstants
1823                                             .SHARED_PREFS_KEY_MIGRATED_FROM_ADEXTDATA_TO_SYSTEM_SERVER,
1824                                     /* defValue= */ false);
1825             if (shouldSkipMigration) {
1826                 LogUtil.v(
1827                         "Consent migration has happened to user %d, skip...",
1828                         context.getUser().getIdentifier());
1829                 return;
1830             }
1831             LogUtil.d("Started migrating Consent from PPAPI to System Service");
1832 
1833             Boolean consentKey =
1834                     Boolean.TRUE.equals(datastore.getBoolean(ConsentConstants.CONSENT_KEY));
1835 
1836             // Migrate Consent and Notification Displayed to System Service.
1837             // Set consent enabled only when value is TRUE. FALSE and null are regarded as disabled.
1838             setConsentToSystemServer(adServicesManager, Boolean.TRUE.equals(consentKey));
1839 
1840             // Set notification displayed only when value is TRUE. FALSE and null are regarded as
1841             // not displayed.
1842             if (Boolean.TRUE.equals(
1843                     datastore.getBoolean(ConsentConstants.NOTIFICATION_DISPLAYED_ONCE))) {
1844                 adServicesManager.recordNotificationDisplayed(true);
1845             }
1846 
1847             Boolean manualInteractionRecorded =
1848                     datastore.getBoolean(ConsentConstants.MANUAL_INTERACTION_WITH_CONSENT_RECORDED);
1849             if (manualInteractionRecorded != null) {
1850                 adServicesManager.recordUserManualInteractionWithConsent(
1851                         manualInteractionRecorded ? 1 : -1);
1852             }
1853 
1854             // Save migration has happened into shared preferences.
1855             SharedPreferences.Editor editor = sharedPreferences.edit();
1856             editor.putBoolean(ConsentConstants.SHARED_PREFS_KEY_HAS_MIGRATED, true);
1857             appConsents =
1858                     AppConsents.builder()
1859                             .setMsmtConsent(consentKey)
1860                             .setFledgeConsent(consentKey)
1861                             .setTopicsConsent(consentKey)
1862                             .build();
1863 
1864             if (editor.commit()) {
1865                 LogUtil.d("Finished migrating Consent from PPAPI to System Service");
1866                 statsdAdServicesLogger.logConsentMigrationStats(
1867                         getConsentManagerStatsForLogging(
1868                                 appConsents,
1869                                 ConsentMigrationStats.MigrationStatus
1870                                         .SUCCESS_WITH_SHARED_PREF_UPDATED,
1871                                 ConsentMigrationStats.MigrationType.PPAPI_TO_SYSTEM_SERVICE,
1872                                 context));
1873             } else {
1874                 LogUtil.e(
1875                         "Finished migrating Consent from PPAPI to System Service but shared"
1876                                 + " preference is not updated.");
1877                 ErrorLogUtil.e(
1878                         AD_SERVICES_ERROR_REPORTED__ERROR_CODE__SHARED_PREF_UPDATE_FAILURE,
1879                         AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__UX);
1880                 statsdAdServicesLogger.logConsentMigrationStats(
1881                         getConsentManagerStatsForLogging(
1882                                 appConsents,
1883                                 ConsentMigrationStats.MigrationStatus
1884                                         .SUCCESS_WITH_SHARED_PREF_NOT_UPDATED,
1885                                 ConsentMigrationStats.MigrationType.PPAPI_TO_SYSTEM_SERVICE,
1886                                 context));
1887             }
1888         } catch (Exception e) {
1889             LogUtil.e("PPAPI consent data migration failed: ", e);
1890             statsdAdServicesLogger.logConsentMigrationStats(
1891                     getConsentManagerStatsForLogging(
1892                             appConsents,
1893                             ConsentMigrationStats.MigrationStatus.FAILURE,
1894                             ConsentMigrationStats.MigrationType.PPAPI_TO_SYSTEM_SERVICE,
1895                             context));
1896         } finally {
1897             RbATraceProvider.endSection(flags);
1898         }
1899     }
1900 
1901     // Clear PPAPI Consent if fully migrated to use system server consent. This is because system
1902     // consent cannot be migrated back to PPAPI. This data clearing should only happen once.
1903     @VisibleForTesting
1904     // TODO(b/311183933): Remove passed in Context from static method.
1905     @SuppressWarnings("AvoidStaticContext")
clearPpApiConsent(Context context, AtomicFileDatastore datastore)1906     static void clearPpApiConsent(Context context, AtomicFileDatastore datastore) {
1907         // Exit if PPAPI consent has cleared.
1908         SharedPreferences sharedPreferences = getPrefs(context);
1909         if (sharedPreferences.getBoolean(
1910                 ConsentConstants.SHARED_PREFS_KEY_PPAPI_HAS_CLEARED, /* defValue */ false)) {
1911             return;
1912         }
1913 
1914         LogUtil.d("Started clearing Consent in PPAPI.");
1915 
1916         try {
1917             datastore.clear();
1918         } catch (IOException e) {
1919             throw new RuntimeException("Failed to clear PPAPI Consent", e);
1920         }
1921 
1922         // Save that PPAPI consent has cleared into shared preferences.
1923         SharedPreferences.Editor editor = sharedPreferences.edit();
1924         editor.putBoolean(ConsentConstants.SHARED_PREFS_KEY_PPAPI_HAS_CLEARED, true);
1925 
1926         if (editor.commit()) {
1927             LogUtil.d("Finished clearing Consent in PPAPI.");
1928         } else {
1929             LogUtil.e("Finished clearing Consent in PPAPI but shared preference is not updated.");
1930             ErrorLogUtil.e(
1931                     AD_SERVICES_ERROR_REPORTED__ERROR_CODE__SHARED_PREF_UPDATE_FAILURE,
1932                     AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__UX);
1933         }
1934     }
1935 
1936     // Set the shared preference to false for given key.
1937     @VisibleForTesting
1938     // TODO(b/311183933): Remove passed in Context from static method.
1939     @SuppressWarnings("AvoidStaticContext")
resetSharedPreference(Context context, String sharedPreferenceKey)1940     static void resetSharedPreference(Context context, String sharedPreferenceKey) {
1941         Objects.requireNonNull(context, "context cannot be null");
1942         Objects.requireNonNull(sharedPreferenceKey, "sharedPreferenceKey cannot be null");
1943 
1944         SharedPreferences sharedPreferences = getPrefs(context);
1945         SharedPreferences.Editor editor = sharedPreferences.edit();
1946         editor.putBoolean(sharedPreferenceKey, false);
1947 
1948         if (editor.commit()) {
1949             LogUtil.d("Finished resetting shared preference for " + sharedPreferenceKey);
1950         } else {
1951             LogUtil.e("Failed to reset shared preference for " + sharedPreferenceKey);
1952             ErrorLogUtil.e(
1953                     AD_SERVICES_ERROR_REPORTED__ERROR_CODE__SHARED_PREF_RESET_FAILURE,
1954                     AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__UX);
1955         }
1956     }
1957 
1958     @VisibleForTesting
handleEnrollmentDataMigrationIfNeeded(ConsentManager manager)1959     static void handleEnrollmentDataMigrationIfNeeded(ConsentManager manager) {
1960         String value = manager.getModuleEnrollmentState();
1961         if (value != null && !value.isEmpty()) {
1962             return;
1963         }
1964         EnrollmentData data = new EnrollmentData();
1965 
1966         // convert data (Ad ID is left out for now)
1967         int[] modules =
1968                 new int[] {
1969                     MEASUREMENT,
1970                     PROTECTED_AUDIENCE,
1971                     PROTECTED_APP_SIGNALS,
1972                     TOPICS,
1973                     ON_DEVICE_PERSONALIZATION
1974                 };
1975         for (int apiModule : modules) {
1976             data.putModuleState(apiModule, manager.getConvertedModuleState(apiModule));
1977             data.putUserChoice(apiModule, manager.getConvertedUserChoice(apiModule));
1978         }
1979 
1980         // store data
1981         String dataString = EnrollmentData.serialize(data);
1982         manager.setModuleEnrollmentData(dataString);
1983     }
1984 
1985     @ModuleUserChoiceCode
getConvertedUserChoice(@oduleCode int apiType)1986     private int getConvertedUserChoice(@ModuleCode int apiType) {
1987         Boolean consent = null;
1988 
1989         try {
1990             switch (apiType) {
1991                 case MEASUREMENT -> consent = getConsentNullable(AdServicesApiType.MEASUREMENTS);
1992                 case ON_DEVICE_PERSONALIZATION, PROTECTED_APP_SIGNALS -> {
1993                     boolean isEuDevice =
1994                             DeviceRegionProvider.isEuDevice(ApplicationContextSingleton.get());
1995                     boolean isOnboardedEeaPasUser =
1996                             isEuDevice && mFlags.getEeaPasUxEnabled() && wasPasNotificationOpened();
1997                     boolean isOnboardedRowPasUser =
1998                             !isEuDevice
1999                                     && mFlags.getPasUxEnabled()
2000                                     && wasPasNotificationDisplayed();
2001                     if (isOnboardedEeaPasUser || isOnboardedRowPasUser) {
2002                         // true since this consent is combined with toggles for final user choice.
2003                         consent = true;
2004                     }
2005                 }
2006                 case PROTECTED_AUDIENCE -> consent = getConsentNullable(AdServicesApiType.FLEDGE);
2007                 case TOPICS -> consent = getConsentNullable(AdServicesApiType.TOPICS);
2008                 default -> consent = null;
2009             }
2010         } catch (NullPointerException e) {
2011             LogUtil.v("No previous consent for apiType:" + apiType);
2012         }
2013 
2014         return consent == null
2015                 ? USER_CHOICE_UNKNOWN
2016                 : consent ? USER_CHOICE_OPTED_IN : USER_CHOICE_OPTED_OUT;
2017     }
2018 
2019     @ModuleState
getConvertedModuleState(@oduleCode int apiType)2020     private int getConvertedModuleState(@ModuleCode int apiType) {
2021         int state = MODULE_STATE_DISABLED;
2022         switch (apiType) {
2023             case MEASUREMENT -> {
2024                 if (wasGaUxNotificationDisplayed()
2025                         || wasU18NotificationDisplayed()
2026                         || wasPasNotificationDisplayed()) {
2027                     state = MODULE_STATE_ENABLED;
2028                 }
2029             }
2030             case ON_DEVICE_PERSONALIZATION, PROTECTED_APP_SIGNALS -> {
2031                 if (wasPasNotificationDisplayed()) {
2032                     state = MODULE_STATE_ENABLED;
2033                 }
2034             }
2035             case PROTECTED_AUDIENCE, TOPICS -> {
2036                 if (wasGaUxNotificationDisplayed() || wasPasNotificationDisplayed()) {
2037                     state = MODULE_STATE_ENABLED;
2038                 }
2039             }
2040             default -> state = MODULE_STATE_UNKNOWN;
2041         }
2042         return state;
2043     }
2044 
2045     // To write to PPAPI if consent source of truth is PPAPI_ONLY or dual sources.
2046     // To write to system server if consent source of truth is SYSTEM_SERVER_ONLY or dual sources.
2047     @VisibleForTesting
setConsentToSourceOfTruth(boolean isGiven)2048     void setConsentToSourceOfTruth(boolean isGiven) {
2049         executeSettersByConsentSourceOfTruth(
2050                 () -> setConsentToPpApi(isGiven),
2051                 () -> setConsentToSystemServer(mAdServicesManager, isGiven),
2052                 () ->
2053                         mAppSearchConsentManager.setConsent(
2054                                 ConsentConstants.CONSENT_KEY_FOR_ALL, isGiven),
2055                 /* errorLogger= */ null);
2056     }
2057 
2058     @VisibleForTesting
getConsentFromSourceOfTruth()2059     boolean getConsentFromSourceOfTruth() {
2060         return executeGettersByConsentSourceOfTruth(
2061                 false,
2062                 () -> getConsentFromPpApi(),
2063                 () -> getConsentFromSystemServer(mAdServicesManager),
2064                 () -> mAppSearchConsentManager.getConsent(ConsentConstants.CONSENT_KEY_FOR_ALL),
2065                 /* errorLogger= */ null);
2066     }
2067 
2068     @VisibleForTesting
getPerApiConsentFromSourceOfTruth(AdServicesApiType apiType)2069     boolean getPerApiConsentFromSourceOfTruth(AdServicesApiType apiType) {
2070         boolean businessLogicMigrationEnabled =
2071                 FlagsFactory.getFlags().getAdServicesConsentBusinessLogicMigrationEnabled();
2072         if (businessLogicMigrationEnabled) {
2073             return getUserChoice(apiType).isGiven();
2074         }
2075         return executeGettersByConsentSourceOfTruth(
2076                 false,
2077                 () -> getConsentPerApiFromPpApi(apiType),
2078                 () ->
2079                         getPerApiConsentFromSystemServer(
2080                                 mAdServicesManager, apiType.toConsentApiType()),
2081                 () -> mAppSearchConsentManager.getConsent(apiType.toPpApiDatastoreKey()),
2082                 /* errorLogger= */ null);
2083     }
2084 
2085     @VisibleForTesting
setPerApiConsentToSourceOfTruth(boolean isGiven, AdServicesApiType apiType)2086     void setPerApiConsentToSourceOfTruth(boolean isGiven, AdServicesApiType apiType) {
2087         boolean businessLogicMigrationEnabled =
2088                 FlagsFactory.getFlags().getAdServicesConsentBusinessLogicMigrationEnabled();
2089         if (businessLogicMigrationEnabled) {
2090             setUserChoice(apiType, isGiven ? USER_CHOICE_OPTED_IN : USER_CHOICE_OPTED_OUT);
2091         }
2092         executeSettersByConsentSourceOfTruth(
2093                 () -> {
2094                     setConsentPerApiToPpApi(apiType, isGiven);
2095                     setAggregatedConsentToPpApi();
2096                 },
2097                 () ->
2098                         setPerApiConsentToSystemServer(
2099                                 mAdServicesManager, apiType.toConsentApiType(), isGiven),
2100                 () -> mAppSearchConsentManager.setConsent(apiType.toPpApiDatastoreKey(), isGiven),
2101                 /* errorLogger= */ null);
2102     }
2103 
2104     /**
2105      * This method handles migration of consent data from AppSearch to AdServices. Consent data is
2106      * written to AppSearch on S- and ported to AdServices after OTA to T. If any new data is
2107      * written for consent, we need to make sure it is migrated correctly post-OTA in this method.
2108      */
2109     @VisibleForTesting
2110     // TODO(b/311183933): Remove passed in Context from static method.
2111     @SuppressWarnings("AvoidStaticContext")
handleConsentMigrationFromAppSearchIfNeeded( Context context, AtomicFileDatastore datastore, AppConsentDao appConsentDao, AppSearchConsentManager appSearchConsentManager, AdServicesManager adServicesManager, StatsdAdServicesLogger statsdAdServicesLogger)2112     static void handleConsentMigrationFromAppSearchIfNeeded(
2113             Context context,
2114             AtomicFileDatastore datastore,
2115             AppConsentDao appConsentDao,
2116             AppSearchConsentManager appSearchConsentManager,
2117             AdServicesManager adServicesManager,
2118             StatsdAdServicesLogger statsdAdServicesLogger) {
2119         Flags flags = FlagsFactory.getFlags();
2120         RbATraceProvider.beginSection(
2121                 CONSENT_MANAGER,
2122                 CLASS_NAME_CONSENT_MANAGER,
2123                 METHOD_NAME_MIGRATION_FROM_APP_SEARCH,
2124                 flags);
2125 
2126         Objects.requireNonNull(context, "context cannot be null");
2127         Objects.requireNonNull(appSearchConsentManager, "appSearchConsentManager cannot be null");
2128         LogUtil.d("Check migrating Consent from AppSearch to PPAPI and System Service");
2129 
2130         // On R/S, this function should never be executed because AppSearch to PPAPI and
2131         // System Server migration is a T+ feature. On T+, this function should only execute
2132         // if it's within the AdServices APK and not ExtServices. So check if it's within
2133         // ExtServices, and bail out if that's the case on any platform.
2134         String packageName = context.getPackageName();
2135         if (packageName != null && packageName.endsWith(ADEXTSERVICES_PACKAGE_NAME_SUFFIX)) {
2136             LogUtil.d(
2137                     "Aborting attempt to migrate AppSearch to PPAPI and System Service in"
2138                             + " ExtServices");
2139             return;
2140         }
2141 
2142         AppConsents appConsents = null;
2143         try {
2144             // This should be called only once after OTA (if flag is enabled). If we did not record
2145             // showing the notification on T+ yet and we have shown the notification on S- (as
2146             // recorded in AppSearch), initialize T+ consent data so that we don't show notification
2147             // twice (after OTA upgrade).
2148             SharedPreferences sharedPreferences = getPrefs(context);
2149             // If we did not migrate notification data, we should not attempt to migrate anything.
2150             if (!appSearchConsentManager.migrateConsentDataIfNeeded(
2151                     sharedPreferences, datastore, adServicesManager, appConsentDao)) {
2152                 LogUtil.d("Skipping consent migration from AppSearch");
2153                 return;
2154             }
2155 
2156             // Migrate Consent for all APIs and per API to PP API and System Service.
2157             appConsents =
2158                     migrateAppSearchConsents(appSearchConsentManager, adServicesManager, datastore);
2159 
2160             // Record interactions data only if we recorded an interaction in AppSearch.
2161             int manualInteractionRecorded =
2162                     appSearchConsentManager.getUserManualInteractionWithConsent();
2163             if (manualInteractionRecorded == MANUAL_INTERACTIONS_RECORDED) {
2164                 // Initialize PP API datastore.
2165                 storeUserManualInteractionToPpApi(manualInteractionRecorded, datastore);
2166                 // Initialize system service.
2167                 adServicesManager.recordUserManualInteractionWithConsent(manualInteractionRecorded);
2168             }
2169 
2170             // Record that we migrated consent data from AppSearch. We write the notification data
2171             // to system server and perform migration only if system server did not record any
2172             // notification having been displayed.
2173             SharedPreferences.Editor editor = sharedPreferences.edit();
2174             editor.putBoolean(ConsentConstants.SHARED_PREFS_KEY_APPSEARCH_HAS_MIGRATED, true);
2175             if (editor.commit()) {
2176                 LogUtil.d("Finished migrating Consent from AppSearch to PPAPI + System Service");
2177                 statsdAdServicesLogger.logConsentMigrationStats(
2178                         getConsentManagerStatsForLogging(
2179                                 appConsents,
2180                                 ConsentMigrationStats.MigrationStatus
2181                                         .SUCCESS_WITH_SHARED_PREF_UPDATED,
2182                                 ConsentMigrationStats.MigrationType.APPSEARCH_TO_SYSTEM_SERVICE,
2183                                 context));
2184             } else {
2185                 LogUtil.e(
2186                         "Finished migrating Consent from AppSearch to PPAPI + System Service "
2187                                 + "but shared preference is not updated.");
2188                 statsdAdServicesLogger.logConsentMigrationStats(
2189                         getConsentManagerStatsForLogging(
2190                                 appConsents,
2191                                 ConsentMigrationStats.MigrationStatus
2192                                         .SUCCESS_WITH_SHARED_PREF_NOT_UPDATED,
2193                                 ConsentMigrationStats.MigrationType.APPSEARCH_TO_SYSTEM_SERVICE,
2194                                 context));
2195             }
2196         } catch (IOException e) {
2197             LogUtil.e("AppSearch consent data migration failed: ", e);
2198             ErrorLogUtil.e(
2199                     e,
2200                     AD_SERVICES_ERROR_REPORTED__ERROR_CODE__APP_SEARCH_DATA_MIGRATION_FAILURE,
2201                     AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__UX);
2202             statsdAdServicesLogger.logConsentMigrationStats(
2203                     getConsentManagerStatsForLogging(
2204                             appConsents,
2205                             ConsentMigrationStats.MigrationStatus.FAILURE,
2206                             ConsentMigrationStats.MigrationType.APPSEARCH_TO_SYSTEM_SERVICE,
2207                             context));
2208         } finally {
2209             RbATraceProvider.endSection(flags);
2210         }
2211     }
2212 
2213     /**
2214      * This method returns and migrates the consent states (opt in/out) for all PPAPIs, each API and
2215      * their default consent values.
2216      */
2217     @VisibleForTesting
migrateAppSearchConsents( AppSearchConsentManager appSearchConsentManager, AdServicesManager adServicesManager, AtomicFileDatastore datastore)2218     static AppConsents migrateAppSearchConsents(
2219             AppSearchConsentManager appSearchConsentManager,
2220             AdServicesManager adServicesManager,
2221             AtomicFileDatastore datastore)
2222             throws IOException {
2223         boolean consented = appSearchConsentManager.getConsent(ConsentConstants.CONSENT_KEY);
2224         datastore.putBoolean(ConsentConstants.CONSENT_KEY, consented);
2225         adServicesManager.setConsent(getConsentParcel(ConsentParcel.ALL_API, consented));
2226 
2227         // Record default consents.
2228         boolean defaultConsent =
2229                 appSearchConsentManager.getConsent(ConsentConstants.DEFAULT_CONSENT);
2230         datastore.putBoolean(ConsentConstants.DEFAULT_CONSENT, defaultConsent);
2231         adServicesManager.recordDefaultConsent(defaultConsent);
2232         boolean topicsDefaultConsented =
2233                 appSearchConsentManager.getConsent(ConsentConstants.TOPICS_DEFAULT_CONSENT);
2234         datastore.putBoolean(ConsentConstants.TOPICS_DEFAULT_CONSENT, topicsDefaultConsented);
2235         adServicesManager.recordTopicsDefaultConsent(topicsDefaultConsented);
2236         boolean fledgeDefaultConsented =
2237                 appSearchConsentManager.getConsent(ConsentConstants.FLEDGE_DEFAULT_CONSENT);
2238         datastore.putBoolean(ConsentConstants.FLEDGE_DEFAULT_CONSENT, fledgeDefaultConsented);
2239         adServicesManager.recordFledgeDefaultConsent(fledgeDefaultConsented);
2240         boolean measurementDefaultConsented =
2241                 appSearchConsentManager.getConsent(ConsentConstants.MEASUREMENT_DEFAULT_CONSENT);
2242         datastore.putBoolean(
2243                 ConsentConstants.MEASUREMENT_DEFAULT_CONSENT, measurementDefaultConsented);
2244         adServicesManager.recordMeasurementDefaultConsent(measurementDefaultConsented);
2245 
2246         // Record per API consents.
2247         boolean topicsConsented =
2248                 appSearchConsentManager.getConsent(AdServicesApiType.TOPICS.toPpApiDatastoreKey());
2249         datastore.putBoolean(AdServicesApiType.TOPICS.toPpApiDatastoreKey(), topicsConsented);
2250         setPerApiConsentToSystemServer(
2251                 adServicesManager, AdServicesApiType.TOPICS.toConsentApiType(), topicsConsented);
2252         boolean fledgeConsented =
2253                 appSearchConsentManager.getConsent(AdServicesApiType.FLEDGE.toPpApiDatastoreKey());
2254         datastore.putBoolean(AdServicesApiType.FLEDGE.toPpApiDatastoreKey(), fledgeConsented);
2255         setPerApiConsentToSystemServer(
2256                 adServicesManager, AdServicesApiType.FLEDGE.toConsentApiType(), fledgeConsented);
2257         boolean measurementConsented =
2258                 appSearchConsentManager.getConsent(
2259                         AdServicesApiType.MEASUREMENTS.toPpApiDatastoreKey());
2260         datastore.putBoolean(
2261                 AdServicesApiType.MEASUREMENTS.toPpApiDatastoreKey(), measurementConsented);
2262         setPerApiConsentToSystemServer(
2263                 adServicesManager,
2264                 AdServicesApiType.MEASUREMENTS.toConsentApiType(),
2265                 measurementConsented);
2266 
2267         boolean businessLogicMigrationEnabled =
2268                 FlagsFactory.getFlags().getAdServicesConsentBusinessLogicMigrationEnabled();
2269         if (businessLogicMigrationEnabled) {
2270             String data = appSearchConsentManager.getModuleEnrollmentState();
2271             if (data == null) {
2272                 data = "";
2273             }
2274             datastore.putString(ConsentConstants.MODULE_ENROLLMENT_STATE, data);
2275             adServicesManager.setModuleEnrollmentState(data);
2276         }
2277         return AppConsents.builder()
2278                 .setMsmtConsent(measurementConsented)
2279                 .setTopicsConsent(topicsConsented)
2280                 .setFledgeConsent(fledgeConsented)
2281                 .build();
2282     }
2283 
getConsentParcel(Integer apiType, Boolean consented)2284     private static ConsentParcel getConsentParcel(Integer apiType, Boolean consented) {
2285         return new ConsentParcel.Builder().setConsentApiType(apiType).setIsGiven(consented).build();
2286     }
2287 
2288     /**
2289      * Represents revoked consent as internally determined by the PP APIs.
2290      *
2291      * <p>This is an internal-only exception and is not meant to be returned to external callers.
2292      */
2293     public static class RevokedConsentException extends IllegalStateException {
2294         public static final String REVOKED_CONSENT_ERROR_MESSAGE =
2295                 "Error caused by revoked user consent";
2296 
2297         /** Creates an instance of a {@link RevokedConsentException}. */
RevokedConsentException()2298         public RevokedConsentException() {
2299             super(REVOKED_CONSENT_ERROR_MESSAGE);
2300         }
2301     }
2302 
asyncExecute(Runnable runnable)2303     private void asyncExecute(Runnable runnable) {
2304         AdServicesExecutors.getBackgroundExecutor().execute(runnable);
2305     }
2306 
logWipeoutStats(WipeoutStatus wipeoutStatus)2307     private void logWipeoutStats(WipeoutStatus wipeoutStatus) {
2308         AdServicesLoggerImpl.getInstance()
2309                 .logMeasurementWipeoutStats(
2310                         new MeasurementWipeoutStats.Builder()
2311                                 .setCode(AD_SERVICES_MEASUREMENT_WIPEOUT)
2312                                 .setWipeoutType(wipeoutStatus.getWipeoutType().getValue())
2313                                 .build());
2314     }
2315 
2316     /** Returns whether the isAdIdEnabled bit is true based on consent_source_of_truth. */
isAdIdEnabled()2317     public Boolean isAdIdEnabled() {
2318         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
2319             return ConsentManagerV2.getInstance().isAdIdEnabled();
2320         }
2321         return executeGettersByConsentSourceOfTruth(
2322                 /* defaultReturn= */ false,
2323                 () -> mDatastore.getBoolean(ConsentConstants.IS_AD_ID_ENABLED),
2324                 () -> mAdServicesManager.isAdIdEnabled(),
2325                 () -> mAppSearchConsentManager.isAdIdEnabled(),
2326                 /* errorLogger= */ null);
2327     }
2328 
2329     /** Set the AdIdEnabled bit to storage based on consent_source_of_truth. */
setAdIdEnabled(boolean isAdIdEnabled)2330     public void setAdIdEnabled(boolean isAdIdEnabled) {
2331         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
2332             ConsentManagerV2.getInstance().setAdIdEnabled(isAdIdEnabled);
2333             return;
2334         }
2335         executeSettersByConsentSourceOfTruth(
2336                 () -> mDatastore.putBoolean(ConsentConstants.IS_AD_ID_ENABLED, isAdIdEnabled),
2337                 () -> mAdServicesManager.setAdIdEnabled(isAdIdEnabled),
2338                 () -> mAppSearchConsentManager.setAdIdEnabled(isAdIdEnabled),
2339                 /* errorLogger= */ null);
2340     }
2341 
2342     /** Returns whether the isU18Account bit is true based on consent_source_of_truth. */
isU18Account()2343     public Boolean isU18Account() {
2344         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
2345             return ConsentManagerV2.getInstance().isU18Account();
2346         }
2347         return executeGettersByConsentSourceOfTruth(
2348                 /* defaultReturn= */ false,
2349                 () -> mDatastore.getBoolean(ConsentConstants.IS_U18_ACCOUNT),
2350                 () -> mAdServicesManager.isU18Account(),
2351                 () -> mAppSearchConsentManager.isU18Account(),
2352                 /* errorLogger= */ null);
2353     }
2354 
2355     /** Set the U18Account bit to storage based on consent_source_of_truth. */
setU18Account(boolean isU18Account)2356     public void setU18Account(boolean isU18Account) {
2357         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
2358             ConsentManagerV2.getInstance().setU18Account(isU18Account);
2359             return;
2360         }
2361         executeSettersByConsentSourceOfTruth(
2362                 () -> mDatastore.putBoolean(ConsentConstants.IS_U18_ACCOUNT, isU18Account),
2363                 () -> mAdServicesManager.setU18Account(isU18Account),
2364                 () -> mAppSearchConsentManager.setU18Account(isU18Account),
2365                 /* errorLogger= */ null);
2366     }
2367 
2368     /** Returns whether the isEntryPointEnabled bit is true based on consent_source_of_truth. */
isEntryPointEnabled()2369     public Boolean isEntryPointEnabled() {
2370         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
2371             return ConsentManagerV2.getInstance().isEntryPointEnabled();
2372         }
2373         return executeGettersByConsentSourceOfTruth(
2374                 /* defaultReturn= */ false,
2375                 () -> mDatastore.getBoolean(ConsentConstants.IS_ENTRY_POINT_ENABLED),
2376                 () -> mAdServicesManager.isEntryPointEnabled(),
2377                 () -> mAppSearchConsentManager.isEntryPointEnabled(),
2378                 /* errorLogger= */ null);
2379     }
2380 
2381     /** Set the EntryPointEnabled bit to storage based on consent_source_of_truth. */
setEntryPointEnabled(boolean isEntryPointEnabled)2382     public void setEntryPointEnabled(boolean isEntryPointEnabled) {
2383         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
2384             ConsentManagerV2.getInstance().setEntryPointEnabled(isEntryPointEnabled);
2385             return;
2386         }
2387         executeSettersByConsentSourceOfTruth(
2388                 () ->
2389                         mDatastore.putBoolean(
2390                                 ConsentConstants.IS_ENTRY_POINT_ENABLED, isEntryPointEnabled),
2391                 () -> mAdServicesManager.setEntryPointEnabled(isEntryPointEnabled),
2392                 () -> mAppSearchConsentManager.setEntryPointEnabled(isEntryPointEnabled),
2393                 /* errorLogger= */ null);
2394     }
2395 
2396     /** Returns whether the isAdultAccount bit is true based on consent_source_of_truth. */
isAdultAccount()2397     public Boolean isAdultAccount() {
2398         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
2399             return ConsentManagerV2.getInstance().isAdultAccount();
2400         }
2401         return executeGettersByConsentSourceOfTruth(
2402                 /* defaultReturn= */ false,
2403                 () -> mDatastore.getBoolean(ConsentConstants.IS_ADULT_ACCOUNT),
2404                 () -> mAdServicesManager.isAdultAccount(),
2405                 () -> mAppSearchConsentManager.isAdultAccount(),
2406                 /* errorLogger= */ null);
2407     }
2408 
2409     /** Set the AdultAccount bit to storage based on consent_source_of_truth. */
setAdultAccount(boolean isAdultAccount)2410     public void setAdultAccount(boolean isAdultAccount) {
2411         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
2412             ConsentManagerV2.getInstance().setAdultAccount(isAdultAccount);
2413             return;
2414         }
2415         executeSettersByConsentSourceOfTruth(
2416                 () -> mDatastore.putBoolean(ConsentConstants.IS_ADULT_ACCOUNT, isAdultAccount),
2417                 () -> mAdServicesManager.setAdultAccount(isAdultAccount),
2418                 () -> mAppSearchConsentManager.setAdultAccount(isAdultAccount),
2419                 /* errorLogger= */ null);
2420     }
2421 
2422     /**
2423      * Returns whether the wasU18NotificationDisplayed bit is true based on consent_source_of_truth.
2424      */
wasU18NotificationDisplayed()2425     public Boolean wasU18NotificationDisplayed() {
2426         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
2427             return ConsentManagerV2.getInstance().wasU18NotificationDisplayed();
2428         }
2429         return executeGettersByConsentSourceOfTruth(
2430                 /* defaultReturn= */ true,
2431                 () -> mDatastore.getBoolean(ConsentConstants.WAS_U18_NOTIFICATION_DISPLAYED),
2432                 () -> mAdServicesManager.wasU18NotificationDisplayed(),
2433                 () -> mAppSearchConsentManager.wasU18NotificationDisplayed(),
2434                 /* errorLogger= */ null);
2435     }
2436 
2437     /** Set the U18NotificationDisplayed bit to storage based on consent_source_of_truth. */
setU18NotificationDisplayed(boolean wasU18NotificationDisplayed)2438     public void setU18NotificationDisplayed(boolean wasU18NotificationDisplayed) {
2439         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
2440             ConsentManagerV2.getInstance().setU18NotificationDisplayed(wasU18NotificationDisplayed);
2441             return;
2442         }
2443         executeSettersByConsentSourceOfTruth(
2444                 () ->
2445                         mDatastore.putBoolean(
2446                                 ConsentConstants.WAS_U18_NOTIFICATION_DISPLAYED,
2447                                 wasU18NotificationDisplayed),
2448                 () -> mAdServicesManager.setU18NotificationDisplayed(wasU18NotificationDisplayed),
2449                 () ->
2450                         mAppSearchConsentManager.setU18NotificationDisplayed(
2451                                 wasU18NotificationDisplayed),
2452                 /* errorLogger= */ null);
2453     }
2454 
convertUxString(String uxString)2455     private PrivacySandboxUxCollection convertUxString(String uxString) {
2456         return Stream.of(PrivacySandboxUxCollection.values())
2457                 .filter(ux -> uxString.equals(ux.toString()))
2458                 .findFirst()
2459                 .orElse(UNSUPPORTED_UX);
2460     }
2461 
2462     /** Returns current UX based on consent_source_of_truth. */
getUx()2463     public PrivacySandboxUxCollection getUx() {
2464         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
2465             return ConsentManagerV2.getInstance().getUx();
2466         }
2467         boolean businessLogicMigrationEnabled =
2468                 FlagsFactory.getFlags().getAdServicesConsentBusinessLogicMigrationEnabled();
2469         if (businessLogicMigrationEnabled) {
2470             return determineUxFromEnrollmentData();
2471         }
2472         return executeGettersByConsentSourceOfTruth(
2473                 /* defaultReturn= */ UNSUPPORTED_UX,
2474                 () -> mUxStatesDao.getUx(),
2475                 () -> convertUxString(mAdServicesManager.getUx()),
2476                 () -> mAppSearchConsentManager.getUx(),
2477                 /* errorLogger= */ null);
2478     }
2479 
determineUxFromEnrollmentData()2480     private PrivacySandboxUxCollection determineUxFromEnrollmentData() {
2481         EnrollmentData data = EnrollmentData.deserialize(getModuleEnrollmentState());
2482         int[] allModules =
2483                 new int[] {
2484                     MODULE_TOPICS,
2485                     MODULE_PROTECTED_AUDIENCE,
2486                     MODULE_MEASUREMENT,
2487                     MODULE_PROTECTED_APP_SIGNALS,
2488                     MODULE_ON_DEVICE_PERSONALIZATION
2489                 };
2490         boolean isAnyModuleEnabled = false;
2491         boolean isPersonalizedAdsModuleEnabled = false;
2492         for (int apiModule : allModules) {
2493             int state = data.getModuleState(apiModule);
2494             if (state == MODULE_STATE_ENABLED) {
2495                 isAnyModuleEnabled = true;
2496                 if (apiModule != MODULE_MEASUREMENT) {
2497                     isPersonalizedAdsModuleEnabled = true;
2498                 }
2499             }
2500         }
2501         // currently PAS UX is within GA UX, once UxSelector is Revamped, this method won't exist
2502         // anyways, so no need to have separate bit for PAS/ODP Enabled.
2503         if (isPersonalizedAdsModuleEnabled) {
2504             return GA_UX;
2505         } else if (isAnyModuleEnabled) {
2506             return U18_UX;
2507         }
2508         return UNSUPPORTED_UX;
2509     }
2510 
2511     /**
2512      * Determines what UX should be displayed to the end user currently.
2513      *
2514      * @return UX for end user.
2515      */
determineEndUserSettingsUxFromEnrollmentData()2516     public EndUserUx determineEndUserSettingsUxFromEnrollmentData() {
2517         EnrollmentData data = EnrollmentData.deserialize(getModuleEnrollmentState());
2518         int[] allModules =
2519                 new int[] {
2520                     MODULE_TOPICS,
2521                     MODULE_PROTECTED_AUDIENCE,
2522                     MODULE_MEASUREMENT,
2523                     MODULE_PROTECTED_APP_SIGNALS,
2524                     MODULE_ON_DEVICE_PERSONALIZATION
2525                 };
2526         boolean isAnyModuleEnabled = false;
2527         boolean isNotFirstTimeUser = false;
2528         boolean isPersonalizedAdsModuleEnabled = false;
2529         boolean isPasOdpModuleEnabled = false;
2530         boolean isPasOdpModuleOptedIn = false;
2531         for (int apiModule : allModules) {
2532             int state = data.getModuleState(apiModule);
2533             int userChoice = data.getUserChoice(apiModule);
2534             if (state == MODULE_STATE_ENABLED) {
2535                 isAnyModuleEnabled = true;
2536                 if (apiModule != MODULE_MEASUREMENT) {
2537                     isPersonalizedAdsModuleEnabled = true;
2538                 }
2539                 if (apiModule == MODULE_PROTECTED_APP_SIGNALS
2540                         || apiModule == MODULE_ON_DEVICE_PERSONALIZATION) {
2541                     isPasOdpModuleEnabled = true;
2542                 }
2543             }
2544             if (userChoice != USER_CHOICE_UNKNOWN) {
2545                 isNotFirstTimeUser = true;
2546             }
2547             if (userChoice == USER_CHOICE_OPTED_IN
2548                     && (apiModule == MODULE_PROTECTED_APP_SIGNALS
2549                             || apiModule == MODULE_ON_DEVICE_PERSONALIZATION)) {
2550                 isPasOdpModuleOptedIn = true;
2551             }
2552         }
2553 
2554         // whether PAS/ODP APIs are being enabled with other APIs for the first time, OR PAS/ODP
2555         // APIs have been activated via System API setting user choice to opted-in, which does not
2556         // signify user has opted-in, as the final consent needs to be combined with the toggle
2557         // consents.
2558         boolean PasOdpFirstTimeOrActivated =
2559                 isPasOdpModuleEnabled && (!isNotFirstTimeUser || isPasOdpModuleOptedIn);
2560         if (PasOdpFirstTimeOrActivated) {
2561             return EndUserUx.GA_WITH_PAS;
2562         } else if (isPersonalizedAdsModuleEnabled) {
2563             return EndUserUx.GA;
2564         } else if (isAnyModuleEnabled) {
2565             return EndUserUx.U18;
2566         }
2567         return EndUserUx.GA;
2568     }
2569 
2570     /** Set the current UX to storage based on consent_source_of_truth. */
setUx(PrivacySandboxUxCollection ux)2571     public void setUx(PrivacySandboxUxCollection ux) {
2572         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
2573             ConsentManagerV2.getInstance().setUx(ux);
2574             return;
2575         }
2576         executeSettersByConsentSourceOfTruth(
2577                 () -> mUxStatesDao.setUx(ux),
2578                 () -> mAdServicesManager.setUx(ux.toString()),
2579                 () -> mAppSearchConsentManager.setUx(ux),
2580                 /* errorLogger= */ null);
2581     }
2582 
2583     /** Returns if any module sate is enabled. */
getIsAnyModuleStateEnabled()2584     public boolean getIsAnyModuleStateEnabled() {
2585         EnrollmentData data = EnrollmentData.deserialize(getModuleEnrollmentState());
2586         SparseIntArray states = data.getModuleStates();
2587         boolean isAnyModuleStateEnabled = false;
2588         for (int i = 0; i < states.size(); i++) {
2589             if (states.valueAt(i) == MODULE_STATE_ENABLED) {
2590                 isAnyModuleStateEnabled = true;
2591             }
2592         }
2593         return isAnyModuleStateEnabled;
2594     }
2595 
2596     /**
2597      * Get module state for desired module.
2598      *
2599      * @param apiModule desired module
2600      * @return module state
2601      */
2602     @ModuleState
getModuleState(@oduleCode int apiModule)2603     public int getModuleState(@ModuleCode int apiModule) {
2604         EnrollmentData data = EnrollmentData.deserialize(getModuleEnrollmentState());
2605         return data.getModuleState(apiModule);
2606     }
2607 
2608     /**
2609      * Gets enrollmentdata.
2610      *
2611      * @return enrollment data.
2612      */
getEnrollmentData()2613     public EnrollmentData getEnrollmentData() {
2614         return EnrollmentData.deserialize(getModuleEnrollmentState());
2615     }
2616 
2617     /**
2618      * Sets module state for a module.
2619      *
2620      * @param modulesStates object to set
2621      */
setModuleStates(SparseIntArray modulesStates)2622     public void setModuleStates(SparseIntArray modulesStates) {
2623         EnrollmentData data = EnrollmentData.deserialize(getModuleEnrollmentState());
2624         for (int i = 0; i < modulesStates.size(); i++) {
2625             data.putModuleState(modulesStates.keyAt(i), modulesStates.valueAt(i));
2626         }
2627         setModuleEnrollmentData(EnrollmentData.serialize(data));
2628     }
2629 
getUserChoice(AdServicesApiType apiType)2630     private AdServicesApiConsent getUserChoice(AdServicesApiType apiType) {
2631         int apiModule = -1;
2632         switch (apiType) {
2633             case TOPICS -> apiModule = TOPICS;
2634             case FLEDGE -> apiModule = PROTECTED_AUDIENCE;
2635             case MEASUREMENTS -> apiModule = MEASUREMENT;
2636             default -> {
2637                 LogUtil.v("Skipping ALL_API and UNKNOWN API Types for getUserChoice.");
2638             }
2639         }
2640         return new AdServicesApiConsent(getUserChoice(apiModule) == USER_CHOICE_OPTED_IN);
2641     }
2642 
2643     /**
2644      * Gets user choice for a module.
2645      *
2646      * @param apiModule Module to get
2647      * @return User choice of the module
2648      */
2649     @ModuleUserChoiceCode
getUserChoice(@oduleCode int apiModule)2650     public int getUserChoice(@ModuleCode int apiModule) {
2651         EnrollmentData data = EnrollmentData.deserialize(getModuleEnrollmentState());
2652         return data.getUserChoice(apiModule);
2653     }
2654 
setUserChoice(AdServicesApiType apiType, @ModuleUserChoiceCode int userChoice)2655     private void setUserChoice(AdServicesApiType apiType, @ModuleUserChoiceCode int userChoice) {
2656         List<AdServicesModuleUserChoice> userChoices = new ArrayList<>();
2657         switch (apiType) {
2658             case TOPICS -> {
2659                 userChoices.add(new AdServicesModuleUserChoice(TOPICS, userChoice));
2660             }
2661             case FLEDGE -> {
2662                 userChoices.add(new AdServicesModuleUserChoice(PROTECTED_AUDIENCE, userChoice));
2663             }
2664             case MEASUREMENTS -> {
2665                 userChoices.add(new AdServicesModuleUserChoice(MEASUREMENT, userChoice));
2666             }
2667             default -> {
2668                 LogUtil.v("Skipping ALL_API and UNKNOWN API Types for setUserChoice.");
2669             }
2670         }
2671         setUserChoices(userChoices);
2672     }
2673 
2674     /**
2675      * Aligns user choices to module states by setting user choice to unknown if a module state is
2676      * not enabled.
2677      *
2678      * <p>This method should only be called specifically after a notification is shown to ensure the
2679      * user choices are erased if a module state is now disabled or unknown. This method is also a
2680      * safeguard, since a request to set user choices to unknown can also be made instead.
2681      */
alignUserChoicesIfNeeded()2682     public void alignUserChoicesIfNeeded() {
2683         EnrollmentData data = EnrollmentData.deserialize(getModuleEnrollmentState());
2684         List<AdServicesModuleUserChoice> userChoices = new ArrayList<>();
2685         SparseIntArray moduleStates = data.getModuleStates();
2686         for (int i = 0; i < moduleStates.size(); i++) {
2687             int moduleState = moduleStates.keyAt(i);
2688             int state = moduleStates.valueAt(i);
2689             if (state != MODULE_STATE_ENABLED) {
2690                 userChoices.add(new AdServicesModuleUserChoice(moduleState, USER_CHOICE_UNKNOWN));
2691             }
2692         }
2693         setUserChoices(userChoices);
2694     }
2695 
2696     /**
2697      * Sets user choice for modules.
2698      *
2699      * @param userChoices User choices to store
2700      */
setUserChoices(List<AdServicesModuleUserChoice> userChoices)2701     public void setUserChoices(List<AdServicesModuleUserChoice> userChoices) {
2702         EnrollmentData data = EnrollmentData.deserialize(getModuleEnrollmentState());
2703         for (AdServicesModuleUserChoice userChoice : userChoices) {
2704             data.putUserChoice(userChoice);
2705         }
2706         setModuleEnrollmentData(EnrollmentData.serialize(data));
2707     }
2708 
2709     /** Sets module enrollment data to storage based on consent_source_of_truth. */
getModuleEnrollmentState()2710     public String getModuleEnrollmentState() {
2711         return executeGettersByConsentSourceOfTruth(
2712                 "",
2713                 () -> mDatastore.getString(ConsentConstants.MODULE_ENROLLMENT_STATE),
2714                 () -> mAdServicesManager.getModuleEnrollmentState(),
2715                 () -> mAppSearchConsentManager.getModuleEnrollmentState(),
2716                 /* errorLogger= */ null);
2717     }
2718 
2719     /** Set module enrollment data to storage based on consent_source_of_truth. */
setModuleEnrollmentData(String data)2720     void setModuleEnrollmentData(String data) {
2721         executeSettersByConsentSourceOfTruth(
2722                 () -> mDatastore.putString(ConsentConstants.MODULE_ENROLLMENT_STATE, data),
2723                 () -> mAdServicesManager.setModuleEnrollmentState(data),
2724                 () -> mAppSearchConsentManager.setModuleEnrollmentState(data),
2725                 /* errorLogger= */ null);
2726     }
2727 
convertEnrollmentChannelString( PrivacySandboxUxCollection ux, String enrollmentChannelString)2728     private PrivacySandboxEnrollmentChannelCollection convertEnrollmentChannelString(
2729             PrivacySandboxUxCollection ux, String enrollmentChannelString) {
2730         if (enrollmentChannelString == null) {
2731             return null;
2732         }
2733         return Stream.of(ux.getEnrollmentChannelCollection())
2734                 .filter(channel -> enrollmentChannelString.equals(channel.toString()))
2735                 .findFirst()
2736                 .orElse(null);
2737     }
2738 
2739     /** Returns current enrollment channel based on consent_source_of_truth. */
getEnrollmentChannel( PrivacySandboxUxCollection ux)2740     public PrivacySandboxEnrollmentChannelCollection getEnrollmentChannel(
2741             PrivacySandboxUxCollection ux) {
2742         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
2743             return ConsentManagerV2.getInstance().getEnrollmentChannel(ux);
2744         }
2745         return executeGettersByConsentSourceOfTruth(
2746                 /* defaultReturn= */ null,
2747                 () -> mUxStatesDao.getEnrollmentChannel(ux),
2748                 () -> convertEnrollmentChannelString(ux, mAdServicesManager.getEnrollmentChannel()),
2749                 () -> mAppSearchConsentManager.getEnrollmentChannel(ux),
2750                 /* errorLogger= */ null);
2751     }
2752 
2753     /** Set the current enrollment channel to storage based on consent_source_of_truth. */
setEnrollmentChannel( PrivacySandboxUxCollection ux, PrivacySandboxEnrollmentChannelCollection channel)2754     public void setEnrollmentChannel(
2755             PrivacySandboxUxCollection ux, PrivacySandboxEnrollmentChannelCollection channel) {
2756         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
2757             ConsentManagerV2.getInstance().setEnrollmentChannel(ux, channel);
2758             return;
2759         }
2760         executeSettersByConsentSourceOfTruth(
2761                 () -> mUxStatesDao.setEnrollmentChannel(ux, channel),
2762                 () -> mAdServicesManager.setEnrollmentChannel(channel.toString()),
2763                 () -> mAppSearchConsentManager.setEnrollmentChannel(ux, channel),
2764                 /* errorLogger= */ null);
2765     }
2766 
2767     /**
2768      * Gets PAS consent for fledge, pasUxEnable flag has checked is eea, thus we don't need to check
2769      * this again.
2770      */
isPasConsentGiven()2771     public boolean isPasConsentGiven() {
2772         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
2773             return ConsentManagerV2.getInstance().isPasFledgeConsentGiven();
2774         }
2775         if (mDebugFlags.getConsentManagerDebugMode()) {
2776             return true;
2777         }
2778         if (mFlags.getAdServicesConsentBusinessLogicMigrationEnabled()) {
2779             return getUserChoice(PROTECTED_AUDIENCE) == USER_CHOICE_OPTED_IN
2780                     && getUserChoice(PROTECTED_APP_SIGNALS) == USER_CHOICE_OPTED_IN;
2781         }
2782         if (mFlags.getEeaPasUxEnabled()) {
2783             if (DeviceRegionProvider.isEuDevice(ApplicationContextSingleton.get())) {
2784                 return wasPasNotificationOpened() && getConsent(AdServicesApiType.FLEDGE).isGiven();
2785             }
2786         }
2787 
2788         return mFlags.getPasUxEnabled()
2789                 && wasPasNotificationDisplayed()
2790                 && getConsent(AdServicesApiType.FLEDGE).isGiven();
2791     }
2792 
2793     /**
2794      * Gets ODP consent for fledge, pasUxEnable flag has checked is eea, thus we don't need to check
2795      * this again.
2796      */
isOdpFledgeConsentGiven()2797     public boolean isOdpFledgeConsentGiven() {
2798         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
2799             return ConsentManagerV2.getInstance().isPasFledgeConsentGiven();
2800         }
2801         if (mDebugFlags.getConsentManagerDebugMode()) {
2802             return true;
2803         }
2804         if (mFlags.getAdServicesConsentBusinessLogicMigrationEnabled()) {
2805             return getUserChoice(PROTECTED_AUDIENCE) == USER_CHOICE_OPTED_IN
2806                     && getUserChoice(ON_DEVICE_PERSONALIZATION) == USER_CHOICE_OPTED_IN;
2807         }
2808         if (mFlags.getEeaPasUxEnabled()) {
2809             if (DeviceRegionProvider.isEuDevice(ApplicationContextSingleton.get())) {
2810                 return wasPasNotificationOpened() && getConsent(AdServicesApiType.FLEDGE).isGiven();
2811             }
2812         }
2813 
2814         return mFlags.getPasUxEnabled()
2815                 && wasPasNotificationDisplayed()
2816                 && getConsent(AdServicesApiType.FLEDGE).isGiven();
2817     }
2818 
2819     /** Gets ODP consent for measurement. */
isOdpMeasurementConsentGiven()2820     public boolean isOdpMeasurementConsentGiven() {
2821         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
2822             return ConsentManagerV2.getInstance().isPasMeasurementConsentGiven();
2823         }
2824         if (mDebugFlags.getConsentManagerDebugMode()) {
2825             return true;
2826         }
2827         if (mFlags.getAdServicesConsentBusinessLogicMigrationEnabled()) {
2828             return getUserChoice(MEASUREMENT) == USER_CHOICE_OPTED_IN
2829                     && getUserChoice(ON_DEVICE_PERSONALIZATION) == USER_CHOICE_OPTED_IN;
2830         }
2831         if (mFlags.getEeaPasUxEnabled()) {
2832             if (DeviceRegionProvider.isEuDevice(ApplicationContextSingleton.get())) {
2833                 return wasPasNotificationOpened()
2834                         && getConsent(AdServicesApiType.MEASUREMENTS).isGiven();
2835             }
2836         }
2837         return mFlags.getPasUxEnabled()
2838                 && wasPasNotificationDisplayed()
2839                 && getConsent(AdServicesApiType.MEASUREMENTS).isGiven();
2840     }
2841 
2842     /**
2843      * Returns whether the measurement data reset activity happens based on consent_source_of_truth.
2844      */
isMeasurementDataReset()2845     public Boolean isMeasurementDataReset() {
2846         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
2847             return ConsentManagerV2.getInstance().isMeasurementDataReset();
2848         }
2849         return executeGettersByConsentSourceOfTruth(
2850                 /* defaultReturn= */ false,
2851                 () -> mDatastore.getBoolean(ConsentConstants.IS_MEASUREMENT_DATA_RESET),
2852                 () -> mAdServicesManager.isMeasurementDataReset(),
2853                 () -> mAppSearchConsentManager.isMeasurementDataReset(),
2854                 /* errorLogger= */ null);
2855     }
2856 
2857     /** Set the isMeasurementDataReset bit to storage based on consent_source_of_truth. */
setMeasurementDataReset(boolean isMeasurementDataReset)2858     public void setMeasurementDataReset(boolean isMeasurementDataReset) {
2859         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
2860             ConsentManagerV2.getInstance().setMeasurementDataReset(isMeasurementDataReset);
2861             return;
2862         }
2863         executeSettersByConsentSourceOfTruth(
2864                 () ->
2865                         mDatastore.putBoolean(
2866                                 ConsentConstants.IS_MEASUREMENT_DATA_RESET, isMeasurementDataReset),
2867                 () -> mAdServicesManager.setMeasurementDataReset(isMeasurementDataReset),
2868                 () -> mAppSearchConsentManager.setMeasurementDataReset(isMeasurementDataReset),
2869                 /* errorLogger= */ null);
2870     }
2871 
2872     /**
2873      * Returns whether the measurement data reset activity happens based on consent_source_of_truth.
2874      */
isPaDataReset()2875     public Boolean isPaDataReset() {
2876         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
2877             return ConsentManagerV2.getInstance().isPaDataReset();
2878         }
2879         return executeGettersByConsentSourceOfTruth(
2880                 /* defaultReturn= */ false,
2881                 () -> mDatastore.getBoolean(ConsentConstants.IS_PA_DATA_RESET),
2882                 () -> mAdServicesManager.isPaDataReset(),
2883                 () -> mAppSearchConsentManager.isPaDataReset(),
2884                 /* errorLogger= */ null);
2885     }
2886 
2887     /** Set the isPaDataReset bit to storage based on consent_source_of_truth. */
setPaDataReset(boolean isPaDataReset)2888     public void setPaDataReset(boolean isPaDataReset) {
2889         if (FlagsFactory.getFlags().getEnableConsentManagerV2()) {
2890             ConsentManagerV2.getInstance().setPaDataReset(isPaDataReset);
2891             return;
2892         }
2893         executeSettersByConsentSourceOfTruth(
2894                 () -> mDatastore.putBoolean(ConsentConstants.IS_PA_DATA_RESET, isPaDataReset),
2895                 () -> mAdServicesManager.setPaDataReset(isPaDataReset),
2896                 () -> mAppSearchConsentManager.setPaDataReset(isPaDataReset),
2897                 /* errorLogger= */ null);
2898     }
2899 
2900     /**
2901      * Returns whether the PAS notification was opened and the detailed PAS notification activity
2902      * was displayed.
2903      */
wasPasNotificationOpened()2904     public Boolean wasPasNotificationOpened() {
2905         return executeGettersByConsentSourceOfTruth(
2906                 /* defaultReturn= */ false,
2907                 () -> mDatastore.getBoolean(ConsentConstants.PAS_NOTIFICATION_OPENED),
2908                 () -> mAdServicesManager.wasPasNotificationOpened(),
2909                 () -> false,
2910                 /* errorLogger= */ null);
2911     }
2912 
2913     /** Set the isPaDataReset bit to storage based on consent_source_of_truth. */
recordPasNotificationOpened(boolean wasPasNotificationOpened)2914     public void recordPasNotificationOpened(boolean wasPasNotificationOpened) {
2915         executeSettersByConsentSourceOfTruth(
2916                 () ->
2917                         mDatastore.putBoolean(
2918                                 ConsentConstants.PAS_NOTIFICATION_OPENED, wasPasNotificationOpened),
2919                 () -> mAdServicesManager.recordPasNotificationOpened(wasPasNotificationOpened),
2920                 // APPSEARCH_ONLY is only set on S which has not implemented PAS updates.
2921                 () -> {
2922                     throw new IllegalStateException(
2923                             getAppSearchExceptionMessage(
2924                                     /* illegalAction */ "store if PAS notification was displayed"));
2925                 },
2926                 /* errorLogger= */ null);
2927     }
2928 
2929     /** Dump its internal state */
dump(PrintWriter writer, @Nullable String[] args)2930     public void dump(PrintWriter writer, @Nullable String[] args) {
2931         writer.println("ConsentManager");
2932         String prefix = "  ";
2933 
2934         writer.printf(
2935                 "%sSource of truth: %s\n",
2936                 prefix, consentSourceOfTruthToString(mConsentSourceOfTruth));
2937 
2938         writer.printf("%ssDataMigrationDuration: %dms\n", prefix, sDataMigrationDurationMs);
2939         writer.printf("%ssInstantiationDuration: %dms\n", prefix, sInstantiationDurationMs);
2940 
2941         writer.printf("%sDatastore:\n", prefix);
2942         String prefix2 = "    ";
2943         mDatastore.dump(writer, prefix2, /* args= */ null);
2944     }
2945 
2946     /** Returns a user-friendly representation of {@code source}. */
consentSourceOfTruthToString(@onsentSourceOfTruth int source)2947     public static String consentSourceOfTruthToString(@ConsentSourceOfTruth int source) {
2948         switch (source) {
2949             case Flags.SYSTEM_SERVER_ONLY:
2950                 return "SYSTEM_SERVER_ONLY";
2951             case Flags.PPAPI_ONLY:
2952                 return "PPAPI_ONLY";
2953             case Flags.PPAPI_AND_SYSTEM_SERVER:
2954                 return "PPAPI_AND_SYSTEM_SERVER";
2955             case Flags.APPSEARCH_ONLY:
2956                 return "APPSEARCH_ONLY";
2957             default:
2958                 return "UNKNOWN-" + source;
2959         }
2960     }
2961 
2962     @FunctionalInterface
2963     interface ThrowableSetter {
apply()2964         void apply() throws IOException, RuntimeException;
2965     }
2966 
2967     @FunctionalInterface
2968     interface ErrorLogger {
apply(Exception e)2969         void apply(Exception e);
2970     }
2971 
2972     /**
2973      * Generic setter that saves consent data to diffrerent data stores based on the consent source
2974      * of truth.
2975      *
2976      * @param appSetter Function that saves consent data to the app storage.
2977      * @param systemServiceSetter Function that saves consent data to the system server.
2978      * @param appSearchSetter Function that saves consent data to the appsearch.
2979      * @param errorLogger Function that logs exceptions during write operations.
2980      */
executeSettersByConsentSourceOfTruth( ThrowableSetter appSetter, ThrowableSetter systemServiceSetter, ThrowableSetter appSearchSetter, ErrorLogger errorLogger)2981     private void executeSettersByConsentSourceOfTruth(
2982             ThrowableSetter appSetter,
2983             ThrowableSetter systemServiceSetter, /* MUST pass lambdas instead of method
2984             references for back compat. */
2985             ThrowableSetter appSearchSetter, /* MUST pass lambdas instead of method references
2986             for back compat. */
2987             ErrorLogger errorLogger) {
2988         RbATraceProvider.beginSection(
2989                 CONSENT_MANAGER, CLASS_NAME_CONSENT_MANAGER, METHOD_NAME_SET_CONSENT, mFlags);
2990 
2991         mReadWriteLock.writeLock().lock();
2992         try {
2993             switch (mConsentSourceOfTruth) {
2994                 case Flags.PPAPI_ONLY:
2995                     appSetter.apply();
2996                     break;
2997                 case Flags.SYSTEM_SERVER_ONLY:
2998                     systemServiceSetter.apply();
2999                     break;
3000                 case Flags.PPAPI_AND_SYSTEM_SERVER:
3001                     appSetter.apply();
3002                     systemServiceSetter.apply();
3003                     break;
3004                 case Flags.APPSEARCH_ONLY:
3005                     if (mFlags.getEnableAppsearchConsentData()) {
3006                         appSearchSetter.apply();
3007                     }
3008                     break;
3009                 default:
3010                     throw new RuntimeException(
3011                             ConsentConstants.ERROR_MESSAGE_INVALID_CONSENT_SOURCE_OF_TRUTH);
3012             }
3013         } catch (IOException | RuntimeException e) {
3014             if (errorLogger != null) {
3015                 errorLogger.apply(e);
3016             }
3017             throw new RuntimeException(
3018                     getClass().getSimpleName() + " failed. " + e.getMessage(), e);
3019         } finally {
3020             mReadWriteLock.writeLock().unlock();
3021             RbATraceProvider.endSection(mFlags);
3022         }
3023     }
3024 
3025     @FunctionalInterface
3026     interface ThrowableGetter<T> {
apply()3027         T apply() throws IOException, RuntimeException;
3028     }
3029 
3030     /**
3031      * Generic getter that reads consent data from diffrerent data stores based on the consent
3032      * source of truth.
3033      *
3034      * @param defaultReturn Default return value.
3035      * @param appGetter Function that reads consent data from the app storage.
3036      * @param systemServiceGetter Function that reads consent data from the system server.
3037      * @param appSearchGetter Function that reads consent data from appsearch.
3038      * @param errorLogger Function that logs exceptions during read operations.
3039      */
executeGettersByConsentSourceOfTruth( T defaultReturn, ThrowableGetter<T> appGetter, ThrowableGetter<T> systemServiceGetter, ThrowableGetter<T> appSearchGetter, ErrorLogger errorLogger)3040     private <T> T executeGettersByConsentSourceOfTruth(
3041             T defaultReturn,
3042             ThrowableGetter<T> appGetter,
3043             ThrowableGetter<T> systemServiceGetter, /* MUST pass lambdas instead of method
3044             references for back compat. */
3045             ThrowableGetter<T> appSearchGetter, /* MUST pass lambdas instead of method references
3046             for back compat. */
3047             ErrorLogger errorLogger) {
3048         RbATraceProvider.beginSection(
3049                 CONSENT_MANAGER, CLASS_NAME_CONSENT_MANAGER, METHOD_NAME_GET_CONSENT, mFlags);
3050 
3051         mReadWriteLock.readLock().lock();
3052         try {
3053             switch (mConsentSourceOfTruth) {
3054                 case Flags.PPAPI_ONLY:
3055                     return appGetter.apply();
3056                 case Flags.SYSTEM_SERVER_ONLY:
3057                     // Intentional fallthrough.
3058                 case Flags.PPAPI_AND_SYSTEM_SERVER:
3059                     return systemServiceGetter.apply();
3060                 case Flags.APPSEARCH_ONLY:
3061                     if (mFlags.getEnableAppsearchConsentData()) {
3062                         return appSearchGetter.apply();
3063                     }
3064                     break;
3065                 default:
3066                     LogUtil.e(ConsentConstants.ERROR_MESSAGE_INVALID_CONSENT_SOURCE_OF_TRUTH);
3067                     return defaultReturn;
3068             }
3069         } catch (IOException | RuntimeException e) {
3070             if (errorLogger != null) {
3071                 errorLogger.apply(e);
3072             }
3073             LogUtil.e(getClass().getSimpleName() + " failed. " + e.getMessage());
3074         } finally {
3075             mReadWriteLock.readLock().unlock();
3076             RbATraceProvider.endSection(mFlags);
3077         }
3078 
3079         return defaultReturn;
3080     }
3081 
3082     /* Returns the region od the device */
getConsentRegion(Context context)3083     private static int getConsentRegion(Context context) {
3084         return DeviceRegionProvider.isEuDevice(context)
3085                 ? AD_SERVICES_SETTINGS_USAGE_REPORTED__REGION__EU
3086                 : AD_SERVICES_SETTINGS_USAGE_REPORTED__REGION__ROW;
3087     }
3088 
3089     /***
3090      * Returns an object of ConsentMigrationStats for logging
3091      *
3092      * @param appConsents AppConsents consents per API (fledge, msmt, topics, default)
3093      * @param migrationStatus Status of migration ( FAILURE, SUCCESS_WITH_SHARED_PREF_UPDATED,
3094      *                        SUCCESS_WITH_SHARED_PREF_NOT_UPDATED)
3095      * @param migrationType Type of migration ( PPAPI_TO_SYSTEM_SERVICE,
3096      *                      APPSEARCH_TO_SYSTEM_SERVICE,
3097      *                      ADEXT_SERVICE_TO_SYSTEM_SERVICE,
3098      *                      ADEXT_SERVICE_TO_APPSEARCH)
3099      * @param context Context of the application
3100      * @return consentMigrationStats returns ConsentMigrationStats for logging
3101      */
3102     // TODO(b/311183933): Remove passed in Context from static method.
3103     @SuppressWarnings("AvoidStaticContext")
getConsentManagerStatsForLogging( AppConsents appConsents, ConsentMigrationStats.MigrationStatus migrationStatus, ConsentMigrationStats.MigrationType migrationType, Context context)3104     public static ConsentMigrationStats getConsentManagerStatsForLogging(
3105             AppConsents appConsents,
3106             ConsentMigrationStats.MigrationStatus migrationStatus,
3107             ConsentMigrationStats.MigrationType migrationType,
3108             Context context) {
3109         ConsentMigrationStats consentMigrationStats =
3110                 ConsentMigrationStats.builder()
3111                         .setMigrationType(migrationType)
3112                         // When appConsents is null we log it as a failure
3113                         .setMigrationStatus(
3114                                 appConsents != null
3115                                         ? migrationStatus
3116                                         : ConsentMigrationStats.MigrationStatus.FAILURE)
3117                         .setMsmtConsent(appConsents == null || appConsents.getMsmtConsent())
3118                         .setTopicsConsent(appConsents == null || appConsents.getTopicsConsent())
3119                         .setFledgeConsent(appConsents == null || appConsents.getFledgeConsent())
3120                         .setRegion(getConsentRegion(context))
3121                         .build();
3122         return consentMigrationStats;
3123     }
3124 
getAppSearchExceptionMessage(String illegalAction)3125     private static String getAppSearchExceptionMessage(String illegalAction) {
3126         return String.format(
3127                 "Attempting to %s using APPSEARCH_ONLY consent source of truth!", illegalAction);
3128     }
3129 
3130     @SuppressWarnings("AvoidSharedPreferences") // Legacy usage
getPrefs(Context context)3131     private static SharedPreferences getPrefs(Context context) {
3132         return context.getSharedPreferences(
3133                 ConsentConstants.SHARED_PREFS_CONSENT, Context.MODE_PRIVATE);
3134     }
3135 }
3136