• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package 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