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