diff options
Diffstat (limited to 'adservices/service-core/java/com/android/adservices/service/adselection/AdSelectionRunner.java')
-rw-r--r-- | adservices/service-core/java/com/android/adservices/service/adselection/AdSelectionRunner.java | 359 |
1 files changed, 107 insertions, 252 deletions
diff --git a/adservices/service-core/java/com/android/adservices/service/adselection/AdSelectionRunner.java b/adservices/service-core/java/com/android/adservices/service/adselection/AdSelectionRunner.java index 2f69f2f3d9..7851ef3986 100644 --- a/adservices/service-core/java/com/android/adservices/service/adselection/AdSelectionRunner.java +++ b/adservices/service-core/java/com/android/adservices/service/adselection/AdSelectionRunner.java @@ -23,18 +23,14 @@ import android.adservices.adselection.AdSelectionCallback; import android.adservices.adselection.AdSelectionConfig; import android.adservices.adselection.AdSelectionInput; import android.adservices.adselection.AdSelectionResponse; -import android.adservices.common.AdSelectionSignals; import android.adservices.common.AdServicesStatusUtils; import android.adservices.common.FledgeErrorResponse; -import android.adservices.exceptions.AdServicesException; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SuppressLint; import android.content.Context; import android.net.Uri; import android.os.LimitExceededException; import android.os.RemoteException; -import android.util.Pair; import com.android.adservices.LogUtil; import com.android.adservices.data.adselection.AdSelectionEntryDao; @@ -43,18 +39,18 @@ import com.android.adservices.data.adselection.DBBuyerDecisionLogic; import com.android.adservices.data.customaudience.CustomAudienceDao; import com.android.adservices.data.customaudience.DBCustomAudience; import com.android.adservices.service.Flags; -import com.android.adservices.service.common.AdServicesHttpsClient; import com.android.adservices.service.common.AppImportanceFilter; import com.android.adservices.service.common.AppImportanceFilter.WrongCallingApplicationStateException; import com.android.adservices.service.common.FledgeAllowListsFilter; import com.android.adservices.service.common.FledgeAuthorizationFilter; import com.android.adservices.service.common.Throttler; import com.android.adservices.service.consent.ConsentManager; -import com.android.adservices.service.devapi.DevContext; +import com.android.adservices.service.js.JSSandboxIsNotAvailableException; +import com.android.adservices.service.js.JSScriptEngine; import com.android.adservices.service.stats.AdServicesLogger; +import com.android.adservices.service.stats.ApiServiceLatencyCalculator; import com.android.internal.annotations.VisibleForTesting; -import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.util.concurrent.AsyncFunction; import com.google.common.util.concurrent.FluentFuture; @@ -66,20 +62,13 @@ import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.UncheckedTimeoutException; import java.time.Clock; -import java.time.Instant; import java.util.List; import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; -import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; -import java.util.stream.Collectors; - /** * Orchestrator that runs the Ads Auction/Bidding and Scoring logic The class expects the caller to @@ -88,7 +77,7 @@ import java.util.stream.Collectors; * * <p>Class takes in an executor on which it runs the AdSelection logic */ -public final class AdSelectionRunner { +public abstract class AdSelectionRunner { @VisibleForTesting static final String AD_SELECTION_ERROR_PATTERN = "%s: %s"; @@ -112,86 +101,90 @@ public final class AdSelectionRunner { @VisibleForTesting static final String AD_SELECTION_THROTTLED = "Ad selection exceeded allowed rate limit"; + @VisibleForTesting + static final String JS_SANDBOX_IS_NOT_AVAILABLE = + String.format( + AD_SELECTION_ERROR_PATTERN, + ERROR_AD_SELECTION_FAILURE, + "JS Sandbox is not available"); + public static final long DAY_IN_SECONDS = 60 * 60 * 24; - @NonNull private final Context mContext; - @NonNull private final CustomAudienceDao mCustomAudienceDao; - @NonNull private final AdSelectionEntryDao mAdSelectionEntryDao; - @NonNull private final AdServicesHttpsClient mAdServicesHttpsClient; - @NonNull private final ListeningExecutorService mLightweightExecutorService; - @NonNull private final ListeningExecutorService mBackgroundExecutorService; - @NonNull private final AdsScoreGenerator mAdsScoreGenerator; - @NonNull private final AdBidGenerator mAdBidGenerator; - @NonNull private final AdSelectionIdGenerator mAdSelectionIdGenerator; - @NonNull private final Clock mClock; - @NonNull private final ConsentManager mConsentManager; - @NonNull private final AdServicesLogger mAdServicesLogger; - @NonNull private final Flags mFlags; - @NonNull private final AppImportanceFilter mAppImportanceFilter; - private final int mCallerUid; - @NonNull private final Supplier<Throttler> mThrottlerSupplier; - @NonNull private final FledgeAuthorizationFilter mFledgeAuthorizationFilter; - @NonNull private final FledgeAllowListsFilter mFledgeAllowListsFilter; + @NonNull protected final Context mContext; + @NonNull protected final CustomAudienceDao mCustomAudienceDao; + @NonNull protected final AdSelectionEntryDao mAdSelectionEntryDao; + @NonNull protected final ListeningExecutorService mLightweightExecutorService; + @NonNull protected final ListeningExecutorService mBackgroundExecutorService; + @NonNull protected final ScheduledThreadPoolExecutor mScheduledExecutor; + @NonNull protected final AdSelectionIdGenerator mAdSelectionIdGenerator; + @NonNull protected final Clock mClock; + @NonNull protected final ConsentManager mConsentManager; + @NonNull protected final AdServicesLogger mAdServicesLogger; + @NonNull protected final Flags mFlags; + @NonNull protected final AppImportanceFilter mAppImportanceFilter; + @NonNull protected final Supplier<Throttler> mThrottlerSupplier; + @NonNull protected final FledgeAuthorizationFilter mFledgeAuthorizationFilter; + @NonNull protected final FledgeAllowListsFilter mFledgeAllowListsFilter; + @NonNull protected final ApiServiceLatencyCalculator mApiServiceLatencyCalculator; + protected final int mCallerUid; + /** + * @param context service context + * @param customAudienceDao DAO to access custom audience storage + * @param adSelectionEntryDao DAO to access ad selection storage + * @param lightweightExecutorService executor for running short tasks + * @param backgroundExecutorService executor for longer running tasks (ex. network calls) + * @param scheduledExecutor executor for tasks to be run with a delay or timed executions + * @param consentManager instance of {@link ConsentManager} for verifying user consent + * @param adServicesLogger logger for logging calls to PPAPI + * @param appImportanceFilter filter to assert calling app is running in the foreground + * @param flags for accessing feature flags + * @param throttlerSupplier supplier for throttling calls to PPAPI + * @param callerUid calling app UID + * @param fledgeAuthorizationFilter filter for authorizing the caller on certain behavior + * @param fledgeAllowListsFilter filter for verifying the caller can call PPAPI + */ public AdSelectionRunner( @NonNull final Context context, @NonNull final CustomAudienceDao customAudienceDao, @NonNull final AdSelectionEntryDao adSelectionEntryDao, - @NonNull final AdServicesHttpsClient adServicesHttpsClient, @NonNull final ExecutorService lightweightExecutorService, @NonNull final ExecutorService backgroundExecutorService, + @NonNull final ScheduledThreadPoolExecutor scheduledExecutor, @NonNull final ConsentManager consentManager, @NonNull final AdServicesLogger adServicesLogger, - @NonNull final DevContext devContext, @NonNull AppImportanceFilter appImportanceFilter, @NonNull final Flags flags, @NonNull final Supplier<Throttler> throttlerSupplier, int callerUid, @NonNull final FledgeAuthorizationFilter fledgeAuthorizationFilter, - @NonNull final FledgeAllowListsFilter fledgeAllowListsFilter) { + @NonNull final FledgeAllowListsFilter fledgeAllowListsFilter, + @NonNull final ApiServiceLatencyCalculator apiServiceLatencyCalculator) { Objects.requireNonNull(context); Objects.requireNonNull(customAudienceDao); Objects.requireNonNull(adSelectionEntryDao); - Objects.requireNonNull(adServicesHttpsClient); Objects.requireNonNull(lightweightExecutorService); Objects.requireNonNull(backgroundExecutorService); Objects.requireNonNull(consentManager); Objects.requireNonNull(adServicesLogger); - Objects.requireNonNull(devContext); Objects.requireNonNull(appImportanceFilter); Objects.requireNonNull(flags); Objects.requireNonNull(throttlerSupplier); Objects.requireNonNull(fledgeAuthorizationFilter); Objects.requireNonNull(fledgeAllowListsFilter); + Preconditions.checkArgument( + JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable(), + JS_SANDBOX_IS_NOT_AVAILABLE); + Objects.requireNonNull(apiServiceLatencyCalculator); + mContext = context; mCustomAudienceDao = customAudienceDao; mAdSelectionEntryDao = adSelectionEntryDao; - mAdServicesHttpsClient = adServicesHttpsClient; mLightweightExecutorService = MoreExecutors.listeningDecorator(lightweightExecutorService); mBackgroundExecutorService = MoreExecutors.listeningDecorator(backgroundExecutorService); + mScheduledExecutor = scheduledExecutor; mConsentManager = consentManager; mAdServicesLogger = adServicesLogger; - mAdsScoreGenerator = - new AdsScoreGeneratorImpl( - new AdSelectionScriptEngine( - mContext, - () -> flags.getEnforceIsolateMaxHeapSize(), - () -> flags.getIsolateMaxHeapSizeBytes()), - mLightweightExecutorService, - mBackgroundExecutorService, - mAdServicesHttpsClient, - devContext, - mAdSelectionEntryDao, - flags); - mAdBidGenerator = - new AdBidGeneratorImpl( - context, - mAdServicesHttpsClient, - mLightweightExecutorService, - mBackgroundExecutorService, - devContext, - mCustomAudienceDao, - flags); mAdSelectionIdGenerator = new AdSelectionIdGenerator(); mClock = Clock.systemUTC(); mFlags = flags; @@ -200,6 +193,7 @@ public final class AdSelectionRunner { mCallerUid = callerUid; mFledgeAuthorizationFilter = fledgeAuthorizationFilter; mFledgeAllowListsFilter = fledgeAllowListsFilter; + mApiServiceLatencyCalculator = apiServiceLatencyCalculator; } @VisibleForTesting @@ -207,12 +201,10 @@ public final class AdSelectionRunner { @NonNull final Context context, @NonNull final CustomAudienceDao customAudienceDao, @NonNull final AdSelectionEntryDao adSelectionEntryDao, - @NonNull final AdServicesHttpsClient adServicesHttpsClient, @NonNull final ExecutorService lightweightExecutorService, @NonNull final ExecutorService backgroundExecutorService, + @NonNull final ScheduledThreadPoolExecutor scheduledExecutor, @NonNull final ConsentManager consentManager, - @NonNull final AdsScoreGenerator adsScoreGenerator, - @NonNull final AdBidGenerator adBidGenerator, @NonNull final AdSelectionIdGenerator adSelectionIdGenerator, @NonNull Clock clock, @NonNull final AdServicesLogger adServicesLogger, @@ -221,32 +213,30 @@ public final class AdSelectionRunner { @NonNull final Supplier<Throttler> throttlerSupplier, int callerUid, @NonNull final FledgeAuthorizationFilter fledgeAuthorizationFilter, - @NonNull final FledgeAllowListsFilter fledgeAllowListsFilter) { + @NonNull final FledgeAllowListsFilter fledgeAllowListsFilter, + @NonNull final ApiServiceLatencyCalculator apiServiceLatencyCalculator) { Objects.requireNonNull(context); Objects.requireNonNull(customAudienceDao); Objects.requireNonNull(adSelectionEntryDao); - Objects.requireNonNull(adServicesHttpsClient); Objects.requireNonNull(lightweightExecutorService); Objects.requireNonNull(backgroundExecutorService); + Objects.requireNonNull(scheduledExecutor); Objects.requireNonNull(consentManager); - Objects.requireNonNull(adsScoreGenerator); - Objects.requireNonNull(adBidGenerator); Objects.requireNonNull(adSelectionIdGenerator); Objects.requireNonNull(clock); Objects.requireNonNull(adServicesLogger); Objects.requireNonNull(appImportanceFilter); Objects.requireNonNull(flags); Objects.requireNonNull(fledgeAuthorizationFilter); + Objects.requireNonNull(apiServiceLatencyCalculator); mContext = context; mCustomAudienceDao = customAudienceDao; mAdSelectionEntryDao = adSelectionEntryDao; - mAdServicesHttpsClient = adServicesHttpsClient; mLightweightExecutorService = MoreExecutors.listeningDecorator(lightweightExecutorService); mBackgroundExecutorService = MoreExecutors.listeningDecorator(backgroundExecutorService); + mScheduledExecutor = scheduledExecutor; mConsentManager = consentManager; - mAdsScoreGenerator = adsScoreGenerator; - mAdBidGenerator = adBidGenerator; mAdSelectionIdGenerator = adSelectionIdGenerator; mClock = clock; mAdServicesLogger = adServicesLogger; @@ -256,6 +246,7 @@ public final class AdSelectionRunner { mCallerUid = callerUid; mFledgeAuthorizationFilter = fledgeAuthorizationFilter; mFledgeAllowListsFilter = fledgeAllowListsFilter; + mApiServiceLatencyCalculator = apiServiceLatencyCalculator; } /** @@ -293,8 +284,6 @@ public final class AdSelectionRunner { @Override public void onSuccess(DBAdSelection result) { notifySuccessToCaller(result, callback); - // TODO(242280808): Schedule a clear for stale data instead of this hack - clearExpiredAdSelectionData(); } @Override @@ -306,12 +295,11 @@ public final class AdSelectionRunner { } else { notifyFailureToCaller(callback, t); } - // TODO(242280808): Schedule a clear for stale data instead of this hack - clearExpiredAdSelectionData(); } }, mLightweightExecutorService); } catch (Throwable t) { + LogUtil.v("run ad selection fails fast with exception %s.", t.toString()); notifyFailureToCaller(callback, t); } } @@ -330,11 +318,15 @@ public final class AdSelectionRunner { LogUtil.e(e, "Encountered exception during notifying AdSelection callback"); resultCode = AdServicesStatusUtils.STATUS_UNKNOWN_ERROR; } finally { + int overallLatencyMs = mApiServiceLatencyCalculator.getApiServiceOverallLatencyMs(); LogUtil.v( - "Ad Selection with Id:%d completed, attempted notifying success", - result.getAdSelectionId()); + "Ad Selection with Id:%d completed with overall latency %d in ms, " + + "attempted notifying success", + result.getAdSelectionId(), overallLatencyMs); + // TODO(b//253522566): When including logging data from bidding & auction server side + // should be able to differentiate the data from the on-device telemetry. mAdServicesLogger.logFledgeApiCallStats( - AD_SERVICES_API_CALLED__API_NAME__SELECT_ADS, resultCode); + AD_SERVICES_API_CALLED__API_NAME__SELECT_ADS, resultCode, overallLatencyMs); } } @@ -350,8 +342,15 @@ public final class AdSelectionRunner { LogUtil.e(e, "Encountered exception during notifying AdSelection callback"); resultCode = AdServicesStatusUtils.STATUS_UNKNOWN_ERROR; } finally { + int overallLatencyMs = mApiServiceLatencyCalculator.getApiServiceOverallLatencyMs(); + LogUtil.v( + "Ad Selection with Id:%d completed with overall latency %d in ms, " + + "attempted notifying success for a silent failure", + mAdSelectionIdGenerator.generateId(), overallLatencyMs); + // TODO(b//253522566): When including logging data from bidding & auction server side + // should be able to differentiate the data from the on-device telemetry. mAdServicesLogger.logFledgeApiCallStats( - AD_SERVICES_API_CALLED__API_NAME__SELECT_ADS, resultCode); + AD_SERVICES_API_CALLED__API_NAME__SELECT_ADS, resultCode, overallLatencyMs); } } @@ -372,6 +371,8 @@ public final class AdSelectionRunner { resultCode = AdServicesStatusUtils.STATUS_INVALID_ARGUMENT; } else if (t instanceof LimitExceededException) { resultCode = AdServicesStatusUtils.STATUS_RATE_LIMIT_REACHED; + } else if (t instanceof JSSandboxIsNotAvailableException) { + resultCode = AdServicesStatusUtils.STATUS_JS_SANDBOX_UNAVAILABLE; } else { resultCode = AdServicesStatusUtils.STATUS_INTERNAL_ERROR; } @@ -391,8 +392,12 @@ public final class AdSelectionRunner { LogUtil.e(e, "Encountered exception during notifying AdSelection callback"); resultCode = AdServicesStatusUtils.STATUS_UNKNOWN_ERROR; } finally { + int overallLatencyMs = mApiServiceLatencyCalculator.getApiServiceOverallLatencyMs(); + LogUtil.v("Ad Selection failed with overall latency %d in ms", overallLatencyMs); + // TODO(b//253522566): When including logging data from bidding & auction server side + // should be able to differentiate the data from the on-device telemetry. mAdServicesLogger.logFledgeApiCallStats( - AD_SERVICES_API_CALLED__API_NAME__SELECT_ADS, resultCode); + AD_SERVICES_API_CALLED__API_NAME__SELECT_ADS, resultCode, overallLatencyMs); } } @@ -410,60 +415,34 @@ public final class AdSelectionRunner { ListenableFuture<List<DBCustomAudience>> buyerCustomAudience = getBuyersCustomAudience(adSelectionConfig); + ListenableFuture<AdSelectionOrchestrationResult> dbAdSelection = + orchestrateAdSelection(adSelectionConfig, callerPackageName, buyerCustomAudience); - AsyncFunction<List<DBCustomAudience>, List<AdBiddingOutcome>> bidAds = - buyerCAs -> { - return runAdBidding(buyerCAs, adSelectionConfig); - }; - - ListenableFuture<List<AdBiddingOutcome>> biddingOutcome = - Futures.transformAsync(buyerCustomAudience, bidAds, mLightweightExecutorService); - - AsyncFunction<List<AdBiddingOutcome>, List<AdScoringOutcome>> mapBidsToScores = - bids -> { - return runAdScoring(bids, adSelectionConfig); - }; - - ListenableFuture<List<AdScoringOutcome>> scoredAds = - Futures.transformAsync( - biddingOutcome, mapBidsToScores, mLightweightExecutorService); - - Function<List<AdScoringOutcome>, AdScoringOutcome> reduceScoresToWinner = - scores -> { - return getWinningOutcome(scores); - }; - - ListenableFuture<AdScoringOutcome> winningOutcome = - Futures.transform(scoredAds, reduceScoresToWinner, mLightweightExecutorService); - - Function<AdScoringOutcome, Pair<DBAdSelection.Builder, String>> mapWinnerToDBResult = - scoringWinner -> { - return createAdSelectionResult(scoringWinner); - }; - - ListenableFuture<Pair<DBAdSelection.Builder, String>> dbAdSelectionBuilder = - Futures.transform(winningOutcome, mapWinnerToDBResult, mLightweightExecutorService); - - AsyncFunction<Pair<DBAdSelection.Builder, String>, DBAdSelection> saveResultToPersistence = + AsyncFunction<AdSelectionOrchestrationResult, DBAdSelection> saveResultToPersistence = adSelectionAndJs -> { return persistAdSelection( - adSelectionAndJs.first, adSelectionAndJs.second, callerPackageName); + adSelectionAndJs.mDbAdSelectionBuilder, + adSelectionAndJs.mBuyerDecisionLogicJs, + callerPackageName); }; - return FluentFuture.from(dbAdSelectionBuilder) + return FluentFuture.from(dbAdSelection) .transformAsync(saveResultToPersistence, mLightweightExecutorService) .withTimeout( mFlags.getAdSelectionOverallTimeoutMs(), TimeUnit.MILLISECONDS, - // TODO(b/237103033): Comply with thread usage policy for AdServices; - // use a global scheduled executor - new ScheduledThreadPoolExecutor(1)) + mScheduledExecutor) .catching( TimeoutException.class, this::handleTimeoutError, mLightweightExecutorService); } + abstract ListenableFuture<AdSelectionOrchestrationResult> orchestrateAdSelection( + @NonNull AdSelectionConfig adSelectionConfig, + @NonNull String callerPackageName, + @NonNull ListenableFuture<List<DBCustomAudience>> buyerCustomAudience); + @Nullable private DBAdSelection handleTimeoutError(TimeoutException e) { LogUtil.e(e, "Ad Selection exceeded time limit"); @@ -491,136 +470,6 @@ public final class AdSelectionRunner { }); } - private ListenableFuture<List<AdBiddingOutcome>> runAdBidding( - @NonNull final List<DBCustomAudience> customAudiences, - @NonNull final AdSelectionConfig adSelectionConfig) - throws InterruptedException, ExecutionException { - if (customAudiences.isEmpty()) { - LogUtil.w("Cannot invoke bidding on empty list of CAs"); - return Futures.immediateFailedFuture(new Throwable("No CAs found for selection")); - } - - // TODO(b/237004875) : Use common thread pool for parallel execution if possible - ForkJoinPool customThreadPool = new ForkJoinPool(getParallelBiddingCount()); - final AtomicReference<List<ListenableFuture<AdBiddingOutcome>>> bidWinningAds = - new AtomicReference<>(); - - try { - LogUtil.d("Triggering bidding for all %d custom audiences", customAudiences.size()); - customThreadPool - .submit( - () -> { - LogUtil.v("Invoking bidding for #%d CAs", customAudiences.size()); - bidWinningAds.set( - customAudiences.parallelStream() - .map( - customAudience -> { - return runAdBiddingPerCA( - customAudience, - adSelectionConfig); - }) - .collect(Collectors.toList())); - }) - .get(); - } catch (InterruptedException e) { - final String exceptionReason = "Bidding Interrupted Exception"; - LogUtil.e(e, exceptionReason); - throw new InterruptedException(exceptionReason); - } catch (ExecutionException e) { - final String exceptionReason = "Bidding Execution Exception"; - LogUtil.e(e, exceptionReason); - throw new ExecutionException(e.getCause()); - } finally { - customThreadPool.shutdownNow(); - } - return Futures.successfulAsList(bidWinningAds.get()); - } - - private int getParallelBiddingCount() { - int parallelBiddingCountConfigValue = mFlags.getAdSelectionConcurrentBiddingCount(); - int numberOfAvailableProcessors = Runtime.getRuntime().availableProcessors(); - return Math.min(parallelBiddingCountConfigValue, numberOfAvailableProcessors); - } - - private ListenableFuture<AdBiddingOutcome> runAdBiddingPerCA( - @NonNull final DBCustomAudience customAudience, - @NonNull final AdSelectionConfig adSelectionConfig) { - LogUtil.v(String.format("Invoking bidding for CA: %s", customAudience.getName())); - - // TODO(b/233239475) : Validate Buyer signals in Ad Selection Config - AdSelectionSignals buyerSignal = - Optional.ofNullable( - adSelectionConfig - .getPerBuyerSignals() - .get(customAudience.getBuyer())) - .orElse(AdSelectionSignals.EMPTY); - return mAdBidGenerator.runAdBiddingPerCA( - customAudience, - adSelectionConfig.getAdSelectionSignals(), - buyerSignal, - AdSelectionSignals.EMPTY, - adSelectionConfig); - // TODO(b/230569187): get the contextualSignal securely = "invoking app name" - } - - @SuppressLint("DefaultLocale") - private ListenableFuture<List<AdScoringOutcome>> runAdScoring( - @NonNull final List<AdBiddingOutcome> adBiddingOutcomes, - @NonNull final AdSelectionConfig adSelectionConfig) - throws AdServicesException { - LogUtil.v("Got %d bidding outcomes", adBiddingOutcomes.size()); - List<AdBiddingOutcome> validBiddingOutcomes = - adBiddingOutcomes.stream().filter(Objects::nonNull).collect(Collectors.toList()); - - if (validBiddingOutcomes.isEmpty()) { - LogUtil.w("Received empty list of Bidding outcomes"); - throw new IllegalStateException(ERROR_NO_VALID_BIDS_FOR_SCORING); - } - return mAdsScoreGenerator.runAdScoring(validBiddingOutcomes, adSelectionConfig); - } - - private AdScoringOutcome getWinningOutcome( - @NonNull List<AdScoringOutcome> overallAdScoringOutcome) { - LogUtil.v("Scoring completed, generating winning outcome"); - return overallAdScoringOutcome.stream() - .filter(a -> a.getAdWithScore().getScore() > 0) - .max( - (a, b) -> - Double.compare( - a.getAdWithScore().getScore(), - b.getAdWithScore().getScore())) - .orElseThrow(() -> new IllegalStateException(ERROR_NO_WINNING_AD_FOUND)); - } - - /** - * This method populates an Ad Selection result ready to be persisted in DB, with all the fields - * except adSelectionId and creation time, which should be created as close as possible to - * persistence logic - * - * @param scoringWinner Winning Ad for overall Ad Selection - * @return A {@link Pair} with a Builder for {@link DBAdSelection} populated with necessary data - * and a string containing the JS with the decision logic from this buyer. - */ - @VisibleForTesting - Pair<DBAdSelection.Builder, String> createAdSelectionResult( - @NonNull AdScoringOutcome scoringWinner) { - DBAdSelection.Builder dbAdSelectionBuilder = new DBAdSelection.Builder(); - LogUtil.v("Creating Ad Selection result from scoring winner"); - dbAdSelectionBuilder - .setWinningAdBid(scoringWinner.getAdWithScore().getAdWithBid().getBid()) - .setCustomAudienceSignals( - scoringWinner.getCustomAudienceBiddingInfo().getCustomAudienceSignals()) - .setWinningAdRenderUri( - scoringWinner.getAdWithScore().getAdWithBid().getAdData().getRenderUri()) - .setBiddingLogicUri( - scoringWinner.getCustomAudienceBiddingInfo().getBiddingLogicUri()) - .setContextualSignals("{}"); - // TODO(b/230569187): get the contextualSignal securely = "invoking app name" - return Pair.create( - dbAdSelectionBuilder, - scoringWinner.getCustomAudienceBiddingInfo().getBuyerDecisionLogicJs()); - } - private ListenableFuture<DBAdSelection> persistAdSelection( @NonNull DBAdSelection.Builder dbAdSelectionBuilder, @NonNull String buyerDecisionLogicJS, @@ -654,7 +503,7 @@ public final class AdSelectionRunner { * user consent */ private Void assertCallerHasUserConsent() throws ConsentManager.RevokedConsentException { - if (!mConsentManager.getConsent(mContext.getPackageManager()).isGiven()) { + if (!mConsentManager.getConsent().isGiven()) { throw new ConsentManager.RevokedConsentException(); } return null; @@ -793,8 +642,14 @@ public final class AdSelectionRunner { return null; } - private void clearExpiredAdSelectionData() { - Instant expirationTime = mClock.instant().minusSeconds(DAY_IN_SECONDS); - mAdSelectionEntryDao.removeExpiredAdSelection(expirationTime); + static class AdSelectionOrchestrationResult { + DBAdSelection.Builder mDbAdSelectionBuilder; + String mBuyerDecisionLogicJs; + + AdSelectionOrchestrationResult( + DBAdSelection.Builder dbAdSelectionBuilder, String buyerDecisionLogicJs) { + this.mDbAdSelectionBuilder = dbAdSelectionBuilder; + this.mBuyerDecisionLogicJs = buyerDecisionLogicJs; + } } } |