1 /* 2 * Copyright (C) 2024 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.adselection; 18 19 import static android.adservices.customaudience.CustomAudience.FLAG_AUCTION_SERVER_REQUEST_OMIT_ADS; 20 21 import android.adservices.common.AdTechIdentifier; 22 import android.annotation.NonNull; 23 24 import com.android.adservices.data.customaudience.DBCustomAudience; 25 import com.android.adservices.data.signals.DBEncodedPayload; 26 import com.android.adservices.service.proto.bidding_auction_servers.BiddingAuctionServers; 27 import com.android.adservices.service.stats.BuyerInputGeneratorIntermediateStats; 28 29 import com.google.common.base.Strings; 30 import com.google.common.collect.ImmutableList; 31 import com.google.protobuf.ByteString; 32 33 import java.util.List; 34 import java.util.Map; 35 import java.util.stream.Collectors; 36 37 public class CompressedBuyerInputCreatorHelper { 38 protected static final String EMPTY_USER_BIDDING_SIGNALS = "{}"; 39 private final AuctionServerPayloadMetricsStrategy mAuctionServerPayloadMetricsStrategy; 40 private final boolean mPasExtendedMetricsEnabled; 41 private final boolean mEnableOmitAds; 42 43 private int mEncodedSignalsCount = 0; 44 private int mEncodedSignalsTotalSizeInBytes = 0; 45 private int mEncodedSignalsMaxSizeInBytes = 0; 46 private int mEncodedSignalsMinSizeInBytes = Integer.MAX_VALUE; 47 CompressedBuyerInputCreatorHelper( AuctionServerPayloadMetricsStrategy auctionServerPayloadMetricsStrategy, boolean pasExtendedMetricsEnabled, boolean enableOmitAds)48 public CompressedBuyerInputCreatorHelper( 49 AuctionServerPayloadMetricsStrategy auctionServerPayloadMetricsStrategy, 50 boolean pasExtendedMetricsEnabled, 51 boolean enableOmitAds) { 52 mAuctionServerPayloadMetricsStrategy = auctionServerPayloadMetricsStrategy; 53 mPasExtendedMetricsEnabled = pasExtendedMetricsEnabled; 54 mEnableOmitAds = enableOmitAds; 55 } 56 57 /** 58 * Builds a bidding and auction server custom audience proto from a {@link DBCustomAudience}. 59 */ buildCustomAudienceProtoFrom( DBCustomAudience customAudience)60 public BiddingAuctionServers.BuyerInput.CustomAudience buildCustomAudienceProtoFrom( 61 DBCustomAudience customAudience) { 62 BiddingAuctionServers.BuyerInput.CustomAudience.Builder customAudienceBuilder = 63 BiddingAuctionServers.BuyerInput.CustomAudience.newBuilder(); 64 65 customAudienceBuilder 66 .setName(customAudience.getName()) 67 .setOwner(customAudience.getOwner()) 68 .setUserBiddingSignals(getUserBiddingSignals(customAudience)) 69 .addAllBiddingSignalsKeys(getTrustedBiddingSignalKeys(customAudience)); 70 71 if (shouldIncludeAds(customAudience)) { 72 customAudienceBuilder.addAllAdRenderIds(getAdRenderIds(customAudience)); 73 } 74 return customAudienceBuilder.build(); 75 } 76 77 /** 78 * Builds a bidding and auction server protected signals proto from a {@link DBEncodedPayload}. 79 */ buildProtectedSignalsProtoFrom( DBEncodedPayload dbEncodedSignalsPayload)80 public BiddingAuctionServers.ProtectedAppSignals buildProtectedSignalsProtoFrom( 81 DBEncodedPayload dbEncodedSignalsPayload) { 82 BiddingAuctionServers.ProtectedAppSignals.Builder protectedSignalsBuilder = 83 BiddingAuctionServers.ProtectedAppSignals.newBuilder(); 84 85 return protectedSignalsBuilder 86 .setAppInstallSignals( 87 ByteString.copyFrom(dbEncodedSignalsPayload.getEncodedPayload())) 88 .setEncodingVersion(dbEncodedSignalsPayload.getVersion()) 89 .build(); 90 } 91 getUserBiddingSignals(DBCustomAudience customAudience)92 protected String getUserBiddingSignals(DBCustomAudience customAudience) { 93 return customAudience.getUserBiddingSignals() == null 94 ? EMPTY_USER_BIDDING_SIGNALS 95 : customAudience.getUserBiddingSignals().toString(); 96 } 97 getAdRenderIds(DBCustomAudience dbCustomAudience)98 private List<String> getAdRenderIds(DBCustomAudience dbCustomAudience) { 99 return dbCustomAudience.getAds().stream() 100 .filter(ad -> !Strings.isNullOrEmpty(ad.getAdRenderId())) 101 .map(ad -> ad.getAdRenderId()) 102 .collect(Collectors.toList()); 103 } 104 shouldIncludeAds(DBCustomAudience customAudience)105 private boolean shouldIncludeAds(DBCustomAudience customAudience) { 106 return !(mEnableOmitAds 107 && ((customAudience.getAuctionServerRequestFlags() 108 & FLAG_AUCTION_SERVER_REQUEST_OMIT_ADS) 109 != 0)); 110 } 111 getTrustedBiddingSignalKeys(@onNull DBCustomAudience customAudience)112 protected List<String> getTrustedBiddingSignalKeys(@NonNull DBCustomAudience customAudience) { 113 List<String> biddingSignalKeys = customAudience.getTrustedBiddingData().getKeys(); 114 // If the bidding signal keys is just the CA name, we don't need to pass it to the server. 115 if (biddingSignalKeys.size() == 1 116 && customAudience.getName().equals(biddingSignalKeys.get(0))) { 117 return ImmutableList.of(); 118 } 119 120 // Remove the CA name from the bidding signal keys list to save space. 121 biddingSignalKeys.remove(customAudience.getName()); 122 return biddingSignalKeys; 123 } 124 calculateEncodedSignalsInBytes(byte[] encodedPayload)125 private int calculateEncodedSignalsInBytes(byte[] encodedPayload) { 126 return encodedPayload.length; 127 } 128 129 /** Invokes {@link AuctionServerPayloadMetricsStrategy} to add per buyer intermediate stats. */ addToBuyerIntermediateStats( Map<AdTechIdentifier, BuyerInputGeneratorIntermediateStats> perBuyerStats, DBCustomAudience dbCustomAudience, BiddingAuctionServers.BuyerInput.CustomAudience customAudience)130 public void addToBuyerIntermediateStats( 131 Map<AdTechIdentifier, BuyerInputGeneratorIntermediateStats> perBuyerStats, 132 DBCustomAudience dbCustomAudience, 133 BiddingAuctionServers.BuyerInput.CustomAudience customAudience) { 134 mAuctionServerPayloadMetricsStrategy.addToBuyerIntermediateStats( 135 perBuyerStats, dbCustomAudience, customAudience); 136 } 137 138 /** Increments PAS extended metrics based on the length of the encoded payload. */ incrementPasExtendedMetrics(byte[] encodedPayload)139 public void incrementPasExtendedMetrics(byte[] encodedPayload) { 140 if (mPasExtendedMetricsEnabled) { 141 int encodedSignalsInBytes = calculateEncodedSignalsInBytes(encodedPayload); 142 mEncodedSignalsCount += 1; 143 mEncodedSignalsTotalSizeInBytes += encodedSignalsInBytes; 144 mEncodedSignalsMaxSizeInBytes = 145 Math.max(mEncodedSignalsMaxSizeInBytes, encodedSignalsInBytes); 146 mEncodedSignalsMinSizeInBytes = 147 Math.min(mEncodedSignalsMinSizeInBytes, encodedSignalsInBytes); 148 } 149 } 150 151 /** Logs the buyer input generated stats. */ logBuyerInputGeneratedStats( Map<AdTechIdentifier, BuyerInputGeneratorIntermediateStats> perBuyerStats)152 public void logBuyerInputGeneratedStats( 153 Map<AdTechIdentifier, BuyerInputGeneratorIntermediateStats> perBuyerStats) { 154 // Log per buyer stats if feature is enabled 155 if (mPasExtendedMetricsEnabled) { 156 mAuctionServerPayloadMetricsStrategy 157 .logGetAdSelectionDataBuyerInputGeneratedStatsWithExtendedPasMetrics( 158 perBuyerStats, 159 mEncodedSignalsCount, 160 mEncodedSignalsTotalSizeInBytes, 161 mEncodedSignalsMaxSizeInBytes, 162 mEncodedSignalsMinSizeInBytes); 163 } else { 164 mAuctionServerPayloadMetricsStrategy.logGetAdSelectionDataBuyerInputGeneratedStats( 165 perBuyerStats); 166 } 167 } 168 } 169