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 android.adservices.adselection; 18 19 import static android.adservices.common.AdServicesPermissions.ACCESS_ADSERVICES_AD_SELECTION; 20 import static android.adservices.common.AdServicesPermissions.ACCESS_ADSERVICES_CUSTOM_AUDIENCE; 21 import static android.adservices.common.AdServicesPermissions.ACCESS_ADSERVICES_PROTECTED_SIGNALS; 22 23 import android.adservices.common.AdServicesStatusUtils; 24 import android.adservices.common.FledgeErrorResponse; 25 import android.annotation.CallbackExecutor; 26 import android.annotation.NonNull; 27 import android.annotation.RequiresPermission; 28 import android.os.Build; 29 import android.os.OutcomeReceiver; 30 import android.os.RemoteException; 31 32 import androidx.annotation.RequiresApi; 33 34 import com.android.adservices.LoggerFactory; 35 36 import java.util.Objects; 37 import java.util.concurrent.Executor; 38 39 /** 40 * {@link TestAdSelectionManager} provides APIs for apps and ad SDKs to test ad selection processes. 41 * 42 * <p>These APIs are intended to be used for end-to-end testing. They are enabled only for 43 * debuggable apps on phones running a debuggable OS build with developer options enabled. 44 */ 45 @RequiresApi(Build.VERSION_CODES.S) 46 public class TestAdSelectionManager { 47 private static final LoggerFactory.Logger sLogger = LoggerFactory.getFledgeLogger(); 48 49 private final AdSelectionManager mAdSelectionManager; 50 TestAdSelectionManager(@onNull AdSelectionManager adSelectionManager)51 TestAdSelectionManager(@NonNull AdSelectionManager adSelectionManager) { 52 Objects.requireNonNull(adSelectionManager); 53 54 mAdSelectionManager = adSelectionManager; 55 } 56 57 // TODO(b/289362476): Add override APIs for server auction key fetch 58 59 /** 60 * Overrides the AdSelection API for a given {@link AdSelectionConfig} to avoid fetching data 61 * from remote servers and use the data provided in {@link AddAdSelectionOverrideRequest} 62 * instead. The {@link AddAdSelectionOverrideRequest} is provided by the Ads SDK. 63 * 64 * <p>This method is intended to be used for end-to-end testing. This API is enabled only for 65 * apps in debug mode with developer options enabled. 66 * 67 * @throws IllegalStateException if this API is not enabled for the caller 68 * <p>The receiver either returns a {@code void} for a successful run, or an {@link 69 * Exception} indicates the error. 70 */ 71 @RequiresPermission( 72 anyOf = { 73 ACCESS_ADSERVICES_CUSTOM_AUDIENCE, 74 ACCESS_ADSERVICES_PROTECTED_SIGNALS, 75 ACCESS_ADSERVICES_AD_SELECTION 76 }) overrideAdSelectionConfigRemoteInfo( @onNull AddAdSelectionOverrideRequest request, @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Object, Exception> receiver)77 public void overrideAdSelectionConfigRemoteInfo( 78 @NonNull AddAdSelectionOverrideRequest request, 79 @NonNull @CallbackExecutor Executor executor, 80 @NonNull OutcomeReceiver<Object, Exception> receiver) { 81 Objects.requireNonNull(request); 82 Objects.requireNonNull(executor); 83 Objects.requireNonNull(receiver); 84 85 try { 86 final AdSelectionService service = 87 mAdSelectionManager.getServiceProvider().getService(); 88 service.overrideAdSelectionConfigRemoteInfo( 89 request.getAdSelectionConfig(), 90 request.getDecisionLogicJs(), 91 request.getTrustedScoringSignals(), 92 request.getPerBuyerDecisionLogic(), 93 new AdSelectionOverrideCallback.Stub() { 94 @Override 95 public void onSuccess() { 96 executor.execute(() -> receiver.onResult(new Object())); 97 } 98 99 @Override 100 public void onFailure(FledgeErrorResponse failureParcel) { 101 executor.execute( 102 () -> 103 receiver.onError( 104 AdServicesStatusUtils.asException( 105 failureParcel))); 106 } 107 }); 108 } catch (NullPointerException e) { 109 sLogger.e(e, "Unable to find the AdSelection service."); 110 receiver.onError( 111 new IllegalStateException("Unable to find the AdSelection service.", e)); 112 } catch (RemoteException e) { 113 sLogger.e(e, "Exception"); 114 receiver.onError(new IllegalStateException("Failure of AdSelection service.", e)); 115 } 116 } 117 118 /** 119 * Removes an override for {@link AdSelectionConfig} in the Ad Selection API with associated the 120 * data in {@link RemoveAdSelectionOverrideRequest}. The {@link 121 * RemoveAdSelectionOverrideRequest} is provided by the Ads SDK. 122 * 123 * <p>This method is intended to be used for end-to-end testing. This API is enabled only for 124 * apps in debug mode with developer options enabled. 125 * 126 * @throws IllegalStateException if this API is not enabled for the caller 127 * <p>The receiver either returns a {@code void} for a successful run, or an {@link 128 * Exception} indicates the error. 129 */ 130 @RequiresPermission( 131 anyOf = { 132 ACCESS_ADSERVICES_CUSTOM_AUDIENCE, 133 ACCESS_ADSERVICES_PROTECTED_SIGNALS, 134 ACCESS_ADSERVICES_AD_SELECTION 135 }) removeAdSelectionConfigRemoteInfoOverride( @onNull RemoveAdSelectionOverrideRequest request, @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Object, Exception> receiver)136 public void removeAdSelectionConfigRemoteInfoOverride( 137 @NonNull RemoveAdSelectionOverrideRequest request, 138 @NonNull @CallbackExecutor Executor executor, 139 @NonNull OutcomeReceiver<Object, Exception> receiver) { 140 Objects.requireNonNull(request); 141 Objects.requireNonNull(executor); 142 Objects.requireNonNull(receiver); 143 144 try { 145 final AdSelectionService service = 146 mAdSelectionManager.getServiceProvider().getService(); 147 service.removeAdSelectionConfigRemoteInfoOverride( 148 request.getAdSelectionConfig(), 149 new AdSelectionOverrideCallback.Stub() { 150 @Override 151 public void onSuccess() { 152 executor.execute(() -> receiver.onResult(new Object())); 153 } 154 155 @Override 156 public void onFailure(FledgeErrorResponse failureParcel) { 157 executor.execute( 158 () -> 159 receiver.onError( 160 AdServicesStatusUtils.asException( 161 failureParcel))); 162 } 163 }); 164 } catch (NullPointerException e) { 165 sLogger.e(e, "Unable to find the AdSelection service."); 166 receiver.onError( 167 new IllegalStateException("Unable to find the AdSelection service.", e)); 168 } catch (RemoteException e) { 169 sLogger.e(e, "Exception"); 170 receiver.onError(new IllegalStateException("Failure of AdSelection service.", e)); 171 } 172 } 173 174 /** 175 * Removes all override data for {@link AdSelectionConfig} in the Ad Selection API. 176 * 177 * <p>This method is intended to be used for end-to-end testing. This API is enabled only for 178 * apps in debug mode with developer options enabled. 179 * 180 * @throws IllegalStateException if this API is not enabled for the caller 181 * <p>The receiver either returns a {@code void} for a successful run, or an {@link 182 * Exception} indicates the error. 183 */ 184 @RequiresPermission( 185 anyOf = { 186 ACCESS_ADSERVICES_CUSTOM_AUDIENCE, 187 ACCESS_ADSERVICES_PROTECTED_SIGNALS, 188 ACCESS_ADSERVICES_AD_SELECTION 189 }) resetAllAdSelectionConfigRemoteOverrides( @onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Object, Exception> receiver)190 public void resetAllAdSelectionConfigRemoteOverrides( 191 @NonNull @CallbackExecutor Executor executor, 192 @NonNull OutcomeReceiver<Object, Exception> receiver) { 193 Objects.requireNonNull(executor); 194 Objects.requireNonNull(receiver); 195 196 try { 197 final AdSelectionService service = 198 mAdSelectionManager.getServiceProvider().getService(); 199 service.resetAllAdSelectionConfigRemoteOverrides( 200 new AdSelectionOverrideCallback.Stub() { 201 @Override 202 public void onSuccess() { 203 executor.execute(() -> receiver.onResult(new Object())); 204 } 205 206 @Override 207 public void onFailure(FledgeErrorResponse failureParcel) { 208 executor.execute( 209 () -> 210 receiver.onError( 211 AdServicesStatusUtils.asException( 212 failureParcel))); 213 } 214 }); 215 } catch (NullPointerException e) { 216 sLogger.e(e, "Unable to find the AdSelection service."); 217 receiver.onError( 218 new IllegalStateException("Unable to find the AdSelection service.", e)); 219 } catch (RemoteException e) { 220 sLogger.e(e, "Exception"); 221 receiver.onError(new IllegalStateException("Failure of AdSelection service.", e)); 222 } 223 } 224 225 /** 226 * Overrides the AdSelection API for {@link AdSelectionFromOutcomesConfig} to avoid fetching 227 * data from remote servers and use the data provided in {@link 228 * AddAdSelectionFromOutcomesOverrideRequest} instead. The {@link 229 * AddAdSelectionFromOutcomesOverrideRequest} is provided by the Ads SDK. 230 * 231 * <p>This method is intended to be used for end-to-end testing. This API is enabled only for 232 * apps in debug mode with developer options enabled. 233 * 234 * @throws IllegalStateException if this API is not enabled for the caller 235 * <p>The receiver either returns a {@code void} for a successful run, or an {@link 236 * Exception} indicates the error. 237 */ 238 @RequiresPermission( 239 anyOf = { 240 ACCESS_ADSERVICES_CUSTOM_AUDIENCE, 241 ACCESS_ADSERVICES_PROTECTED_SIGNALS, 242 ACCESS_ADSERVICES_AD_SELECTION 243 }) overrideAdSelectionFromOutcomesConfigRemoteInfo( @onNull AddAdSelectionFromOutcomesOverrideRequest request, @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Object, Exception> receiver)244 public void overrideAdSelectionFromOutcomesConfigRemoteInfo( 245 @NonNull AddAdSelectionFromOutcomesOverrideRequest request, 246 @NonNull @CallbackExecutor Executor executor, 247 @NonNull OutcomeReceiver<Object, Exception> receiver) { 248 Objects.requireNonNull(request); 249 Objects.requireNonNull(executor); 250 Objects.requireNonNull(receiver); 251 252 try { 253 final AdSelectionService service = 254 mAdSelectionManager.getServiceProvider().getService(); 255 service.overrideAdSelectionFromOutcomesConfigRemoteInfo( 256 request.getAdSelectionFromOutcomesConfig(), 257 request.getOutcomeSelectionLogicJs(), 258 request.getOutcomeSelectionTrustedSignals(), 259 new AdSelectionOverrideCallback.Stub() { 260 @Override 261 public void onSuccess() { 262 executor.execute(() -> receiver.onResult(new Object())); 263 } 264 265 @Override 266 public void onFailure(FledgeErrorResponse failureParcel) { 267 executor.execute( 268 () -> 269 receiver.onError( 270 AdServicesStatusUtils.asException( 271 failureParcel))); 272 } 273 }); 274 } catch (NullPointerException e) { 275 sLogger.e(e, "Unable to find the AdSelection service."); 276 receiver.onError( 277 new IllegalStateException("Unable to find the AdSelection service.", e)); 278 } catch (RemoteException e) { 279 sLogger.e(e, "Exception"); 280 receiver.onError(new IllegalStateException("Failure of AdSelection service.", e)); 281 } 282 } 283 284 /** 285 * Removes an override for {@link AdSelectionFromOutcomesConfig} in th Ad Selection API with 286 * associated the data in {@link RemoveAdSelectionOverrideRequest}. The {@link 287 * RemoveAdSelectionOverrideRequest} is provided by the Ads SDK. 288 * 289 * <p>This method is intended to be used for end-to-end testing. This API is enabled only for 290 * apps in debug mode with developer options enabled. 291 * 292 * @throws IllegalStateException if this API is not enabled for the caller 293 * <p>The receiver either returns a {@code void} for a successful run, or an {@link 294 * Exception} indicates the error. 295 */ 296 @RequiresPermission( 297 anyOf = { 298 ACCESS_ADSERVICES_CUSTOM_AUDIENCE, 299 ACCESS_ADSERVICES_PROTECTED_SIGNALS, 300 ACCESS_ADSERVICES_AD_SELECTION 301 }) removeAdSelectionFromOutcomesConfigRemoteInfoOverride( @onNull RemoveAdSelectionFromOutcomesOverrideRequest request, @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Object, Exception> receiver)302 public void removeAdSelectionFromOutcomesConfigRemoteInfoOverride( 303 @NonNull RemoveAdSelectionFromOutcomesOverrideRequest request, 304 @NonNull @CallbackExecutor Executor executor, 305 @NonNull OutcomeReceiver<Object, Exception> receiver) { 306 Objects.requireNonNull(request); 307 Objects.requireNonNull(executor); 308 Objects.requireNonNull(receiver); 309 310 try { 311 final AdSelectionService service = 312 mAdSelectionManager.getServiceProvider().getService(); 313 service.removeAdSelectionFromOutcomesConfigRemoteInfoOverride( 314 request.getAdSelectionFromOutcomesConfig(), 315 new AdSelectionOverrideCallback.Stub() { 316 @Override 317 public void onSuccess() { 318 executor.execute(() -> receiver.onResult(new Object())); 319 } 320 321 @Override 322 public void onFailure(FledgeErrorResponse failureParcel) { 323 executor.execute( 324 () -> 325 receiver.onError( 326 AdServicesStatusUtils.asException( 327 failureParcel))); 328 } 329 }); 330 } catch (NullPointerException e) { 331 sLogger.e(e, "Unable to find the AdSelection service."); 332 receiver.onError( 333 new IllegalStateException("Unable to find the AdSelection service.", e)); 334 } catch (RemoteException e) { 335 sLogger.e(e, "Exception"); 336 receiver.onError(new IllegalStateException("Failure of AdSelection service.", e)); 337 } 338 } 339 340 /** 341 * Removes all override data for {@link AdSelectionFromOutcomesConfig} in the Ad Selection API. 342 * 343 * <p>This method is intended to be used for end-to-end testing. This API is enabled only for 344 * apps in debug mode with developer options enabled. 345 * 346 * @throws IllegalStateException if this API is not enabled for the caller 347 * <p>The receiver either returns a {@code void} for a successful run, or an {@link 348 * Exception} indicates the error. 349 */ 350 @RequiresPermission( 351 anyOf = { 352 ACCESS_ADSERVICES_CUSTOM_AUDIENCE, 353 ACCESS_ADSERVICES_PROTECTED_SIGNALS, 354 ACCESS_ADSERVICES_AD_SELECTION 355 }) resetAllAdSelectionFromOutcomesConfigRemoteOverrides( @onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Object, Exception> receiver)356 public void resetAllAdSelectionFromOutcomesConfigRemoteOverrides( 357 @NonNull @CallbackExecutor Executor executor, 358 @NonNull OutcomeReceiver<Object, Exception> receiver) { 359 Objects.requireNonNull(executor); 360 Objects.requireNonNull(receiver); 361 362 try { 363 final AdSelectionService service = 364 mAdSelectionManager.getServiceProvider().getService(); 365 service.resetAllAdSelectionFromOutcomesConfigRemoteOverrides( 366 new AdSelectionOverrideCallback.Stub() { 367 @Override 368 public void onSuccess() { 369 executor.execute(() -> receiver.onResult(new Object())); 370 } 371 372 @Override 373 public void onFailure(FledgeErrorResponse failureParcel) { 374 executor.execute( 375 () -> 376 receiver.onError( 377 AdServicesStatusUtils.asException( 378 failureParcel))); 379 } 380 }); 381 } catch (NullPointerException e) { 382 sLogger.e(e, "Unable to find the AdSelection service."); 383 receiver.onError( 384 new IllegalStateException("Unable to find the AdSelection service.", e)); 385 } catch (RemoteException e) { 386 sLogger.e(e, "Exception"); 387 receiver.onError(new IllegalStateException("Failure of AdSelection service.", e)); 388 } 389 } 390 391 /** 392 * Sets the override for event histogram data, which is used in frequency cap filtering during 393 * ad selection. 394 * 395 * <p>This method is intended to be used for end-to-end testing. This API is enabled only for 396 * apps in debug mode with developer options enabled. 397 * 398 * <p>The given {@code outcomeReceiver} either returns an empty {@link Object} if successful or 399 * an {@link Exception} which indicates the error. 400 * 401 * @throws IllegalStateException if this API is not enabled for the caller 402 * @hide 403 */ 404 // TODO(b/265204820): Unhide for frequency cap dev override API review 405 @RequiresPermission( 406 anyOf = { 407 ACCESS_ADSERVICES_CUSTOM_AUDIENCE, 408 ACCESS_ADSERVICES_PROTECTED_SIGNALS, 409 ACCESS_ADSERVICES_AD_SELECTION 410 }) setAdCounterHistogramOverride( @onNull SetAdCounterHistogramOverrideRequest setRequest, @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Object, Exception> outcomeReceiver)411 public void setAdCounterHistogramOverride( 412 @NonNull SetAdCounterHistogramOverrideRequest setRequest, 413 @NonNull @CallbackExecutor Executor executor, 414 @NonNull OutcomeReceiver<Object, Exception> outcomeReceiver) { 415 Objects.requireNonNull(setRequest, "Request must not be null"); 416 Objects.requireNonNull(executor, "Executor must not be null"); 417 Objects.requireNonNull(outcomeReceiver, "Outcome receiver must not be null"); 418 419 try { 420 final AdSelectionService service = 421 Objects.requireNonNull(mAdSelectionManager.getServiceProvider().getService()); 422 service.setAdCounterHistogramOverride( 423 new SetAdCounterHistogramOverrideInput.Builder() 424 .setAdEventType(setRequest.getAdEventType()) 425 .setAdCounterKey(setRequest.getAdCounterKey()) 426 .setHistogramTimestamps(setRequest.getHistogramTimestamps()) 427 .setBuyer(setRequest.getBuyer()) 428 .setCustomAudienceOwner(setRequest.getCustomAudienceOwner()) 429 .setCustomAudienceName(setRequest.getCustomAudienceName()) 430 .build(), 431 new AdSelectionOverrideCallback.Stub() { 432 @Override 433 public void onSuccess() { 434 executor.execute(() -> outcomeReceiver.onResult(new Object())); 435 } 436 437 @Override 438 public void onFailure(FledgeErrorResponse failureParcel) { 439 executor.execute( 440 () -> 441 outcomeReceiver.onError( 442 AdServicesStatusUtils.asException( 443 failureParcel))); 444 } 445 }); 446 } catch (NullPointerException e) { 447 sLogger.e(e, "Unable to find the AdSelection service"); 448 outcomeReceiver.onError( 449 new IllegalStateException("Unable to find the AdSelection service", e)); 450 } catch (RemoteException e) { 451 sLogger.e(e, "Remote exception encountered while updating ad counter histogram"); 452 outcomeReceiver.onError(new IllegalStateException("Failure of AdSelection service", e)); 453 } 454 } 455 456 /** 457 * Removes an override for event histogram data, which is used in frequency cap filtering during 458 * ad selection. 459 * 460 * <p>This method is intended to be used for end-to-end testing. This API is enabled only for 461 * apps in debug mode with developer options enabled. 462 * 463 * <p>The given {@code outcomeReceiver} either returns an empty {@link Object} if successful or 464 * an {@link Exception} which indicates the error. 465 * 466 * @throws IllegalStateException if this API is not enabled for the caller 467 * @hide 468 */ 469 // TODO(b/265204820): Unhide for frequency cap dev override API review 470 @RequiresPermission( 471 anyOf = { 472 ACCESS_ADSERVICES_CUSTOM_AUDIENCE, 473 ACCESS_ADSERVICES_PROTECTED_SIGNALS, 474 ACCESS_ADSERVICES_AD_SELECTION 475 }) removeAdCounterHistogramOverride( @onNull RemoveAdCounterHistogramOverrideRequest removeRequest, @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Object, Exception> outcomeReceiver)476 public void removeAdCounterHistogramOverride( 477 @NonNull RemoveAdCounterHistogramOverrideRequest removeRequest, 478 @NonNull @CallbackExecutor Executor executor, 479 @NonNull OutcomeReceiver<Object, Exception> outcomeReceiver) { 480 Objects.requireNonNull(removeRequest, "Request must not be null"); 481 Objects.requireNonNull(executor, "Executor must not be null"); 482 Objects.requireNonNull(outcomeReceiver, "Outcome receiver must not be null"); 483 484 try { 485 final AdSelectionService service = 486 Objects.requireNonNull(mAdSelectionManager.getServiceProvider().getService()); 487 service.removeAdCounterHistogramOverride( 488 new RemoveAdCounterHistogramOverrideInput.Builder() 489 .setAdEventType(removeRequest.getAdEventType()) 490 .setAdCounterKey(removeRequest.getAdCounterKey()) 491 .setBuyer(removeRequest.getBuyer()) 492 .build(), 493 new AdSelectionOverrideCallback.Stub() { 494 @Override 495 public void onSuccess() { 496 executor.execute(() -> outcomeReceiver.onResult(new Object())); 497 } 498 499 @Override 500 public void onFailure(FledgeErrorResponse failureParcel) { 501 executor.execute( 502 () -> 503 outcomeReceiver.onError( 504 AdServicesStatusUtils.asException( 505 failureParcel))); 506 } 507 }); 508 } catch (NullPointerException e) { 509 sLogger.e(e, "Unable to find the AdSelection service"); 510 outcomeReceiver.onError( 511 new IllegalStateException("Unable to find the AdSelection service", e)); 512 } catch (RemoteException e) { 513 sLogger.e(e, "Remote exception encountered while updating ad counter histogram"); 514 outcomeReceiver.onError(new IllegalStateException("Failure of AdSelection service", e)); 515 } 516 } 517 518 /** 519 * Removes all previously set histogram overrides used in ad selection which were set by the 520 * caller application. 521 * 522 * <p>This method is intended to be used for end-to-end testing. This API is enabled only for 523 * apps in debug mode with developer options enabled. 524 * 525 * <p>The given {@code outcomeReceiver} either returns an empty {@link Object} if successful or 526 * an {@link Exception} which indicates the error. 527 * 528 * @throws IllegalStateException if this API is not enabled for the caller 529 * @hide 530 */ 531 // TODO(b/265204820): Unhide for frequency cap dev override API review 532 @RequiresPermission( 533 anyOf = { 534 ACCESS_ADSERVICES_CUSTOM_AUDIENCE, 535 ACCESS_ADSERVICES_PROTECTED_SIGNALS, 536 ACCESS_ADSERVICES_AD_SELECTION 537 }) resetAllAdCounterHistogramOverrides( @onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Object, Exception> outcomeReceiver)538 public void resetAllAdCounterHistogramOverrides( 539 @NonNull @CallbackExecutor Executor executor, 540 @NonNull OutcomeReceiver<Object, Exception> outcomeReceiver) { 541 Objects.requireNonNull(executor, "Executor must not be null"); 542 Objects.requireNonNull(outcomeReceiver, "Outcome receiver must not be null"); 543 544 try { 545 final AdSelectionService service = 546 Objects.requireNonNull(mAdSelectionManager.getServiceProvider().getService()); 547 service.resetAllAdCounterHistogramOverrides( 548 new AdSelectionOverrideCallback.Stub() { 549 @Override 550 public void onSuccess() { 551 executor.execute(() -> outcomeReceiver.onResult(new Object())); 552 } 553 554 @Override 555 public void onFailure(FledgeErrorResponse failureParcel) { 556 executor.execute( 557 () -> 558 outcomeReceiver.onError( 559 AdServicesStatusUtils.asException( 560 failureParcel))); 561 } 562 }); 563 } catch (NullPointerException e) { 564 sLogger.e(e, "Unable to find the AdSelection service"); 565 outcomeReceiver.onError( 566 new IllegalStateException("Unable to find the AdSelection service", e)); 567 } catch (RemoteException e) { 568 sLogger.e(e, "Remote exception encountered while updating ad counter histogram"); 569 outcomeReceiver.onError(new IllegalStateException("Failure of AdSelection service", e)); 570 } 571 } 572 } 573