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 package android.adservices.adselection; 17 18 import android.adservices.common.AdSelectionSignals; 19 import android.adservices.common.AdTechIdentifier; 20 import android.annotation.NonNull; 21 import android.net.Uri; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 25 import com.android.adservices.AdServicesParcelableUtil; 26 27 import java.util.Collections; 28 import java.util.List; 29 import java.util.Map; 30 import java.util.Objects; 31 32 /** 33 * Contains the configuration of the ad selection process. 34 * 35 * <p>Instances of this class are created by SDKs to be provided as arguments to the {@link 36 * AdSelectionManager#selectAds} and {@link AdSelectionManager#reportImpression} methods in {@link 37 * AdSelectionManager}. 38 */ 39 // TODO(b/233280314): investigate on adSelectionConfig optimization by merging mCustomAudienceBuyers 40 // and mPerBuyerSignals. 41 public final class AdSelectionConfig implements Parcelable { 42 @NonNull private final AdTechIdentifier mSeller; 43 @NonNull private final Uri mDecisionLogicUri; 44 @NonNull private final List<AdTechIdentifier> mCustomAudienceBuyers; 45 @NonNull private final AdSelectionSignals mAdSelectionSignals; 46 @NonNull private final AdSelectionSignals mSellerSignals; 47 @NonNull private final Map<AdTechIdentifier, AdSelectionSignals> mPerBuyerSignals; 48 @NonNull private final Map<AdTechIdentifier, ContextualAds> mBuyerContextualAds; 49 @NonNull private final Uri mTrustedScoringSignalsUri; 50 51 @NonNull 52 public static final Creator<AdSelectionConfig> CREATOR = 53 new Creator<AdSelectionConfig>() { 54 @Override 55 public AdSelectionConfig createFromParcel(@NonNull Parcel in) { 56 Objects.requireNonNull(in); 57 return new AdSelectionConfig(in); 58 } 59 60 @Override 61 public AdSelectionConfig[] newArray(int size) { 62 return new AdSelectionConfig[size]; 63 } 64 }; 65 AdSelectionConfig( @onNull AdTechIdentifier seller, @NonNull Uri decisionLogicUri, @NonNull List<AdTechIdentifier> customAudienceBuyers, @NonNull AdSelectionSignals adSelectionSignals, @NonNull AdSelectionSignals sellerSignals, @NonNull Map<AdTechIdentifier, AdSelectionSignals> perBuyerSignals, @NonNull Map<AdTechIdentifier, ContextualAds> perBuyerContextualAds, @NonNull Uri trustedScoringSignalsUri)66 private AdSelectionConfig( 67 @NonNull AdTechIdentifier seller, 68 @NonNull Uri decisionLogicUri, 69 @NonNull List<AdTechIdentifier> customAudienceBuyers, 70 @NonNull AdSelectionSignals adSelectionSignals, 71 @NonNull AdSelectionSignals sellerSignals, 72 @NonNull Map<AdTechIdentifier, AdSelectionSignals> perBuyerSignals, 73 @NonNull Map<AdTechIdentifier, ContextualAds> perBuyerContextualAds, 74 @NonNull Uri trustedScoringSignalsUri) { 75 this.mSeller = seller; 76 this.mDecisionLogicUri = decisionLogicUri; 77 this.mCustomAudienceBuyers = customAudienceBuyers; 78 this.mAdSelectionSignals = adSelectionSignals; 79 this.mSellerSignals = sellerSignals; 80 this.mPerBuyerSignals = perBuyerSignals; 81 this.mBuyerContextualAds = perBuyerContextualAds; 82 this.mTrustedScoringSignalsUri = trustedScoringSignalsUri; 83 } 84 AdSelectionConfig(@onNull Parcel in)85 private AdSelectionConfig(@NonNull Parcel in) { 86 Objects.requireNonNull(in); 87 mSeller = AdTechIdentifier.CREATOR.createFromParcel(in); 88 mDecisionLogicUri = Uri.CREATOR.createFromParcel(in); 89 mCustomAudienceBuyers = in.createTypedArrayList(AdTechIdentifier.CREATOR); 90 mAdSelectionSignals = AdSelectionSignals.CREATOR.createFromParcel(in); 91 mSellerSignals = AdSelectionSignals.CREATOR.createFromParcel(in); 92 mPerBuyerSignals = 93 AdServicesParcelableUtil.readMapFromParcel( 94 in, AdTechIdentifier::fromString, AdSelectionSignals.class); 95 mBuyerContextualAds = 96 AdServicesParcelableUtil.readMapFromParcel( 97 in, AdTechIdentifier::fromString, ContextualAds.class); 98 mTrustedScoringSignalsUri = Uri.CREATOR.createFromParcel(in); 99 } 100 101 @Override describeContents()102 public int describeContents() { 103 return 0; 104 } 105 106 @Override writeToParcel(@onNull Parcel dest, int flags)107 public void writeToParcel(@NonNull Parcel dest, int flags) { 108 Objects.requireNonNull(dest); 109 110 mSeller.writeToParcel(dest, flags); 111 mDecisionLogicUri.writeToParcel(dest, flags); 112 dest.writeTypedList(mCustomAudienceBuyers); 113 mAdSelectionSignals.writeToParcel(dest, flags); 114 mSellerSignals.writeToParcel(dest, flags); 115 AdServicesParcelableUtil.writeMapToParcel(dest, mPerBuyerSignals); 116 AdServicesParcelableUtil.writeMapToParcel(dest, mBuyerContextualAds); 117 mTrustedScoringSignalsUri.writeToParcel(dest, flags); 118 } 119 120 @Override equals(Object o)121 public boolean equals(Object o) { 122 if (this == o) return true; 123 if (!(o instanceof AdSelectionConfig)) return false; 124 AdSelectionConfig that = (AdSelectionConfig) o; 125 return Objects.equals(mSeller, that.mSeller) 126 && Objects.equals(mDecisionLogicUri, that.mDecisionLogicUri) 127 && Objects.equals(mCustomAudienceBuyers, that.mCustomAudienceBuyers) 128 && Objects.equals(mAdSelectionSignals, that.mAdSelectionSignals) 129 && Objects.equals(mSellerSignals, that.mSellerSignals) 130 && Objects.equals(mPerBuyerSignals, that.mPerBuyerSignals) 131 && Objects.equals(mBuyerContextualAds, that.mBuyerContextualAds) 132 && Objects.equals(mTrustedScoringSignalsUri, that.mTrustedScoringSignalsUri); 133 } 134 135 @Override hashCode()136 public int hashCode() { 137 return Objects.hash( 138 mSeller, 139 mDecisionLogicUri, 140 mCustomAudienceBuyers, 141 mAdSelectionSignals, 142 mSellerSignals, 143 mPerBuyerSignals, 144 mBuyerContextualAds, 145 mTrustedScoringSignalsUri); 146 } 147 148 /** 149 * @return a new builder instance created from this object's cloned data 150 * @hide 151 */ 152 @NonNull cloneToBuilder()153 public AdSelectionConfig.Builder cloneToBuilder() { 154 return new AdSelectionConfig.Builder() 155 .setSeller(this.getSeller()) 156 .setBuyerContextualAds(this.getBuyerContextualAds()) 157 .setAdSelectionSignals(this.getAdSelectionSignals()) 158 .setCustomAudienceBuyers(this.getCustomAudienceBuyers()) 159 .setDecisionLogicUri(this.getDecisionLogicUri()) 160 .setPerBuyerSignals(this.getPerBuyerSignals()) 161 .setSellerSignals(this.getSellerSignals()) 162 .setTrustedScoringSignalsUri(this.getTrustedScoringSignalsUri()); 163 } 164 165 /** @return a AdTechIdentifier of the seller, for example "www.example-ssp.com" */ 166 @NonNull getSeller()167 public AdTechIdentifier getSeller() { 168 return mSeller; 169 } 170 171 /** 172 * @return the URI used to retrieve the JS code containing the seller/SSP scoreAd function used 173 * during the ad selection and reporting processes 174 */ 175 @NonNull getDecisionLogicUri()176 public Uri getDecisionLogicUri() { 177 return mDecisionLogicUri; 178 } 179 180 /** 181 * @return a list of custom audience buyers allowed by the SSP to participate in the ad 182 * selection process 183 */ 184 @NonNull getCustomAudienceBuyers()185 public List<AdTechIdentifier> getCustomAudienceBuyers() { 186 return mCustomAudienceBuyers; 187 } 188 189 /** 190 * @return JSON in an AdSelectionSignals object, fetched from the AdSelectionConfig and consumed 191 * by the JS logic fetched from the DSP, represents signals given to the participating 192 * buyers in the ad selection and reporting processes. 193 */ 194 @NonNull getAdSelectionSignals()195 public AdSelectionSignals getAdSelectionSignals() { 196 return mAdSelectionSignals; 197 } 198 199 /** 200 * @return JSON in an AdSelectionSignals object, provided by the SSP and consumed by the JS 201 * logic fetched from the SSP, represents any information that the SSP used in the ad 202 * scoring process to tweak the results of the ad selection process (e.g. brand safety 203 * checks, excluded contextual ads). 204 */ 205 @NonNull getSellerSignals()206 public AdSelectionSignals getSellerSignals() { 207 return mSellerSignals; 208 } 209 210 /** 211 * @return a Map of buyers and AdSelectionSignals, fetched from the AdSelectionConfig and 212 * consumed by the JS logic fetched from the DSP, representing any information that each 213 * buyer would provide during ad selection to participants (such as bid floor, ad selection 214 * type, etc.) 215 */ 216 @NonNull getPerBuyerSignals()217 public Map<AdTechIdentifier, AdSelectionSignals> getPerBuyerSignals() { 218 return mPerBuyerSignals; 219 } 220 221 /** 222 * @return a Map of buyers and corresponding Contextual Ads, these ads are expected to be 223 * pre-downloaded from the contextual path and injected into Ad Selection. 224 * @hide 225 */ 226 @NonNull getBuyerContextualAds()227 public Map<AdTechIdentifier, ContextualAds> getBuyerContextualAds() { 228 return mBuyerContextualAds; 229 } 230 231 /** 232 * @return URI endpoint of sell-side trusted signal from which creative specific realtime 233 * information can be fetched from. 234 */ 235 @NonNull getTrustedScoringSignalsUri()236 public Uri getTrustedScoringSignalsUri() { 237 return mTrustedScoringSignalsUri; 238 } 239 240 /** Builder for {@link AdSelectionConfig} object. */ 241 public static final class Builder { 242 private AdTechIdentifier mSeller; 243 private Uri mDecisionLogicUri; 244 private List<AdTechIdentifier> mCustomAudienceBuyers; 245 private AdSelectionSignals mAdSelectionSignals = AdSelectionSignals.EMPTY; 246 private AdSelectionSignals mSellerSignals = AdSelectionSignals.EMPTY; 247 private Map<AdTechIdentifier, AdSelectionSignals> mPerBuyerSignals = Collections.emptyMap(); 248 private Map<AdTechIdentifier, ContextualAds> mBuyerContextualAds = Collections.emptyMap(); 249 private Uri mTrustedScoringSignalsUri; 250 Builder()251 public Builder() {} 252 253 /** 254 * Sets the seller identifier. 255 * 256 * <p>See {@link #getSeller()} for more details. 257 */ 258 @NonNull setSeller(@onNull AdTechIdentifier seller)259 public AdSelectionConfig.Builder setSeller(@NonNull AdTechIdentifier seller) { 260 Objects.requireNonNull(seller); 261 262 this.mSeller = seller; 263 return this; 264 } 265 266 /** 267 * Sets the URI used to fetch decision logic for use in the ad selection process. 268 * 269 * <p>See {@link #getDecisionLogicUri()} for more details. 270 */ 271 @NonNull setDecisionLogicUri(@onNull Uri decisionLogicUri)272 public AdSelectionConfig.Builder setDecisionLogicUri(@NonNull Uri decisionLogicUri) { 273 Objects.requireNonNull(decisionLogicUri); 274 275 this.mDecisionLogicUri = decisionLogicUri; 276 return this; 277 } 278 279 /** 280 * Sets the list of allowed buyers. 281 * 282 * <p>See {@link #getCustomAudienceBuyers()} for more details. 283 */ 284 @NonNull setCustomAudienceBuyers( @onNull List<AdTechIdentifier> customAudienceBuyers)285 public AdSelectionConfig.Builder setCustomAudienceBuyers( 286 @NonNull List<AdTechIdentifier> customAudienceBuyers) { 287 Objects.requireNonNull(customAudienceBuyers); 288 289 this.mCustomAudienceBuyers = customAudienceBuyers; 290 return this; 291 } 292 293 /** 294 * Sets the signals provided to buyers during ad selection bid generation. 295 * 296 * <p>If not set, defaults to the empty JSON. 297 * 298 * <p>See {@link #getAdSelectionSignals()} for more details. 299 */ 300 @NonNull setAdSelectionSignals( @onNull AdSelectionSignals adSelectionSignals)301 public AdSelectionConfig.Builder setAdSelectionSignals( 302 @NonNull AdSelectionSignals adSelectionSignals) { 303 Objects.requireNonNull(adSelectionSignals); 304 305 this.mAdSelectionSignals = adSelectionSignals; 306 return this; 307 } 308 309 /** 310 * Set the signals used to modify ad selection results. 311 * 312 * <p>If not set, defaults to the empty JSON. 313 * 314 * <p>See {@link #getSellerSignals()} for more details. 315 */ 316 @NonNull setSellerSignals( @onNull AdSelectionSignals sellerSignals)317 public AdSelectionConfig.Builder setSellerSignals( 318 @NonNull AdSelectionSignals sellerSignals) { 319 Objects.requireNonNull(sellerSignals); 320 321 this.mSellerSignals = sellerSignals; 322 return this; 323 } 324 325 /** 326 * Sets the signals provided by each buyer during ad selection. 327 * 328 * <p>If not set, defaults to an empty map. 329 * 330 * <p>See {@link #getPerBuyerSignals()} for more details. 331 */ 332 @NonNull setPerBuyerSignals( @onNull Map<AdTechIdentifier, AdSelectionSignals> perBuyerSignals)333 public AdSelectionConfig.Builder setPerBuyerSignals( 334 @NonNull Map<AdTechIdentifier, AdSelectionSignals> perBuyerSignals) { 335 Objects.requireNonNull(perBuyerSignals); 336 337 this.mPerBuyerSignals = perBuyerSignals; 338 return this; 339 } 340 341 /** 342 * Sets the contextual Ads corresponding to each buyer during ad selection. 343 * 344 * <p>If not set, defaults to an empty map. 345 * 346 * <p>See {@link #getBuyerContextualAds()} ()} for more details. 347 * 348 * @hide 349 */ 350 @NonNull setBuyerContextualAds( @onNull Map<AdTechIdentifier, ContextualAds> buyerContextualAds)351 public AdSelectionConfig.Builder setBuyerContextualAds( 352 @NonNull Map<AdTechIdentifier, ContextualAds> buyerContextualAds) { 353 Objects.requireNonNull(buyerContextualAds); 354 355 this.mBuyerContextualAds = buyerContextualAds; 356 return this; 357 } 358 359 /** 360 * Sets the URI endpoint of sell-side trusted signal from which creative specific realtime 361 * information can be fetched from. 362 * 363 * <p>If {@link Uri#EMPTY} is passed then network call will be skipped and {@link 364 * AdSelectionSignals#EMPTY} will be passed to ad selection. 365 * 366 * <p>See {@link #getTrustedScoringSignalsUri()} for more details. 367 */ 368 @NonNull setTrustedScoringSignalsUri( @onNull Uri trustedScoringSignalsUri)369 public AdSelectionConfig.Builder setTrustedScoringSignalsUri( 370 @NonNull Uri trustedScoringSignalsUri) { 371 Objects.requireNonNull(trustedScoringSignalsUri); 372 373 this.mTrustedScoringSignalsUri = trustedScoringSignalsUri; 374 return this; 375 } 376 377 /** 378 * Builds an {@link AdSelectionConfig} instance. 379 * 380 * @throws NullPointerException if any required params are null 381 */ 382 @NonNull build()383 public AdSelectionConfig build() { 384 Objects.requireNonNull(mSeller); 385 Objects.requireNonNull(mDecisionLogicUri); 386 Objects.requireNonNull(mCustomAudienceBuyers); 387 Objects.requireNonNull(mAdSelectionSignals); 388 Objects.requireNonNull(mSellerSignals); 389 Objects.requireNonNull(mPerBuyerSignals); 390 Objects.requireNonNull(mBuyerContextualAds); 391 Objects.requireNonNull(mTrustedScoringSignalsUri); 392 return new AdSelectionConfig( 393 mSeller, 394 mDecisionLogicUri, 395 mCustomAudienceBuyers, 396 mAdSelectionSignals, 397 mSellerSignals, 398 mPerBuyerSignals, 399 mBuyerContextualAds, 400 mTrustedScoringSignalsUri); 401 } 402 } 403 } 404