• 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.customaudience;
18 
19 import static com.android.adservices.flags.Flags.FLAG_FLEDGE_ENABLE_CUSTOM_AUDIENCE_COMPONENT_ADS;
20 import static com.android.adservices.flags.Flags.FLAG_FLEDGE_GET_AD_SELECTION_DATA_SELLER_CONFIGURATION_ENABLED;
21 
22 import android.adservices.adselection.GetAdSelectionDataRequest;
23 import android.adservices.common.AdData;
24 import android.adservices.common.AdSelectionSignals;
25 import android.adservices.common.AdTechIdentifier;
26 import android.adservices.common.ComponentAdData;
27 import android.annotation.FlaggedApi;
28 import android.annotation.IntDef;
29 import android.annotation.NonNull;
30 import android.annotation.Nullable;
31 import android.net.Uri;
32 import android.os.OutcomeReceiver;
33 import android.os.Parcel;
34 import android.os.Parcelable;
35 
36 import com.android.adservices.AdServicesParcelableUtil;
37 
38 import java.lang.annotation.Retention;
39 import java.lang.annotation.RetentionPolicy;
40 import java.time.Instant;
41 import java.util.List;
42 import java.util.Objects;
43 import java.util.concurrent.Executor;
44 
45 /**
46  * Represents the information necessary for a custom audience to participate in ad selection.
47  *
48  * <p>A custom audience is an abstract grouping of users with similar demonstrated interests. This
49  * class is a collection of some data stored on a device that is necessary to serve advertisements
50  * targeting a single custom audience.
51  */
52 public final class CustomAudience implements Parcelable {
53     /** @hide */
54     public static final int FLAG_AUCTION_SERVER_REQUEST_DEFAULT = 0;
55 
56     /** @hide */
57     public static final double PRIORITY_DEFAULT = 0.0;
58 
59     /**
60      * This auction server request flag indicates to the service that ads for this {@link
61      * CustomAudience} can be omitted in the server auction payload.
62      */
63     @FlaggedApi(
64             "com.android.adservices.flags.fledge_custom_audience_auction_server_request_flags_enabled")
65     public static final int FLAG_AUCTION_SERVER_REQUEST_OMIT_ADS = 1 << 0;
66 
67     @NonNull private final AdTechIdentifier mBuyer;
68     @NonNull private final String mName;
69     @Nullable private final Instant mActivationTime;
70     @Nullable private final Instant mExpirationTime;
71     @NonNull private final Uri mDailyUpdateUri;
72     @Nullable private final AdSelectionSignals mUserBiddingSignals;
73     @Nullable private final TrustedBiddingData mTrustedBiddingData;
74     @NonNull private final Uri mBiddingLogicUri;
75     @NonNull private final List<AdData> mAds;
76     @NonNull private final List<ComponentAdData> mComponentAds;
77     @AuctionServerRequestFlag private final int mAuctionServerRequestFlags;
78     private final double mPriority;
79 
80     /** @hide */
81     @IntDef(
82             flag = true,
83             prefix = {"FLAG_AUCTION_SERVER_REQUEST"},
84             value = {FLAG_AUCTION_SERVER_REQUEST_DEFAULT, FLAG_AUCTION_SERVER_REQUEST_OMIT_ADS})
85     @Retention(RetentionPolicy.SOURCE)
86     public @interface AuctionServerRequestFlag {}
87 
88     @NonNull
89     public static final Creator<CustomAudience> CREATOR = new Creator<CustomAudience>() {
90         @Override
91         public CustomAudience createFromParcel(@NonNull Parcel in) {
92             Objects.requireNonNull(in);
93 
94             return new CustomAudience(in);
95         }
96 
97         @Override
98         public CustomAudience[] newArray(int size) {
99             return new CustomAudience[size];
100         }
101     };
102 
CustomAudience(@onNull CustomAudience.Builder builder)103     private CustomAudience(@NonNull CustomAudience.Builder builder) {
104         Objects.requireNonNull(builder);
105 
106         mBuyer = builder.mBuyer;
107         mName = builder.mName;
108         mActivationTime = builder.mActivationTime;
109         mExpirationTime = builder.mExpirationTime;
110         mDailyUpdateUri = builder.mDailyUpdateUri;
111         mUserBiddingSignals = builder.mUserBiddingSignals;
112         mTrustedBiddingData = builder.mTrustedBiddingData;
113         mBiddingLogicUri = builder.mBiddingLogicUri;
114         mAds = builder.mAds;
115         mComponentAds = builder.mComponentAds;
116         mAuctionServerRequestFlags = builder.mAuctionServerRequestFlags;
117         mPriority = builder.mPriority;
118     }
119 
CustomAudience(@onNull Parcel in)120     private CustomAudience(@NonNull Parcel in) {
121         Objects.requireNonNull(in);
122 
123         mBuyer = AdTechIdentifier.CREATOR.createFromParcel(in);
124         mName = in.readString();
125         mActivationTime =
126                 AdServicesParcelableUtil.readNullableFromParcel(
127                         in, (sourceParcel) -> Instant.ofEpochMilli(sourceParcel.readLong()));
128         mExpirationTime =
129                 AdServicesParcelableUtil.readNullableFromParcel(
130                         in, (sourceParcel) -> Instant.ofEpochMilli(sourceParcel.readLong()));
131         mDailyUpdateUri = Uri.CREATOR.createFromParcel(in);
132         mUserBiddingSignals =
133                 AdServicesParcelableUtil.readNullableFromParcel(
134                         in, AdSelectionSignals.CREATOR::createFromParcel);
135         mTrustedBiddingData =
136                 AdServicesParcelableUtil.readNullableFromParcel(
137                         in, TrustedBiddingData.CREATOR::createFromParcel);
138         mBiddingLogicUri = Uri.CREATOR.createFromParcel(in);
139         mAds = in.createTypedArrayList(AdData.CREATOR);
140         mComponentAds = in.createTypedArrayList(ComponentAdData.CREATOR);
141         mAuctionServerRequestFlags = in.readInt();
142         mPriority = in.readDouble();
143     }
144 
145     @Override
writeToParcel(@onNull Parcel dest, int flags)146     public void writeToParcel(@NonNull Parcel dest, int flags) {
147         Objects.requireNonNull(dest);
148 
149         mBuyer.writeToParcel(dest, flags);
150         dest.writeString(mName);
151         AdServicesParcelableUtil.writeNullableToParcel(
152                 dest,
153                 mActivationTime,
154                 (targetParcel, sourceInstant) ->
155                         targetParcel.writeLong(sourceInstant.toEpochMilli()));
156         AdServicesParcelableUtil.writeNullableToParcel(
157                 dest,
158                 mExpirationTime,
159                 (targetParcel, sourceInstant) ->
160                         targetParcel.writeLong(sourceInstant.toEpochMilli()));
161         mDailyUpdateUri.writeToParcel(dest, flags);
162         AdServicesParcelableUtil.writeNullableToParcel(
163                 dest,
164                 mUserBiddingSignals,
165                 (targetParcel, sourceSignals) -> sourceSignals.writeToParcel(targetParcel, flags));
166         AdServicesParcelableUtil.writeNullableToParcel(
167                 dest,
168                 mTrustedBiddingData,
169                 (targetParcel, sourceData) -> sourceData.writeToParcel(targetParcel, flags));
170         mBiddingLogicUri.writeToParcel(dest, flags);
171         dest.writeTypedList(mAds);
172         dest.writeTypedList(mComponentAds);
173         dest.writeInt(mAuctionServerRequestFlags);
174         dest.writeDouble(mPriority);
175     }
176 
177     @Override
toString()178     public String toString() {
179         return "CustomAudience{"
180                 + "mBuyer="
181                 + mBuyer
182                 + ", mName='"
183                 + mName
184                 + ", mActivationTime="
185                 + mActivationTime
186                 + ", mExpirationTime="
187                 + mExpirationTime
188                 + ", mDailyUpdateUri="
189                 + mDailyUpdateUri
190                 + ", mUserBiddingSignals="
191                 + mUserBiddingSignals
192                 + ", mTrustedBiddingData="
193                 + mTrustedBiddingData
194                 + ", mBiddingLogicUri="
195                 + mBiddingLogicUri
196                 + ", mAds="
197                 + mAds
198                 + ", mComponentAds="
199                 + mComponentAds
200                 + ", mAuctionServerRequestFlags="
201                 + mAuctionServerRequestFlags
202                 + ", mPriority="
203                 + mPriority
204                 + '}';
205     }
206 
207     /** @hide */
208     @Override
describeContents()209     public int describeContents() {
210         return 0;
211     }
212 
213     /**
214      * A buyer is identified by a domain in the form "buyerexample.com".
215      *
216      * @return an {@link AdTechIdentifier} containing the custom audience's buyer's domain
217      */
218     @NonNull
getBuyer()219     public AdTechIdentifier getBuyer() {
220         return mBuyer;
221     }
222 
223     /**
224      * The custom audience's name is an arbitrary string provided by the owner and buyer on creation
225      * of the {@link CustomAudience} object.
226      *
227      * <p>The overall size of the CA is limited and the size of this field is considered using
228      * {@link String#getBytes()} in {@code UTF-8} encoding.
229      *
230      * @return the String name of the custom audience
231      */
232     @NonNull
getName()233     public String getName() {
234         return mName;
235     }
236 
237     /**
238      * On creation of the {@link CustomAudience} object, an optional activation time may be set in
239      * the future, in order to serve a delayed activation. If the field is not set, the {@link
240      * CustomAudience} will be activated at the time of joining.
241      *
242      * <p>For example, a custom audience for lapsed users may not activate until a threshold of
243      * inactivity is reached, at which point the custom audience's ads will participate in the ad
244      * selection process, potentially redirecting lapsed users to the original owner application.
245      *
246      * <p>The maximum delay in activation is 60 days from initial creation.
247      *
248      * <p>If specified, the activation time must be an earlier instant than the expiration time.
249      *
250      * @return the timestamp {@link Instant}, truncated to milliseconds, after which the custom
251      *     audience is active
252      */
253     @Nullable
getActivationTime()254     public Instant getActivationTime() {
255         return mActivationTime;
256     }
257 
258     /**
259      * Once the expiration time has passed, a custom audience is no longer eligible for daily
260      * ad/bidding data updates or participation in the ad selection process. The custom audience
261      * will then be deleted from memory by the next daily update.
262      *
263      * <p>If no expiration time is provided on creation of the {@link CustomAudience}, expiry will
264      * default to 60 days from activation.
265      *
266      * <p>The maximum expiry is 60 days from initial activation.
267      *
268      * @return the timestamp {@link Instant}, truncated to milliseconds, after which the custom
269      *     audience should be removed
270      */
271     @Nullable
getExpirationTime()272     public Instant getExpirationTime() {
273         return mExpirationTime;
274     }
275 
276     /**
277      * This URI points to a buyer-operated server that hosts updated bidding data and ads metadata
278      * to be used in the on-device ad selection process. The URI must use HTTPS.
279      *
280      * @return the custom audience's daily update URI
281      */
282     @NonNull
getDailyUpdateUri()283     public Uri getDailyUpdateUri() {
284         return mDailyUpdateUri;
285     }
286 
287     /**
288      * User bidding signals are optionally provided by buyers to be consumed by buyer-provided
289      * JavaScript during ad selection in an isolated execution environment.
290      *
291      * <p>If the user bidding signals are not a valid JSON object that can be consumed by the
292      * buyer's JS, the custom audience will not be eligible for ad selection.
293      *
294      * <p>If not specified, the {@link CustomAudience} will not participate in ad selection until
295      * user bidding signals are provided via the daily update for the custom audience.
296      *
297      * @return an {@link AdSelectionSignals} object representing the user bidding signals for the
298      *     custom audience
299      */
300     @Nullable
getUserBiddingSignals()301     public AdSelectionSignals getUserBiddingSignals() {
302         return mUserBiddingSignals;
303     }
304 
305     /**
306      * Trusted bidding data consists of a URI pointing to a trusted server for buyers' bidding data
307      * and a list of keys to query the server with. Note that the keys are arbitrary identifiers
308      * that will only be used to query the trusted server for a buyer's bidding logic during ad
309      * selection.
310      *
311      * <p>If not specified, the {@link CustomAudience} will not participate in ad selection until
312      * trusted bidding data are provided via the daily update for the custom audience.
313      *
314      * @return a {@link TrustedBiddingData} object containing the custom audience's trusted bidding
315      *     data
316      */
317     @Nullable
getTrustedBiddingData()318     public TrustedBiddingData getTrustedBiddingData() {
319         return mTrustedBiddingData;
320     }
321 
322     /**
323      * Returns the target URI used to fetch bidding logic when a custom audience participates in the
324      * ad selection process. The URI must use HTTPS.
325      *
326      * @return the URI for fetching buyer bidding logic
327      */
328     @NonNull
getBiddingLogicUri()329     public Uri getBiddingLogicUri() {
330         return mBiddingLogicUri;
331     }
332 
333     /**
334      * This list of {@link AdData} objects is a full and complete list of the ads that will be
335      * served by this {@link CustomAudience} during the ad selection process.
336      *
337      * <p>If not specified, or if an empty list is provided, the {@link CustomAudience} will not
338      * participate in ad selection until a valid list of ads are provided via the daily update for
339      * the custom audience.
340      *
341      * <p>The combined ads size of the CA is limited and the sizes of each ad's string fields are
342      * considered using {@link String#getBytes()} in {@code UTF-8} encoding.
343      *
344      * @return a {@link List} of {@link AdData} objects representing ads currently served by the
345      *     custom audience
346      */
347     @NonNull
getAds()348     public List<AdData> getAds() {
349         return mAds;
350     }
351 
352     /**
353      * This list of {@link ComponentAdData} objects is a full and complete list of the ad components
354      * that will be served by this {@link CustomAudience} during the ad selection process.
355      *
356      * <p>The combined ads size of the CA is limited and the sizes of each ad's string fields are
357      * considered using {@link String#getBytes()} in {@code UTF-8} encoding.
358      *
359      * @return a {@link List} of {@link ComponentAdData} objects representing component ads
360      *     currently served by the custom audience
361      */
362     @FlaggedApi(FLAG_FLEDGE_ENABLE_CUSTOM_AUDIENCE_COMPONENT_ADS)
363     @NonNull
getComponentAds()364     public List<ComponentAdData> getComponentAds() {
365         return mComponentAds;
366     }
367 
368     /**
369      * Returns the bitfield of auction server request flags. These are flags that influence the
370      * creation of the payload generated by the {@link
371      * android.adservices.adselection.AdSelectionManager#getAdSelectionData(GetAdSelectionDataRequest,
372      * Executor, OutcomeReceiver)} API.
373      *
374      * <p>To create this bitfield, place an {@code |} bitwise operator between each {@link
375      * AuctionServerRequestFlag} to be enabled.
376      */
377     @FlaggedApi(
378             "com.android.adservices.flags.fledge_custom_audience_auction_server_request_flags_enabled")
379     @AuctionServerRequestFlag
getAuctionServerRequestFlags()380     public int getAuctionServerRequestFlags() {
381         return mAuctionServerRequestFlags;
382     }
383 
384     /**
385      * Returns the priority of this CustomAudience with respect to other CustomAudiences for this
386      * buyer.
387      *
388      * <p>This means if there is insufficient space during buyer input generation in the {@link
389      * android.adservices.adselection.AdSelectionManager#getAdSelectionData(GetAdSelectionDataRequest,
390      * Executor, OutcomeReceiver)} call, the service will attempt to include the highest priority
391      * custom audiences first.
392      *
393      * <p>The default value if this field is not set is 0.0.
394      */
395     @FlaggedApi(FLAG_FLEDGE_GET_AD_SELECTION_DATA_SELLER_CONFIGURATION_ENABLED)
getPriority()396     public double getPriority() {
397         return mPriority;
398     }
399 
400     /**
401      * Checks whether two {@link CustomAudience} objects contain the same information.
402      */
403     @Override
equals(Object o)404     public boolean equals(Object o) {
405         if (this == o) return true;
406         if (!(o instanceof CustomAudience)) return false;
407         CustomAudience that = (CustomAudience) o;
408         return mBuyer.equals(that.mBuyer)
409                 && mName.equals(that.mName)
410                 && Objects.equals(mActivationTime, that.mActivationTime)
411                 && Objects.equals(mExpirationTime, that.mExpirationTime)
412                 && mDailyUpdateUri.equals(that.mDailyUpdateUri)
413                 && Objects.equals(mUserBiddingSignals, that.mUserBiddingSignals)
414                 && Objects.equals(mTrustedBiddingData, that.mTrustedBiddingData)
415                 && mBiddingLogicUri.equals(that.mBiddingLogicUri)
416                 && mAds.equals(that.mAds)
417                 && mComponentAds.equals(that.mComponentAds)
418                 && mAuctionServerRequestFlags == that.mAuctionServerRequestFlags
419                 && Double.compare(mPriority, that.mPriority) == 0
420                 && mComponentAds.equals(that.mComponentAds);
421     }
422 
423     /** Returns the hash of the {@link CustomAudience} object's data. */
424     @Override
hashCode()425     public int hashCode() {
426         return Objects.hash(
427                 mBuyer,
428                 mName,
429                 mActivationTime,
430                 mExpirationTime,
431                 mDailyUpdateUri,
432                 mUserBiddingSignals,
433                 mTrustedBiddingData,
434                 mBiddingLogicUri,
435                 mAds,
436                 mComponentAds,
437                 mAuctionServerRequestFlags,
438                 mPriority);
439     }
440 
441     /** Builder for {@link CustomAudience} objects. */
442     public static final class Builder {
443         @Nullable private AdTechIdentifier mBuyer;
444         @Nullable private String mName;
445         @Nullable private Instant mActivationTime;
446         @Nullable private Instant mExpirationTime;
447         @Nullable private Uri mDailyUpdateUri;
448         @Nullable private AdSelectionSignals mUserBiddingSignals;
449         @Nullable private TrustedBiddingData mTrustedBiddingData;
450         @Nullable private Uri mBiddingLogicUri;
451         @Nullable private List<AdData> mAds;
452         @Nullable private List<ComponentAdData> mComponentAds;
453         @AuctionServerRequestFlag private int mAuctionServerRequestFlags;
454         private double mPriority;
455 
456         // TODO(b/232883403): We may need to add @NonNUll members as args.
Builder()457         public Builder() {
458         }
459 
460         /**
461          * Sets the buyer {@link AdTechIdentifier}.
462          *
463          * <p>See {@link #getBuyer()} for more information.
464          */
465         @NonNull
setBuyer(@onNull AdTechIdentifier buyer)466         public CustomAudience.Builder setBuyer(@NonNull AdTechIdentifier buyer) {
467             Objects.requireNonNull(buyer);
468             mBuyer = buyer;
469             return this;
470         }
471 
472         /**
473          * Sets the {@link CustomAudience} object's name.
474          * <p>
475          * See {@link #getName()} for more information.
476          */
477         @NonNull
setName(@onNull String name)478         public CustomAudience.Builder setName(@NonNull String name) {
479             Objects.requireNonNull(name);
480             mName = name;
481             return this;
482         }
483 
484         /**
485          * Sets the time, truncated to milliseconds, after which the {@link CustomAudience} will
486          * serve ads.
487          *
488          * <p>Set to {@code null} in order for this {@link CustomAudience} to be immediately active
489          * and participate in ad selection.
490          *
491          * <p>See {@link #getActivationTime()} for more information.
492          */
493         @NonNull
setActivationTime(@ullable Instant activationTime)494         public CustomAudience.Builder setActivationTime(@Nullable Instant activationTime) {
495             mActivationTime = activationTime;
496             return this;
497         }
498 
499         /**
500          * Sets the time, truncated to milliseconds, after which the {@link CustomAudience} should
501          * be removed.
502          * <p>
503          * See {@link #getExpirationTime()} for more information.
504          */
505         @NonNull
setExpirationTime(@ullable Instant expirationTime)506         public CustomAudience.Builder setExpirationTime(@Nullable Instant expirationTime) {
507             mExpirationTime = expirationTime;
508             return this;
509         }
510 
511         /**
512          * Sets the daily update URI. The URI must use HTTPS.
513          *
514          * <p>See {@link #getDailyUpdateUri()} for more information.
515          */
516         @NonNull
setDailyUpdateUri(@onNull Uri dailyUpdateUri)517         public CustomAudience.Builder setDailyUpdateUri(@NonNull Uri dailyUpdateUri) {
518             Objects.requireNonNull(dailyUpdateUri);
519             mDailyUpdateUri = dailyUpdateUri;
520             return this;
521         }
522 
523         /**
524          * Sets the user bidding signals used in the ad selection process.
525          *
526          * <p>See {@link #getUserBiddingSignals()} for more information.
527          */
528         @NonNull
setUserBiddingSignals( @ullable AdSelectionSignals userBiddingSignals)529         public CustomAudience.Builder setUserBiddingSignals(
530                 @Nullable AdSelectionSignals userBiddingSignals) {
531             mUserBiddingSignals = userBiddingSignals;
532             return this;
533         }
534 
535         /**
536          * Sets the trusted bidding data to be queried and used in the ad selection process.
537          * <p>
538          * See {@link #getTrustedBiddingData()} for more information.
539          */
540         @NonNull
setTrustedBiddingData( @ullable TrustedBiddingData trustedBiddingData)541         public CustomAudience.Builder setTrustedBiddingData(
542                 @Nullable TrustedBiddingData trustedBiddingData) {
543             mTrustedBiddingData = trustedBiddingData;
544             return this;
545         }
546 
547         /**
548          * Sets the URI to fetch bidding logic from for use in the ad selection process. The URI
549          * must use HTTPS.
550          *
551          * <p>See {@link #getBiddingLogicUri()} for more information.
552          */
553         @NonNull
setBiddingLogicUri(@onNull Uri biddingLogicUri)554         public CustomAudience.Builder setBiddingLogicUri(@NonNull Uri biddingLogicUri) {
555             Objects.requireNonNull(biddingLogicUri);
556             mBiddingLogicUri = biddingLogicUri;
557             return this;
558         }
559 
560         /**
561          * Sets the initial remarketing ads served by the custom audience. Will be assigned with an
562          * empty list if not provided.
563          *
564          * <p>See {@link #getAds()} for more information.
565          */
566         @NonNull
setAds(@ullable List<AdData> ads)567         public CustomAudience.Builder setAds(@Nullable List<AdData> ads) {
568             mAds = ads;
569             return this;
570         }
571 
572         /**
573          * Sets the components ads served by the custom audience.
574          *
575          * <p>See {@link #getComponentAds()} for more information.
576          */
577         @FlaggedApi(FLAG_FLEDGE_ENABLE_CUSTOM_AUDIENCE_COMPONENT_ADS)
578         @NonNull
setComponentAds(@onNull List<ComponentAdData> componentAds)579         public CustomAudience.Builder setComponentAds(@NonNull List<ComponentAdData> componentAds) {
580             mComponentAds =
581                     Objects.requireNonNull(componentAds, "The component ads provided are null");
582             return this;
583         }
584 
585         /**
586          * Sets the bitfield of auction server request flags.
587          *
588          * <p>See {@link #getAuctionServerRequestFlags()} for more information.
589          */
590         @FlaggedApi(
591                 "com.android.adservices.flags.fledge_custom_audience_auction_server_request_flags_enabled")
592         @NonNull
setAuctionServerRequestFlags( @uctionServerRequestFlag int auctionServerRequestFlags)593         public CustomAudience.Builder setAuctionServerRequestFlags(
594                 @AuctionServerRequestFlag int auctionServerRequestFlags) {
595             mAuctionServerRequestFlags = auctionServerRequestFlags;
596             return this;
597         }
598 
599         /**
600          * Sets the priority for this custom audience.
601          *
602          * <p>See {@link #getPriority()} for further details.
603          */
604         @FlaggedApi(FLAG_FLEDGE_GET_AD_SELECTION_DATA_SELLER_CONFIGURATION_ENABLED)
605         @NonNull
setPriority(double priority)606         public CustomAudience.Builder setPriority(double priority) {
607             mPriority = priority;
608             return this;
609         }
610 
611         /**
612          * Builds an instance of a {@link CustomAudience}.
613          *
614          * @throws NullPointerException     if any non-null parameter is null
615          * @throws IllegalArgumentException if the expiration time occurs before activation time
616          * @throws IllegalArgumentException if the expiration time is set before the current time
617          */
618         @NonNull
build()619         public CustomAudience build() {
620             Objects.requireNonNull(mBuyer, "The buyer has not been provided");
621             Objects.requireNonNull(mName, "The name has not been provided");
622             Objects.requireNonNull(mDailyUpdateUri, "The daily update URI has not been provided");
623             Objects.requireNonNull(mBiddingLogicUri, "The bidding logic URI has not been provided");
624 
625             // To pass the API lint, we should not allow null Collection.
626             if (mAds == null) {
627                 mAds = List.of();
628             }
629             if (mComponentAds == null) {
630                 mComponentAds = List.of();
631             }
632 
633             return new CustomAudience(this);
634         }
635     }
636 }
637