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.devapi;
18 
19 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__API_NAME_UNKNOWN;
20 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__OVERRIDE_AD_SELECTION_CONFIG_REMOTE_INFO;
21 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__REMOVE_AD_SELECTION_CONFIG_REMOTE_INFO_OVERRIDE;
22 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__RESET_ALL_AD_SELECTION_CONFIG_REMOTE_OVERRIDES;
23 
24 import android.adservices.adselection.AdSelectionConfig;
25 import android.adservices.adselection.AdSelectionFromOutcomesConfig;
26 import android.adservices.adselection.AdSelectionOverrideCallback;
27 import android.adservices.adselection.PerBuyerDecisionLogic;
28 import android.adservices.common.AdSelectionSignals;
29 import android.adservices.common.AdServicesStatusUtils;
30 import android.adservices.common.FledgeErrorResponse;
31 import android.annotation.NonNull;
32 import android.content.pm.PackageManager;
33 import android.os.Build;
34 import android.os.RemoteException;
35 
36 import androidx.annotation.RequiresApi;
37 
38 import com.android.adservices.LoggerFactory;
39 import com.android.adservices.data.adselection.AdSelectionEntryDao;
40 import com.android.adservices.service.Flags;
41 import com.android.adservices.service.common.AppImportanceFilter;
42 import com.android.adservices.service.common.AppImportanceFilter.WrongCallingApplicationStateException;
43 import com.android.adservices.service.consent.AdServicesApiConsent;
44 import com.android.adservices.service.consent.AdServicesApiType;
45 import com.android.adservices.service.consent.ConsentManager;
46 import com.android.adservices.service.stats.AdServicesLogger;
47 
48 import com.google.common.util.concurrent.FluentFuture;
49 import com.google.common.util.concurrent.FutureCallback;
50 import com.google.common.util.concurrent.ListeningExecutorService;
51 import com.google.common.util.concurrent.MoreExecutors;
52 
53 import java.util.Objects;
54 import java.util.concurrent.ExecutorService;
55 
56 /** Encapsulates the AdSelection Override Logic */
57 @RequiresApi(Build.VERSION_CODES.S)
58 public class AdSelectionOverrider {
59     private static final LoggerFactory.Logger sLogger = LoggerFactory.getFledgeLogger();
60     @NonNull private final AdSelectionEntryDao mAdSelectionEntryDao;
61     @NonNull private final ListeningExecutorService mLightweightExecutorService;
62     @NonNull private final ListeningExecutorService mBackgroundExecutorService;
63     @NonNull private final AdSelectionDevOverridesHelper mAdSelectionDevOverridesHelper;
64     @NonNull private final PackageManager mPackageManager;
65     @NonNull private final ConsentManager mConsentManager;
66     @NonNull private final AdServicesLogger mAdServicesLogger;
67     @NonNull private final Flags mFlags;
68     @NonNull private final AppImportanceFilter mAppImportanceFilter;
69     private final int mCallerUid;
70     @NonNull private final String mCallerAppPackageName;
71 
72     /**
73      * Creates an instance of {@link AdSelectionOverrider} with the given {@link DevContext}, {@link
74      * AdSelectionEntryDao}, executor, and {@link AdSelectionDevOverridesHelper}.
75      */
AdSelectionOverrider( @onNull DevContext devContext, @NonNull AdSelectionEntryDao adSelectionEntryDao, @NonNull ExecutorService lightweightExecutorService, @NonNull ExecutorService backgroundExecutorService, @NonNull PackageManager packageManager, @NonNull ConsentManager consentManager, @NonNull AdServicesLogger adServicesLogger, @NonNull AppImportanceFilter appImportanceFilter, @NonNull final Flags flags, int callerUid)76     public AdSelectionOverrider(
77             @NonNull DevContext devContext,
78             @NonNull AdSelectionEntryDao adSelectionEntryDao,
79             @NonNull ExecutorService lightweightExecutorService,
80             @NonNull ExecutorService backgroundExecutorService,
81             @NonNull PackageManager packageManager,
82             @NonNull ConsentManager consentManager,
83             @NonNull AdServicesLogger adServicesLogger,
84             @NonNull AppImportanceFilter appImportanceFilter,
85             @NonNull final Flags flags,
86             int callerUid) {
87         Objects.requireNonNull(devContext);
88         Objects.requireNonNull(adSelectionEntryDao);
89         Objects.requireNonNull(lightweightExecutorService);
90         Objects.requireNonNull(backgroundExecutorService);
91         Objects.requireNonNull(packageManager);
92         Objects.requireNonNull(consentManager);
93         Objects.requireNonNull(adServicesLogger);
94         Objects.requireNonNull(appImportanceFilter);
95         Objects.requireNonNull(flags);
96 
97         this.mAdSelectionEntryDao = adSelectionEntryDao;
98         this.mLightweightExecutorService =
99                 MoreExecutors.listeningDecorator(lightweightExecutorService);
100         this.mBackgroundExecutorService =
101                 MoreExecutors.listeningDecorator(backgroundExecutorService);
102         this.mAdSelectionDevOverridesHelper =
103                 new AdSelectionDevOverridesHelper(devContext, mAdSelectionEntryDao);
104         this.mPackageManager = packageManager;
105         this.mConsentManager = consentManager;
106         this.mAdServicesLogger = adServicesLogger;
107         mFlags = flags;
108         mAppImportanceFilter = appImportanceFilter;
109         mCallerUid = callerUid;
110         mCallerAppPackageName = devContext.getCallingAppPackageName();
111     }
112 
113     /**
114      * Configures our fetching logic relating to {@code adSelectionConfig} to use {@code
115      * decisionLogicJS} instead of fetching from remote servers
116      *
117      * @param callback callback function to be called in case of success or failure
118      */
addOverride( @onNull AdSelectionConfig adSelectionConfig, @NonNull String decisionLogicJS, @NonNull AdSelectionSignals trustedScoringSignals, @NonNull PerBuyerDecisionLogic perBuyerDecisionLogic, @NonNull AdSelectionOverrideCallback callback)119     public void addOverride(
120             @NonNull AdSelectionConfig adSelectionConfig,
121             @NonNull String decisionLogicJS,
122             @NonNull AdSelectionSignals trustedScoringSignals,
123             @NonNull PerBuyerDecisionLogic perBuyerDecisionLogic,
124             @NonNull AdSelectionOverrideCallback callback) {
125         // Auto-generated variable name is too long for lint check
126         int shortApiName =
127                 AD_SERVICES_API_CALLED__API_NAME__OVERRIDE_AD_SELECTION_CONFIG_REMOTE_INFO;
128 
129         FluentFuture.from(
130                         mLightweightExecutorService.submit(
131                                 () -> {
132                                     // Cannot read pH flags in the binder thread so this
133                                     // checks will be done in a spawn thread.
134                                     if (mFlags.getEnforceForegroundStatusForFledgeOverrides()) {
135                                         mAppImportanceFilter.assertCallerIsInForeground(
136                                                 mCallerUid, shortApiName, null);
137                                     }
138 
139                                     return null;
140                                 }))
141                 .transformAsync(
142                         ignoredVoid ->
143                                 callAddOverride(
144                                         adSelectionConfig,
145                                         decisionLogicJS,
146                                         trustedScoringSignals,
147                                         perBuyerDecisionLogic),
148                         mLightweightExecutorService)
149                 .addCallback(
150                         new FutureCallback<Integer>() {
151                             @Override
152                             public void onSuccess(Integer result) {
153                                 sLogger.d("Add dev override for ad selection config succeeded!");
154                                 invokeSuccess(callback, shortApiName, result);
155                             }
156 
157                             @Override
158                             public void onFailure(Throwable t) {
159                                 sLogger.e(t, "Add dev override for ad selection config failed!");
160                                 notifyFailureToCaller(callback, t, shortApiName);
161                             }
162                         },
163                         mLightweightExecutorService);
164     }
165 
166     /**
167      * Removes a decision logic override matching this {@code adSelectionConfig} and {@code
168      * appPackageName}
169      *
170      * @param callback callback function to be called in case of success or failure
171      */
removeOverride( @onNull AdSelectionConfig adSelectionConfig, @NonNull AdSelectionOverrideCallback callback)172     public void removeOverride(
173             @NonNull AdSelectionConfig adSelectionConfig,
174             @NonNull AdSelectionOverrideCallback callback) {
175         // Auto-generated variable name is too long for lint check
176         int shortApiName =
177                 AD_SERVICES_API_CALLED__API_NAME__REMOVE_AD_SELECTION_CONFIG_REMOTE_INFO_OVERRIDE;
178 
179         FluentFuture.from(
180                         mLightweightExecutorService.submit(
181                                 () -> {
182                                     // Cannot read pH flags in the binder thread so this
183                                     // checks will be done in a spawn thread.
184                                     if (mFlags.getEnforceForegroundStatusForFledgeOverrides()) {
185                                         mAppImportanceFilter.assertCallerIsInForeground(
186                                                 mCallerUid, shortApiName, null);
187                                     }
188 
189                                     return null;
190                                 }))
191                 .transformAsync(
192                         ignoredVoid -> callRemoveOverride(adSelectionConfig),
193                         mLightweightExecutorService)
194                 .addCallback(
195                         new FutureCallback<Integer>() {
196                             @Override
197                             public void onSuccess(Integer result) {
198                                 sLogger.d(
199                                         "Removing dev override for ad selection config succeeded!");
200                                 invokeSuccess(callback, shortApiName, result);
201                             }
202 
203                             @Override
204                             public void onFailure(Throwable t) {
205                                 sLogger.e(
206                                         t, "Removing dev override for ad selection config failed!");
207                                 notifyFailureToCaller(callback, t, shortApiName);
208                             }
209                         },
210                         mLightweightExecutorService);
211     }
212 
213     /**
214      * Removes all ad selection overrides matching the {@code appPackageName}
215      *
216      * @param callback callback function to be called in case of success or failure
217      */
removeAllOverridesForAdSelectionConfig( @onNull AdSelectionOverrideCallback callback)218     public void removeAllOverridesForAdSelectionConfig(
219             @NonNull AdSelectionOverrideCallback callback) {
220         // Auto-generated variable name is too long for lint check
221         int shortApiName =
222                 AD_SERVICES_API_CALLED__API_NAME__RESET_ALL_AD_SELECTION_CONFIG_REMOTE_OVERRIDES;
223 
224         FluentFuture.from(
225                         mLightweightExecutorService.submit(
226                                 () -> {
227                                     // Cannot read pH flags in the binder thread so this
228                                     // checks will be done in a spawn thread.
229                                     if (mFlags.getEnforceForegroundStatusForFledgeOverrides()) {
230                                         mAppImportanceFilter.assertCallerIsInForeground(
231                                                 mCallerUid, shortApiName, null);
232                                     }
233 
234                                     return null;
235                                 }))
236                 .transformAsync(
237                         ignoredVoid -> callRemoveAllOverrides(), mLightweightExecutorService)
238                 .addCallback(
239                         new FutureCallback<Integer>() {
240                             @Override
241                             public void onSuccess(Integer result) {
242                                 sLogger.d(
243                                         "Removing all dev overrides for ad selection config"
244                                                 + " succeeded!");
245                                 invokeSuccess(callback, shortApiName, result);
246                             }
247 
248                             @Override
249                             public void onFailure(Throwable t) {
250                                 sLogger.e(
251                                         t,
252                                         "Removing all dev overrides for ad selection config"
253                                                 + " failed!");
254                                 notifyFailureToCaller(callback, t, shortApiName);
255                             }
256                         },
257                         mLightweightExecutorService);
258     }
259 
260     /**
261      * Configures our fetching logic relating to {@code config} to use {@code selectionLogicJs}
262      * instead of fetching from remote servers
263      *
264      * @param callback callback function to be called in case of success or failure
265      */
addOverride( @onNull AdSelectionFromOutcomesConfig config, @NonNull String selectionLogicJs, @NonNull AdSelectionSignals selectionSignals, @NonNull AdSelectionOverrideCallback callback)266     public void addOverride(
267             @NonNull AdSelectionFromOutcomesConfig config,
268             @NonNull String selectionLogicJs,
269             @NonNull AdSelectionSignals selectionSignals,
270             @NonNull AdSelectionOverrideCallback callback) {
271         // Auto-generated variable name is too long for lint check
272         int shortApiName = AD_SERVICES_API_CALLED__API_NAME__API_NAME_UNKNOWN;
273 
274         FluentFuture.from(
275                         mLightweightExecutorService.submit(
276                                 () -> {
277                                     // Cannot read pH flags in the binder thread so this
278                                     // checks will be done in a spawn thread.
279                                     if (mFlags.getEnforceForegroundStatusForFledgeOverrides()) {
280                                         mAppImportanceFilter.assertCallerIsInForeground(
281                                                 mCallerUid, shortApiName, null);
282                                     }
283                                     return null;
284                                 }))
285                 .transformAsync(
286                         ignoredVoid -> callAddOverride(config, selectionLogicJs, selectionSignals),
287                         mLightweightExecutorService)
288                 .addCallback(
289                         new FutureCallback<Integer>() {
290                             @Override
291                             public void onSuccess(Integer result) {
292                                 sLogger.d(
293                                         "Add dev override for ad selection config from outcomes"
294                                                 + " succeeded!");
295                                 invokeSuccess(callback, shortApiName, result);
296                             }
297 
298                             @Override
299                             public void onFailure(Throwable t) {
300                                 sLogger.e(
301                                         t,
302                                         "Add dev override for ad selection config from outcomes"
303                                                 + " failed!");
304                                 notifyFailureToCaller(callback, t, shortApiName);
305                             }
306                         },
307                         mLightweightExecutorService);
308     }
309 
310     /**
311      * Removes a decision logic override matching this {@code config} and {@code appPackageName}
312      *
313      * @param callback callback function to be called in case of success or failure
314      */
removeOverride( @onNull AdSelectionFromOutcomesConfig config, @NonNull AdSelectionOverrideCallback callback)315     public void removeOverride(
316             @NonNull AdSelectionFromOutcomesConfig config,
317             @NonNull AdSelectionOverrideCallback callback) {
318         // Auto-generated variable name is too long for lint check
319         int shortApiName = AD_SERVICES_API_CALLED__API_NAME__API_NAME_UNKNOWN;
320 
321         FluentFuture.from(
322                         mLightweightExecutorService.submit(
323                                 () -> {
324                                     // Cannot read pH flags in the binder thread so this
325                                     // checks will be done in a spawn thread.
326                                     if (mFlags.getEnforceForegroundStatusForFledgeOverrides()) {
327                                         mAppImportanceFilter.assertCallerIsInForeground(
328                                                 mCallerUid, shortApiName, null);
329                                     }
330 
331                                     return null;
332                                 }))
333                 .transformAsync(
334                         ignoredVoid -> callRemoveOverride(config), mLightweightExecutorService)
335                 .addCallback(
336                         new FutureCallback<Integer>() {
337                             @Override
338                             public void onSuccess(Integer result) {
339                                 sLogger.d(
340                                         "Removing dev override for ad selection config from"
341                                                 + " outcomes succeeded!");
342                                 invokeSuccess(callback, shortApiName, result);
343                             }
344 
345                             @Override
346                             public void onFailure(Throwable t) {
347                                 sLogger.e(
348                                         t,
349                                         "Removing dev override for ad selection config from"
350                                                 + " outcomes failed!");
351                                 notifyFailureToCaller(callback, t, shortApiName);
352                             }
353                         },
354                         mLightweightExecutorService);
355     }
356 
357     /**
358      * Removes all ad selection overrides matching the {@code appPackageName}
359      *
360      * @param callback callback function to be called in case of success or failure
361      */
removeAllOverridesForAdSelectionFromOutcomes( @onNull AdSelectionOverrideCallback callback)362     public void removeAllOverridesForAdSelectionFromOutcomes(
363             @NonNull AdSelectionOverrideCallback callback) {
364         // Auto-generated variable name is too long for lint check
365         int shortApiName = AD_SERVICES_API_CALLED__API_NAME__API_NAME_UNKNOWN;
366 
367         FluentFuture.from(
368                         mLightweightExecutorService.submit(
369                                 () -> {
370                                     // Cannot read pH flags in the binder thread so this
371                                     // checks will be done in a spawn thread.
372                                     if (mFlags.getEnforceForegroundStatusForFledgeOverrides()) {
373                                         mAppImportanceFilter.assertCallerIsInForeground(
374                                                 mCallerUid, shortApiName, null);
375                                     }
376 
377                                     return null;
378                                 }))
379                 .transformAsync(
380                         ignoredVoid -> callRemoveAllSelectionLogicOverrides(),
381                         mLightweightExecutorService)
382                 .addCallback(
383                         new FutureCallback<Integer>() {
384                             @Override
385                             public void onSuccess(Integer result) {
386                                 sLogger.d(
387                                         "Removing all dev overrides for ad selection config from"
388                                                 + " outcomes succeeded!");
389                                 invokeSuccess(callback, shortApiName, result);
390                             }
391 
392                             @Override
393                             public void onFailure(Throwable t) {
394                                 sLogger.e(
395                                         t,
396                                         "Removing all dev overrides for ad selection config from"
397                                                 + " outcomes failed!");
398                                 notifyFailureToCaller(callback, t, shortApiName);
399                             }
400                         },
401                         mLightweightExecutorService);
402     }
403 
callAddOverride( @onNull AdSelectionConfig adSelectionConfig, @NonNull String decisionLogicJS, @NonNull AdSelectionSignals trustedScoringSignals, @NonNull PerBuyerDecisionLogic perBuyerDecisionLogic)404     private FluentFuture<Integer> callAddOverride(
405             @NonNull AdSelectionConfig adSelectionConfig,
406             @NonNull String decisionLogicJS,
407             @NonNull AdSelectionSignals trustedScoringSignals,
408             @NonNull PerBuyerDecisionLogic perBuyerDecisionLogic) {
409         return FluentFuture.from(
410                 mBackgroundExecutorService.submit(
411                         () -> {
412                             AdServicesApiConsent userConsent = getAdServicesApiConsent();
413 
414                             if (!userConsent.isGiven()) {
415                                 return AdServicesStatusUtils.STATUS_USER_CONSENT_REVOKED;
416                             }
417 
418                             mAdSelectionDevOverridesHelper.addAdSelectionSellerOverride(
419                                     adSelectionConfig,
420                                     decisionLogicJS,
421                                     trustedScoringSignals,
422                                     perBuyerDecisionLogic);
423                             return AdServicesStatusUtils.STATUS_SUCCESS;
424                         }));
425     }
426 
callRemoveOverride(@onNull AdSelectionConfig adSelectionConfig)427     private FluentFuture<Integer> callRemoveOverride(@NonNull AdSelectionConfig adSelectionConfig) {
428         return FluentFuture.from(
429                 mBackgroundExecutorService.submit(
430                         () -> {
431                             AdServicesApiConsent userConsent = getAdServicesApiConsent();
432 
433                             if (!userConsent.isGiven()) {
434                                 return AdServicesStatusUtils.STATUS_USER_CONSENT_REVOKED;
435                             }
436 
437                             mAdSelectionDevOverridesHelper.removeAdSelectionSellerOverride(
438                                     adSelectionConfig);
439                             return AdServicesStatusUtils.STATUS_SUCCESS;
440                         }));
441     }
442 
443     private FluentFuture<Integer> callRemoveAllOverrides() {
444         return FluentFuture.from(
445                 mBackgroundExecutorService.submit(
446                         () -> {
447                             AdServicesApiConsent userConsent = getAdServicesApiConsent();
448 
449                             if (!userConsent.isGiven()) {
450                                 return AdServicesStatusUtils.STATUS_USER_CONSENT_REVOKED;
451                             }
452 
453                             mAdSelectionDevOverridesHelper.removeAllDecisionLogicOverrides();
454                             return AdServicesStatusUtils.STATUS_SUCCESS;
455                         }));
456     }
457 
458     private FluentFuture<Integer> callAddOverride(
459             @NonNull AdSelectionFromOutcomesConfig config,
460             @NonNull String selectionLogicJs,
461             @NonNull AdSelectionSignals selectionSignals) {
462         return FluentFuture.from(
463                 mBackgroundExecutorService.submit(
464                         () -> {
465                             AdServicesApiConsent userConsent = getAdServicesApiConsent();
466 
467                             if (!userConsent.isGiven()) {
468                                 return AdServicesStatusUtils.STATUS_USER_CONSENT_REVOKED;
469                             }
470 
471                             mAdSelectionDevOverridesHelper.addAdSelectionOutcomeSelectorOverride(
472                                     config, selectionLogicJs, selectionSignals);
473                             return AdServicesStatusUtils.STATUS_SUCCESS;
474                         }));
475     }
476 
477     private FluentFuture<Integer> callRemoveOverride(
478             @NonNull AdSelectionFromOutcomesConfig config) {
479         return FluentFuture.from(
480                 mBackgroundExecutorService.submit(
481                         () -> {
482                             AdServicesApiConsent userConsent = getAdServicesApiConsent();
483 
484                             if (!userConsent.isGiven()) {
485                                 return AdServicesStatusUtils.STATUS_USER_CONSENT_REVOKED;
486                             }
487 
488                             mAdSelectionDevOverridesHelper.removeAdSelectionOutcomeSelectorOverride(
489                                     config);
490                             return AdServicesStatusUtils.STATUS_SUCCESS;
491                         }));
492     }
493 
494     private FluentFuture<Integer> callRemoveAllSelectionLogicOverrides() {
495         return FluentFuture.from(
496                 mBackgroundExecutorService.submit(
497                         () -> {
498                             AdServicesApiConsent userConsent = getAdServicesApiConsent();
499 
500                             if (!userConsent.isGiven()) {
501                                 return AdServicesStatusUtils.STATUS_USER_CONSENT_REVOKED;
502                             }
503 
504                             mAdSelectionDevOverridesHelper.removeAllSelectionLogicOverrides();
505                             return AdServicesStatusUtils.STATUS_SUCCESS;
506                         }));
507     }
508 
509     private AdServicesApiConsent getAdServicesApiConsent() {
510         AdServicesApiConsent userConsent = mConsentManager.getConsent(AdServicesApiType.FLEDGE);
511 
512         return userConsent;
513     }
514 
515     /** Invokes the onFailure function from the callback and handles the exception. */
516     private void invokeFailure(
517             @NonNull AdSelectionOverrideCallback callback,
518             int statusCode,
519             String errorMessage,
520             int apiName) {
521         int resultCode = statusCode;
522         try {
523             callback.onFailure(
524                     new FledgeErrorResponse.Builder()
525                             .setStatusCode(statusCode)
526                             .setErrorMessage(errorMessage)
527                             .build());
528         } catch (RemoteException e) {
529             sLogger.e(e, "Unable to send failed result to the callback");
530             resultCode = AdServicesStatusUtils.STATUS_UNKNOWN_ERROR;
531             throw e.rethrowFromSystemServer();
532         } finally {
533             mAdServicesLogger.logFledgeApiCallStats(
534                     apiName, mCallerAppPackageName, resultCode, /*latencyMs=*/ 0);
535         }
536     }
537 
538     /** Invokes the onSuccess function from the callback and handles the exception. */
539     private void invokeSuccess(
540             @NonNull AdSelectionOverrideCallback callback, int apiName, Integer resultCode) {
541         int resultCodeInt = AdServicesStatusUtils.STATUS_UNSET;
542         if (resultCode != null) {
543             resultCodeInt = resultCode;
544         }
545         try {
546             callback.onSuccess();
547         } catch (RemoteException e) {
548             sLogger.e(e, "Unable to send successful result to the callback");
549             resultCodeInt = AdServicesStatusUtils.STATUS_UNKNOWN_ERROR;
550             throw e.rethrowFromSystemServer();
551         } finally {
552             mAdServicesLogger.logFledgeApiCallStats(
553                     apiName, mCallerAppPackageName, resultCodeInt, /*latencyMs=*/ 0);
554         }
555     }
556 
557     private void notifyFailureToCaller(
558             @NonNull AdSelectionOverrideCallback callback, @NonNull Throwable t, int apiName) {
559         if (t instanceof IllegalArgumentException) {
560             invokeFailure(
561                     callback,
562                     AdServicesStatusUtils.STATUS_INVALID_ARGUMENT,
563                     t.getMessage(),
564                     apiName);
565         } else if (t instanceof WrongCallingApplicationStateException) {
566             invokeFailure(
567                     callback,
568                     AdServicesStatusUtils.STATUS_BACKGROUND_CALLER,
569                     t.getMessage(),
570                     apiName);
571         } else if (t instanceof IllegalStateException) {
572             invokeFailure(
573                     callback, AdServicesStatusUtils.STATUS_INTERNAL_ERROR, t.getMessage(), apiName);
574         } else {
575             invokeFailure(
576                     callback, AdServicesStatusUtils.STATUS_UNAUTHORIZED, t.getMessage(), apiName);
577         }
578     }
579 }
580