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.customaudience; 18 19 import static android.adservices.common.AdServicesStatusUtils.STATUS_BACKGROUND_CALLER; 20 import static android.adservices.common.AdServicesStatusUtils.STATUS_CALLER_NOT_ALLOWED; 21 import static android.adservices.common.AdServicesStatusUtils.STATUS_INTERNAL_ERROR; 22 import static android.adservices.common.AdServicesStatusUtils.STATUS_INVALID_ARGUMENT; 23 import static android.adservices.common.AdServicesStatusUtils.STATUS_RATE_LIMIT_REACHED; 24 import static android.adservices.common.AdServicesStatusUtils.STATUS_UNAUTHORIZED; 25 import static android.adservices.common.AdServicesStatusUtils.StatusCode; 26 27 import static com.android.adservices.service.common.Throttler.ApiKey.FLEDGE_API_JOIN_CUSTOM_AUDIENCE; 28 import static com.android.adservices.service.common.Throttler.ApiKey.FLEDGE_API_LEAVE_CUSTOM_AUDIENCE; 29 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__FETCH_AND_JOIN_CUSTOM_AUDIENCE; 30 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__JOIN_CUSTOM_AUDIENCE; 31 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__LEAVE_CUSTOM_AUDIENCE; 32 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__OVERRIDE_CUSTOM_AUDIENCE_REMOTE_INFO; 33 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__REMOVE_CUSTOM_AUDIENCE_REMOTE_INFO_OVERRIDE; 34 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__RESET_ALL_CUSTOM_AUDIENCE_OVERRIDES; 35 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__SCHEDULE_CUSTOM_AUDIENCE_UPDATE; 36 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_GET_CALLING_UID_ILLEGAL_STATE; 37 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_NOTIFY_FAILURE_BACKGROUND_CALLER; 38 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_NOTIFY_FAILURE_CALLER_NOT_ALLOWED; 39 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_NOTIFY_FAILURE_INTERNAL_ERROR; 40 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_NOTIFY_FAILURE_INVALID_ARGUMENT; 41 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_NOTIFY_FAILURE_RATE_LIMIT_REACHED; 42 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_NOTIFY_FAILURE_UNAUTHORIZED; 43 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_NOTIFY_SUCCESS_TO_CALLER_FAILED; 44 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_NULL_ARGUMENT; 45 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__FETCH_AND_JOIN_CUSTOM_AUDIENCE; 46 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__JOIN_CUSTOM_AUDIENCE; 47 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__LEAVE_CUSTOM_AUDIENCE; 48 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__SCHEDULE_CUSTOM_AUDIENCE_UPDATE; 49 50 import android.adservices.common.AdSelectionSignals; 51 import android.adservices.common.AdServicesPermissions; 52 import android.adservices.common.AdServicesStatusUtils; 53 import android.adservices.common.AdTechIdentifier; 54 import android.adservices.common.FledgeErrorResponse; 55 import android.adservices.customaudience.CustomAudience; 56 import android.adservices.customaudience.CustomAudienceOverrideCallback; 57 import android.adservices.customaudience.FetchAndJoinCustomAudienceCallback; 58 import android.adservices.customaudience.FetchAndJoinCustomAudienceInput; 59 import android.adservices.customaudience.ICustomAudienceCallback; 60 import android.adservices.customaudience.ICustomAudienceService; 61 import android.adservices.customaudience.ScheduleCustomAudienceUpdateCallback; 62 import android.adservices.customaudience.ScheduleCustomAudienceUpdateInput; 63 import android.annotation.NonNull; 64 import android.content.Context; 65 import android.os.Build; 66 import android.os.LimitExceededException; 67 import android.os.RemoteException; 68 69 import androidx.annotation.RequiresApi; 70 71 import com.android.adservices.LoggerFactory; 72 import com.android.adservices.concurrency.AdServicesExecutors; 73 import com.android.adservices.data.adselection.SharedStorageDatabase; 74 import com.android.adservices.data.customaudience.AdDataConversionStrategyFactory; 75 import com.android.adservices.data.customaudience.CustomAudienceDao; 76 import com.android.adservices.errorlogging.ErrorLogUtil; 77 import com.android.adservices.service.DebugFlags; 78 import com.android.adservices.service.Flags; 79 import com.android.adservices.service.FlagsFactory; 80 import com.android.adservices.service.adselection.AdFilteringFeatureFactory; 81 import com.android.adservices.service.common.AdRenderIdValidator; 82 import com.android.adservices.service.common.AppImportanceFilter; 83 import com.android.adservices.service.common.AppImportanceFilter.WrongCallingApplicationStateException; 84 import com.android.adservices.service.common.BinderFlagReader; 85 import com.android.adservices.service.common.CallingAppUidSupplier; 86 import com.android.adservices.service.common.CallingAppUidSupplierBinderImpl; 87 import com.android.adservices.service.common.CustomAudienceServiceFilter; 88 import com.android.adservices.service.common.FledgeAllowListsFilter; 89 import com.android.adservices.service.common.FledgeApiThrottleFilter; 90 import com.android.adservices.service.common.FledgeAuthorizationFilter; 91 import com.android.adservices.service.common.FledgeConsentFilter; 92 import com.android.adservices.service.common.Throttler; 93 import com.android.adservices.service.common.cache.CacheProviderFactory; 94 import com.android.adservices.service.common.httpclient.AdServicesHttpsClient; 95 import com.android.adservices.service.consent.ConsentManager; 96 import com.android.adservices.service.devapi.CustomAudienceOverrider; 97 import com.android.adservices.service.devapi.DevContext; 98 import com.android.adservices.service.devapi.DevContextFilter; 99 import com.android.adservices.service.stats.AdServicesLogger; 100 import com.android.adservices.service.stats.AdServicesLoggerImpl; 101 import com.android.adservices.service.stats.AdsRelevanceStatusUtils; 102 import com.android.internal.annotations.VisibleForTesting; 103 104 import java.time.Clock; 105 import java.util.Objects; 106 import java.util.concurrent.ExecutorService; 107 108 /** Implementation of the Custom Audience service. */ 109 @RequiresApi(Build.VERSION_CODES.S) 110 public class CustomAudienceServiceImpl extends ICustomAudienceService.Stub { 111 private static final LoggerFactory.Logger sLogger = LoggerFactory.getFledgeLogger(); 112 @NonNull private final Context mContext; 113 @NonNull private final CustomAudienceImpl mCustomAudienceImpl; 114 @NonNull private final FledgeAuthorizationFilter mFledgeAuthorizationFilter; 115 @NonNull private final ConsentManager mConsentManager; 116 @NonNull private final ExecutorService mExecutorService; 117 @NonNull private final DevContextFilter mDevContextFilter; 118 @NonNull private final AdServicesLogger mAdServicesLogger; 119 @NonNull private final AppImportanceFilter mAppImportanceFilter; 120 @NonNull private final Flags mFlags; 121 @NonNull private final DebugFlags mDebugFlags; 122 @NonNull private final CallingAppUidSupplier mCallingAppUidSupplier; 123 124 @NonNull private final CustomAudienceServiceFilter mCustomAudienceServiceFilter; 125 @NonNull private final AdFilteringFeatureFactory mAdFilteringFeatureFactory; 126 127 private static final String API_NOT_AUTHORIZED_MSG = 128 "This API is not enabled for the given app because either dev options are disabled or" 129 + " the app is not debuggable."; 130 CustomAudienceServiceImpl(@onNull Context context)131 private CustomAudienceServiceImpl(@NonNull Context context) { 132 this( 133 context, 134 CustomAudienceImpl.getInstance(), 135 FledgeAuthorizationFilter.create(context, AdServicesLoggerImpl.getInstance()), 136 ConsentManager.getInstance(), 137 DevContextFilter.create( 138 context, 139 BinderFlagReader.readFlag( 140 () -> 141 DebugFlags.getInstance() 142 .getDeveloperSessionFeatureEnabled())), 143 AdServicesExecutors.getBackgroundExecutor(), 144 AdServicesLoggerImpl.getInstance(), 145 AppImportanceFilter.create( 146 context, 147 () -> FlagsFactory.getFlags().getForegroundStatuslLevelForValidation()), 148 FlagsFactory.getFlags(), 149 DebugFlags.getInstance(), 150 CallingAppUidSupplierBinderImpl.create(), 151 new CustomAudienceServiceFilter( 152 context, 153 new FledgeConsentFilter( 154 ConsentManager.getInstance(), AdServicesLoggerImpl.getInstance()), 155 FlagsFactory.getFlags(), 156 AppImportanceFilter.create( 157 context, 158 () -> 159 FlagsFactory.getFlags() 160 .getForegroundStatuslLevelForValidation()), 161 FledgeAuthorizationFilter.create( 162 context, AdServicesLoggerImpl.getInstance()), 163 new FledgeAllowListsFilter( 164 FlagsFactory.getFlags(), AdServicesLoggerImpl.getInstance()), 165 new FledgeApiThrottleFilter( 166 Throttler.getInstance(), AdServicesLoggerImpl.getInstance())), 167 new AdFilteringFeatureFactory( 168 SharedStorageDatabase.getInstance().appInstallDao(), 169 SharedStorageDatabase.getInstance().frequencyCapDao(), 170 FlagsFactory.getFlags())); 171 } 172 173 /** Creates a new instance of {@link CustomAudienceServiceImpl}. */ 174 // TODO(b/311183933): Remove passed in Context from static method. 175 @SuppressWarnings("AvoidStaticContext") create(@onNull Context context)176 public static CustomAudienceServiceImpl create(@NonNull Context context) { 177 return new CustomAudienceServiceImpl(context); 178 } 179 180 @VisibleForTesting CustomAudienceServiceImpl( @onNull Context context, @NonNull CustomAudienceImpl customAudienceImpl, @NonNull FledgeAuthorizationFilter fledgeAuthorizationFilter, @NonNull ConsentManager consentManager, @NonNull DevContextFilter devContextFilter, @NonNull ExecutorService executorService, @NonNull AdServicesLogger adServicesLogger, @NonNull AppImportanceFilter appImportanceFilter, @NonNull Flags flags, @NonNull DebugFlags debugFlags, @NonNull CallingAppUidSupplier callingAppUidSupplier, @NonNull CustomAudienceServiceFilter customAudienceServiceFilter, @NonNull AdFilteringFeatureFactory adFilteringFeatureFactory)181 public CustomAudienceServiceImpl( 182 @NonNull Context context, 183 @NonNull CustomAudienceImpl customAudienceImpl, 184 @NonNull FledgeAuthorizationFilter fledgeAuthorizationFilter, 185 @NonNull ConsentManager consentManager, 186 @NonNull DevContextFilter devContextFilter, 187 @NonNull ExecutorService executorService, 188 @NonNull AdServicesLogger adServicesLogger, 189 @NonNull AppImportanceFilter appImportanceFilter, 190 @NonNull Flags flags, 191 @NonNull DebugFlags debugFlags, 192 @NonNull CallingAppUidSupplier callingAppUidSupplier, 193 @NonNull CustomAudienceServiceFilter customAudienceServiceFilter, 194 @NonNull AdFilteringFeatureFactory adFilteringFeatureFactory) { 195 Objects.requireNonNull(context); 196 Objects.requireNonNull(customAudienceImpl); 197 Objects.requireNonNull(fledgeAuthorizationFilter); 198 Objects.requireNonNull(consentManager); 199 Objects.requireNonNull(executorService); 200 Objects.requireNonNull(adServicesLogger); 201 Objects.requireNonNull(appImportanceFilter); 202 Objects.requireNonNull(customAudienceServiceFilter); 203 204 mContext = context; 205 mCustomAudienceImpl = customAudienceImpl; 206 mFledgeAuthorizationFilter = fledgeAuthorizationFilter; 207 mConsentManager = consentManager; 208 mDevContextFilter = devContextFilter; 209 mExecutorService = executorService; 210 mAdServicesLogger = adServicesLogger; 211 mAppImportanceFilter = appImportanceFilter; 212 mFlags = flags; 213 mDebugFlags = debugFlags; 214 mCallingAppUidSupplier = callingAppUidSupplier; 215 mCustomAudienceServiceFilter = customAudienceServiceFilter; 216 mAdFilteringFeatureFactory = adFilteringFeatureFactory; 217 } 218 219 /** 220 * Adds a user to a custom audience. 221 * 222 * @hide 223 */ 224 @Override joinCustomAudience( @onNull CustomAudience customAudience, @NonNull String ownerPackageName, @NonNull ICustomAudienceCallback callback)225 public void joinCustomAudience( 226 @NonNull CustomAudience customAudience, 227 @NonNull String ownerPackageName, 228 @NonNull ICustomAudienceCallback callback) { 229 sLogger.v("Entering joinCustomAudience"); 230 231 final int apiName = AD_SERVICES_API_CALLED__API_NAME__JOIN_CUSTOM_AUDIENCE; 232 233 try { 234 Objects.requireNonNull(customAudience); 235 Objects.requireNonNull(ownerPackageName); 236 Objects.requireNonNull(callback); 237 } catch (NullPointerException exception) { 238 mAdServicesLogger.logFledgeApiCallStats( 239 apiName, ownerPackageName, STATUS_INVALID_ARGUMENT, /* latencyMs= */ 0); 240 AdsRelevanceStatusUtils.logCelInsideBinderThread( 241 exception, 242 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_NULL_ARGUMENT, 243 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__JOIN_CUSTOM_AUDIENCE); 244 // Rethrow because we want to fail fast 245 throw exception; 246 } 247 248 // Caller permissions must be checked in the binder thread, before anything else 249 mFledgeAuthorizationFilter.assertAppDeclaredPermission( 250 mContext, 251 ownerPackageName, 252 apiName, 253 AdServicesPermissions.ACCESS_ADSERVICES_CUSTOM_AUDIENCE); 254 255 final int callerUid = getCallingUid(apiName, ownerPackageName); 256 final DevContext devContext = mDevContextFilter.createDevContext(); 257 sLogger.v("Running service"); 258 mExecutorService.execute( 259 () -> 260 doJoinCustomAudience( 261 customAudience, ownerPackageName, callback, callerUid, devContext)); 262 } 263 264 /** Try to join the custom audience and signal back to the caller using the callback. */ doJoinCustomAudience( @onNull CustomAudience customAudience, @NonNull String ownerPackageName, @NonNull ICustomAudienceCallback callback, final int callerUid, @NonNull final DevContext devContext)265 private void doJoinCustomAudience( 266 @NonNull CustomAudience customAudience, 267 @NonNull String ownerPackageName, 268 @NonNull ICustomAudienceCallback callback, 269 final int callerUid, 270 @NonNull final DevContext devContext) { 271 Objects.requireNonNull(customAudience); 272 Objects.requireNonNull(ownerPackageName); 273 Objects.requireNonNull(callback); 274 Objects.requireNonNull(devContext); 275 276 sLogger.v("Entering doJoinCustomAudience"); 277 278 final int apiName = AD_SERVICES_API_CALLED__API_NAME__JOIN_CUSTOM_AUDIENCE; 279 int resultCode = AdServicesStatusUtils.STATUS_UNSET; 280 // The filters log internally, so don't accidentally log again 281 boolean shouldLog = false; 282 try { 283 try { 284 // Filter and validate request 285 mCustomAudienceServiceFilter.filterRequest( 286 customAudience.getBuyer(), 287 ownerPackageName, 288 mFlags.getEnforceForegroundStatusForFledgeCustomAudience(), 289 false, 290 !mDebugFlags.getConsentNotificationDebugMode(), 291 callerUid, 292 apiName, 293 FLEDGE_API_JOIN_CUSTOM_AUDIENCE, 294 devContext); 295 296 shouldLog = true; 297 298 // Fail silently for revoked user consent 299 if (!mConsentManager.isFledgeConsentRevokedForAppAfterSettingFledgeUse( 300 ownerPackageName)) { 301 sLogger.v("Joining custom audience"); 302 mCustomAudienceImpl.joinCustomAudience( 303 customAudience, ownerPackageName, devContext); 304 BackgroundFetchJob.schedule(mFlags); 305 resultCode = AdServicesStatusUtils.STATUS_SUCCESS; 306 } else { 307 sLogger.v("Consent revoked"); 308 resultCode = AdServicesStatusUtils.STATUS_USER_CONSENT_REVOKED; 309 } 310 } catch (Exception exception) { 311 sLogger.d(exception, "Error encountered in joinCustomAudience, notifying caller"); 312 resultCode = 313 notifyFailure( 314 callback, 315 exception, 316 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__JOIN_CUSTOM_AUDIENCE); 317 return; 318 } 319 320 callback.onSuccess(); 321 } catch (Exception exception) { 322 sLogger.e(exception, "Unable to send result to the callback"); 323 resultCode = STATUS_INTERNAL_ERROR; 324 ErrorLogUtil.e( 325 exception, 326 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_NOTIFY_SUCCESS_TO_CALLER_FAILED, 327 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__JOIN_CUSTOM_AUDIENCE); 328 } finally { 329 if (shouldLog) { 330 mAdServicesLogger.logFledgeApiCallStats( 331 apiName, ownerPackageName, resultCode, /* latencyMs= */ 0); 332 } 333 } 334 } 335 336 /** 337 * Adds the user to the {@link CustomAudience} fetched from a {@code fetchUri} 338 * 339 * @hide 340 */ 341 @Override fetchAndJoinCustomAudience( @onNull FetchAndJoinCustomAudienceInput input, @NonNull FetchAndJoinCustomAudienceCallback callback)342 public void fetchAndJoinCustomAudience( 343 @NonNull FetchAndJoinCustomAudienceInput input, 344 @NonNull FetchAndJoinCustomAudienceCallback callback) { 345 sLogger.v("Executing fetchAndJoinCustomAudience."); 346 final int apiName = AD_SERVICES_API_CALLED__API_NAME__FETCH_AND_JOIN_CUSTOM_AUDIENCE; 347 348 // Failing fast if parameters are null. 349 try { 350 Objects.requireNonNull(input); 351 Objects.requireNonNull(callback); 352 } catch (NullPointerException exception) { 353 mAdServicesLogger.logFledgeApiCallStats( 354 apiName, STATUS_INVALID_ARGUMENT, /* latencyMs= */ 0); 355 AdsRelevanceStatusUtils.logCelInsideBinderThread( 356 exception, 357 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_NULL_ARGUMENT, 358 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__FETCH_AND_JOIN_CUSTOM_AUDIENCE); 359 // Rethrow because we want to fail fast 360 throw exception; 361 } 362 363 // Caller permissions must be checked in the binder thread, before anything else 364 mFledgeAuthorizationFilter.assertAppDeclaredPermission( 365 mContext, 366 input.getCallerPackageName(), 367 apiName, 368 AdServicesPermissions.ACCESS_ADSERVICES_CUSTOM_AUDIENCE); 369 370 final int callerUid = getCallingUid(apiName, input.getCallerPackageName()); 371 final DevContext devContext = mDevContextFilter.createDevContext(); 372 mExecutorService.execute( 373 () -> { 374 FetchCustomAudienceImpl impl = 375 new FetchCustomAudienceImpl( 376 mFlags, 377 mDebugFlags, 378 // TODO(b/235841960): Align on internal Clock usage. 379 Clock.systemUTC(), 380 mAdServicesLogger, 381 mExecutorService, 382 mCustomAudienceImpl.getCustomAudienceDao(), 383 callerUid, 384 mCustomAudienceServiceFilter, 385 new AdServicesHttpsClient( 386 AdServicesExecutors.getBlockingExecutor(), 387 CacheProviderFactory.createNoOpCache()), 388 mAdFilteringFeatureFactory.getFrequencyCapAdDataValidator(), 389 AdRenderIdValidator.createInstance(mFlags), 390 AdDataConversionStrategyFactory.getAdDataConversionStrategy( 391 mFlags.getFledgeFrequencyCapFilteringEnabled(), 392 mFlags.getFledgeAppInstallFilteringEnabled(), 393 mFlags.getFledgeAuctionServerAdRenderIdEnabled()), 394 ComponentAdsStrategy.createInstance( 395 mFlags.getEnableCustomAudienceComponentAds(), 396 new ComponentAdsListValidator( 397 mFlags.getComponentAdRenderIdMaxLengthBytes(), 398 mFlags.getMaxComponentAdsPerCustomAudience()))); 399 400 impl.doFetchCustomAudience(input, callback, devContext); 401 }); 402 } 403 notifyFailure( ICustomAudienceCallback callback, Exception exception, int celPpapiNameId)404 private int notifyFailure( 405 ICustomAudienceCallback callback, Exception exception, int celPpapiNameId) 406 throws RemoteException { 407 int resultCode; 408 if (exception instanceof NullPointerException 409 || exception instanceof IllegalArgumentException) { 410 resultCode = STATUS_INVALID_ARGUMENT; 411 } else if (exception instanceof WrongCallingApplicationStateException) { 412 resultCode = AdServicesStatusUtils.STATUS_BACKGROUND_CALLER; 413 } else if (exception instanceof FledgeAuthorizationFilter.CallerMismatchException) { 414 resultCode = AdServicesStatusUtils.STATUS_UNAUTHORIZED; 415 } else if (exception instanceof FledgeAuthorizationFilter.AdTechNotAllowedException 416 || exception instanceof FledgeAllowListsFilter.AppNotAllowedException) { 417 resultCode = AdServicesStatusUtils.STATUS_CALLER_NOT_ALLOWED; 418 } else if (exception instanceof LimitExceededException) { 419 resultCode = AdServicesStatusUtils.STATUS_RATE_LIMIT_REACHED; 420 } else if (exception instanceof IllegalStateException) { 421 resultCode = STATUS_INTERNAL_ERROR; 422 } else { 423 sLogger.e(exception, "Unexpected error during operation"); 424 resultCode = STATUS_INTERNAL_ERROR; 425 } 426 logExceptionCel(exception, resultCode, celPpapiNameId); 427 callback.onFailure( 428 new FledgeErrorResponse.Builder() 429 .setStatusCode(resultCode) 430 .setErrorMessage(exception.getMessage()) 431 .build()); 432 return resultCode; 433 } 434 435 @Override scheduleCustomAudienceUpdate( ScheduleCustomAudienceUpdateInput input, ScheduleCustomAudienceUpdateCallback callback)436 public void scheduleCustomAudienceUpdate( 437 ScheduleCustomAudienceUpdateInput input, 438 ScheduleCustomAudienceUpdateCallback callback) { 439 final int apiName = AD_SERVICES_API_CALLED__API_NAME__SCHEDULE_CUSTOM_AUDIENCE_UPDATE; 440 try { 441 Objects.requireNonNull(input); 442 Objects.requireNonNull(callback); 443 } catch (NullPointerException exception) { 444 mAdServicesLogger.logFledgeApiCallStats( 445 apiName, 446 input.getCallerPackageName(), 447 STATUS_INVALID_ARGUMENT, 448 /* latencyMs= */ 0); 449 AdsRelevanceStatusUtils.logCelInsideBinderThread( 450 exception, 451 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_NULL_ARGUMENT, 452 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__SCHEDULE_CUSTOM_AUDIENCE_UPDATE); 453 454 // Rethrow because we want to fail fast 455 throw exception; 456 } 457 458 // Caller permissions must be checked in the binder thread, before anything else 459 mFledgeAuthorizationFilter.assertAppDeclaredPermission( 460 mContext, 461 input.getCallerPackageName(), 462 apiName, 463 AdServicesPermissions.ACCESS_ADSERVICES_CUSTOM_AUDIENCE); 464 465 final int callerUid = getCallingUid(apiName, input.getCallerPackageName()); 466 final DevContext devContext = mDevContextFilter.createDevContext(); 467 468 mExecutorService.execute( 469 () -> { 470 ScheduleCustomAudienceUpdateImpl impl = 471 new ScheduleCustomAudienceUpdateImpl( 472 mContext, 473 mConsentManager, 474 callerUid, 475 mFlags, 476 mDebugFlags, 477 mAdServicesLogger, 478 AdServicesExecutors.getBackgroundExecutor(), 479 mCustomAudienceServiceFilter, 480 mCustomAudienceImpl.getCustomAudienceDao()); 481 482 impl.doScheduleCustomAudienceUpdate(input, callback, devContext); 483 }); 484 } 485 486 /** 487 * Attempts to remove a user from a custom audience. 488 * 489 * @hide 490 */ 491 @Override leaveCustomAudience( @onNull String ownerPackageName, @NonNull AdTechIdentifier buyer, @NonNull String name, @NonNull ICustomAudienceCallback callback)492 public void leaveCustomAudience( 493 @NonNull String ownerPackageName, 494 @NonNull AdTechIdentifier buyer, 495 @NonNull String name, 496 @NonNull ICustomAudienceCallback callback) { 497 final int apiName = AD_SERVICES_API_CALLED__API_NAME__LEAVE_CUSTOM_AUDIENCE; 498 499 try { 500 Objects.requireNonNull(ownerPackageName); 501 Objects.requireNonNull(buyer); 502 Objects.requireNonNull(name); 503 Objects.requireNonNull(callback); 504 } catch (NullPointerException exception) { 505 mAdServicesLogger.logFledgeApiCallStats( 506 apiName, ownerPackageName, STATUS_INVALID_ARGUMENT, /* latencyMs= */ 0); 507 AdsRelevanceStatusUtils.logCelInsideBinderThread( 508 exception, 509 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_NULL_ARGUMENT, 510 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__LEAVE_CUSTOM_AUDIENCE); 511 // Rethrow because we want to fail fast 512 throw exception; 513 } 514 515 // Caller permissions must be checked in the binder thread, before anything else 516 mFledgeAuthorizationFilter.assertAppDeclaredPermission( 517 mContext, 518 ownerPackageName, 519 apiName, 520 AdServicesPermissions.ACCESS_ADSERVICES_CUSTOM_AUDIENCE); 521 522 final int callerUid = getCallingUid(apiName, ownerPackageName); 523 final DevContext devContext = mDevContextFilter.createDevContext(); 524 mExecutorService.execute( 525 () -> 526 doLeaveCustomAudience( 527 ownerPackageName, buyer, name, callback, callerUid, devContext)); 528 } 529 530 /** Try to leave the custom audience and signal back to the caller using the callback. */ doLeaveCustomAudience( @onNull String ownerPackageName, @NonNull AdTechIdentifier buyer, @NonNull String name, @NonNull ICustomAudienceCallback callback, final int callerUid, @NonNull final DevContext devContext)531 private void doLeaveCustomAudience( 532 @NonNull String ownerPackageName, 533 @NonNull AdTechIdentifier buyer, 534 @NonNull String name, 535 @NonNull ICustomAudienceCallback callback, 536 final int callerUid, 537 @NonNull final DevContext devContext) { 538 Objects.requireNonNull(ownerPackageName); 539 Objects.requireNonNull(buyer); 540 Objects.requireNonNull(name); 541 Objects.requireNonNull(callback); 542 Objects.requireNonNull(devContext); 543 544 final int apiName = AD_SERVICES_API_CALLED__API_NAME__LEAVE_CUSTOM_AUDIENCE; 545 int resultCode = AdServicesStatusUtils.STATUS_UNSET; 546 // The filters log internally, so don't accidentally log again 547 boolean shouldLog = false; 548 try { 549 try { 550 // Filter and validate request 551 mCustomAudienceServiceFilter.filterRequest( 552 buyer, 553 ownerPackageName, 554 mFlags.getEnforceForegroundStatusForLeaveCustomAudience(), 555 false, 556 !mDebugFlags.getConsentNotificationDebugMode(), 557 callerUid, 558 apiName, 559 FLEDGE_API_LEAVE_CUSTOM_AUDIENCE, 560 devContext); 561 562 shouldLog = true; 563 564 // Fail silently for revoked user consent 565 if (!mConsentManager.isFledgeConsentRevokedForApp(ownerPackageName)) { 566 sLogger.v("Leaving custom audience"); 567 mCustomAudienceImpl.leaveCustomAudience(ownerPackageName, buyer, name); 568 resultCode = AdServicesStatusUtils.STATUS_SUCCESS; 569 } else { 570 sLogger.v("Consent revoked"); 571 resultCode = AdServicesStatusUtils.STATUS_USER_CONSENT_REVOKED; 572 } 573 } catch (WrongCallingApplicationStateException 574 | LimitExceededException 575 | FledgeAuthorizationFilter.CallerMismatchException 576 | FledgeAuthorizationFilter.AdTechNotAllowedException 577 | FledgeAllowListsFilter.AppNotAllowedException exception) { 578 // Catch these specific exceptions, but report them back to the caller 579 sLogger.d(exception, "Error encountered in leaveCustomAudience, notifying caller"); 580 resultCode = 581 notifyFailure( 582 callback, 583 exception, 584 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__LEAVE_CUSTOM_AUDIENCE); 585 return; 586 } catch (Exception exception) { 587 // For all other exceptions, report success 588 sLogger.e(exception, "Unexpected error leaving custom audience"); 589 resultCode = STATUS_INTERNAL_ERROR; 590 } 591 592 callback.onSuccess(); 593 } catch (Exception exception) { 594 sLogger.e(exception, "Unable to send result to the callback"); 595 resultCode = STATUS_INTERNAL_ERROR; 596 ErrorLogUtil.e( 597 exception, 598 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_NOTIFY_SUCCESS_TO_CALLER_FAILED, 599 AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__LEAVE_CUSTOM_AUDIENCE); 600 } finally { 601 if (shouldLog) { 602 mAdServicesLogger.logFledgeApiCallStats( 603 apiName, ownerPackageName, resultCode, /* latencyMs= */ 0); 604 } 605 } 606 } 607 608 /** 609 * Adds a custom audience override with the given information. 610 * 611 * <p>If the owner does not match the calling package name, fail silently. 612 * 613 * @hide 614 */ 615 @Override overrideCustomAudienceRemoteInfo( @onNull String owner, @NonNull AdTechIdentifier buyer, @NonNull String name, @NonNull String biddingLogicJS, long biddingLogicJsVersion, @NonNull AdSelectionSignals trustedBiddingSignals, @NonNull CustomAudienceOverrideCallback callback)616 public void overrideCustomAudienceRemoteInfo( 617 @NonNull String owner, 618 @NonNull AdTechIdentifier buyer, 619 @NonNull String name, 620 @NonNull String biddingLogicJS, 621 long biddingLogicJsVersion, 622 @NonNull AdSelectionSignals trustedBiddingSignals, 623 @NonNull CustomAudienceOverrideCallback callback) { 624 final int apiName = AD_SERVICES_API_CALLED__API_NAME__OVERRIDE_CUSTOM_AUDIENCE_REMOTE_INFO; 625 626 try { 627 Objects.requireNonNull(owner); 628 Objects.requireNonNull(buyer); 629 Objects.requireNonNull(name); 630 Objects.requireNonNull(biddingLogicJS); 631 Objects.requireNonNull(trustedBiddingSignals); 632 Objects.requireNonNull(callback); 633 } catch (NullPointerException exception) { 634 mAdServicesLogger.logFledgeApiCallStats( 635 apiName, STATUS_INVALID_ARGUMENT, /* latencyMs= */ 0); 636 // Rethrow to fail fast 637 throw exception; 638 } 639 640 DevContext devContext = mDevContextFilter.createDevContext(); 641 642 if (!devContext.getDeviceDevOptionsEnabled()) { 643 mAdServicesLogger.logFledgeApiCallStats( 644 apiName, 645 devContext.getCallingAppPackageName(), 646 STATUS_INTERNAL_ERROR, 647 /* latencyMs= */ 0); 648 throw new SecurityException(API_NOT_AUTHORIZED_MSG); 649 } 650 651 // Caller permissions must be checked with a non-null callingAppPackageName 652 mFledgeAuthorizationFilter.assertAppDeclaredPermission( 653 mContext, 654 devContext.getCallingAppPackageName(), 655 apiName, 656 AdServicesPermissions.ACCESS_ADSERVICES_CUSTOM_AUDIENCE); 657 658 CustomAudienceDao customAudienceDao = mCustomAudienceImpl.getCustomAudienceDao(); 659 660 CustomAudienceOverrider overrider = 661 new CustomAudienceOverrider( 662 devContext, 663 customAudienceDao, 664 mExecutorService, 665 mContext.getPackageManager(), 666 mConsentManager, 667 mAdServicesLogger, 668 mAppImportanceFilter, 669 mFlags); 670 671 overrider.addOverride( 672 owner, 673 buyer, 674 name, 675 biddingLogicJS, 676 biddingLogicJsVersion, 677 trustedBiddingSignals, 678 callback); 679 } 680 681 /** 682 * Removes a custom audience override with the given information. 683 * 684 * @hide 685 */ 686 @Override removeCustomAudienceRemoteInfoOverride( @onNull String owner, @NonNull AdTechIdentifier buyer, @NonNull String name, @NonNull CustomAudienceOverrideCallback callback)687 public void removeCustomAudienceRemoteInfoOverride( 688 @NonNull String owner, 689 @NonNull AdTechIdentifier buyer, 690 @NonNull String name, 691 @NonNull CustomAudienceOverrideCallback callback) { 692 final int apiName = 693 AD_SERVICES_API_CALLED__API_NAME__REMOVE_CUSTOM_AUDIENCE_REMOTE_INFO_OVERRIDE; 694 695 try { 696 Objects.requireNonNull(owner); 697 Objects.requireNonNull(buyer); 698 Objects.requireNonNull(name); 699 Objects.requireNonNull(callback); 700 } catch (NullPointerException exception) { 701 mAdServicesLogger.logFledgeApiCallStats( 702 apiName, STATUS_INVALID_ARGUMENT, /* latencyMs= */ 0); 703 // Rethrow to fail fast 704 throw exception; 705 } 706 707 DevContext devContext = mDevContextFilter.createDevContext(); 708 709 if (!devContext.getDeviceDevOptionsEnabled()) { 710 mAdServicesLogger.logFledgeApiCallStats( 711 apiName, 712 devContext.getCallingAppPackageName(), 713 STATUS_INTERNAL_ERROR, 714 /* latencyMs= */ 0); 715 throw new SecurityException(API_NOT_AUTHORIZED_MSG); 716 } 717 718 // Caller permissions must be checked with a non-null callingAppPackageName 719 mFledgeAuthorizationFilter.assertAppDeclaredPermission( 720 mContext, 721 devContext.getCallingAppPackageName(), 722 apiName, 723 AdServicesPermissions.ACCESS_ADSERVICES_CUSTOM_AUDIENCE); 724 725 CustomAudienceDao customAudienceDao = mCustomAudienceImpl.getCustomAudienceDao(); 726 727 CustomAudienceOverrider overrider = 728 new CustomAudienceOverrider( 729 devContext, 730 customAudienceDao, 731 mExecutorService, 732 mContext.getPackageManager(), 733 mConsentManager, 734 mAdServicesLogger, 735 mAppImportanceFilter, 736 mFlags); 737 738 overrider.removeOverride(owner, buyer, name, callback); 739 } 740 741 /** 742 * Resets all custom audience overrides for a given caller. 743 * 744 * @hide 745 */ 746 @Override resetAllCustomAudienceOverrides(@onNull CustomAudienceOverrideCallback callback)747 public void resetAllCustomAudienceOverrides(@NonNull CustomAudienceOverrideCallback callback) { 748 final int apiName = AD_SERVICES_API_CALLED__API_NAME__RESET_ALL_CUSTOM_AUDIENCE_OVERRIDES; 749 750 try { 751 Objects.requireNonNull(callback); 752 } catch (NullPointerException exception) { 753 mAdServicesLogger.logFledgeApiCallStats( 754 apiName, STATUS_INVALID_ARGUMENT, /* latencyMs= */ 0); 755 // Rethrow to fail fast 756 throw exception; 757 } 758 759 final int callerUid = getCallingUid(apiName); 760 761 DevContext devContext = mDevContextFilter.createDevContext(); 762 763 if (!devContext.getDeviceDevOptionsEnabled()) { 764 mAdServicesLogger.logFledgeApiCallStats( 765 apiName, 766 devContext.getCallingAppPackageName(), 767 STATUS_INTERNAL_ERROR, 768 /* latencyMs= */ 0); 769 throw new SecurityException(API_NOT_AUTHORIZED_MSG); 770 } 771 772 // Caller permissions must be checked with a non-null callingAppPackageName 773 mFledgeAuthorizationFilter.assertAppDeclaredPermission( 774 mContext, 775 devContext.getCallingAppPackageName(), 776 apiName, 777 AdServicesPermissions.ACCESS_ADSERVICES_CUSTOM_AUDIENCE); 778 779 CustomAudienceDao customAudienceDao = mCustomAudienceImpl.getCustomAudienceDao(); 780 781 CustomAudienceOverrider overrider = 782 new CustomAudienceOverrider( 783 devContext, 784 customAudienceDao, 785 mExecutorService, 786 mContext.getPackageManager(), 787 mConsentManager, 788 mAdServicesLogger, 789 mAppImportanceFilter, 790 mFlags); 791 792 overrider.removeAllOverrides(callback, callerUid); 793 } 794 getCallingUid(int apiNameLoggingId)795 private int getCallingUid(int apiNameLoggingId) throws IllegalStateException { 796 return getCallingUid(apiNameLoggingId, null); 797 } 798 getCallingUid(int apiNameLoggingId, String callerAppPackageName)799 private int getCallingUid(int apiNameLoggingId, String callerAppPackageName) 800 throws IllegalStateException { 801 try { 802 return mCallingAppUidSupplier.getCallingAppUid(); 803 } catch (IllegalStateException illegalStateException) { 804 mAdServicesLogger.logFledgeApiCallStats( 805 apiNameLoggingId, 806 callerAppPackageName, 807 STATUS_INTERNAL_ERROR, 808 /* latencyMs= */ 0); 809 AdsRelevanceStatusUtils.checkAndLogCelByApiNameLoggingId( 810 illegalStateException, 811 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_GET_CALLING_UID_ILLEGAL_STATE, 812 apiNameLoggingId); 813 throw illegalStateException; 814 } 815 } 816 logExceptionCel( Exception exception, @StatusCode int resultCode, int celPpapiNameId)817 private void logExceptionCel( 818 Exception exception, @StatusCode int resultCode, int celPpapiNameId) { 819 int celEnum = 820 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_NOTIFY_FAILURE_INTERNAL_ERROR; 821 switch (resultCode) { 822 case STATUS_INVALID_ARGUMENT: 823 celEnum = 824 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_NOTIFY_FAILURE_INVALID_ARGUMENT; 825 break; 826 case STATUS_BACKGROUND_CALLER: 827 celEnum = 828 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_NOTIFY_FAILURE_BACKGROUND_CALLER; 829 break; 830 case STATUS_CALLER_NOT_ALLOWED: 831 celEnum = 832 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_NOTIFY_FAILURE_CALLER_NOT_ALLOWED; 833 break; 834 case STATUS_UNAUTHORIZED: 835 celEnum = 836 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_NOTIFY_FAILURE_UNAUTHORIZED; 837 break; 838 case STATUS_RATE_LIMIT_REACHED: 839 celEnum = 840 AD_SERVICES_ERROR_REPORTED__ERROR_CODE__CUSTOM_AUDIENCE_SERVICE_NOTIFY_FAILURE_RATE_LIMIT_REACHED; 841 break; 842 } 843 ErrorLogUtil.e(exception, celEnum, celPpapiNameId); 844 } 845 } 846