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.measurement;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.net.Uri;
23 import android.util.Pair;
24 
25 import com.android.adservices.LoggerFactory;
26 import com.android.adservices.service.Flags;
27 import com.android.adservices.service.FlagsFactory;
28 import com.android.adservices.service.measurement.aggregation.AggregatableAttributionSource;
29 import com.android.adservices.service.measurement.noising.Combinatorics;
30 import com.android.adservices.service.measurement.noising.SourceNoiseHandler;
31 import com.android.adservices.service.measurement.reporting.EventReportWindowCalcDelegate;
32 import com.android.adservices.service.measurement.util.UnsignedLong;
33 import com.android.adservices.service.measurement.util.Validation;
34 import com.android.internal.annotations.VisibleForTesting;
35 
36 import com.google.common.collect.ImmutableMultiset;
37 
38 import org.json.JSONArray;
39 import org.json.JSONException;
40 import org.json.JSONObject;
41 
42 import java.lang.annotation.Retention;
43 import java.lang.annotation.RetentionPolicy;
44 import java.math.BigInteger;
45 import java.util.ArrayList;
46 import java.util.Collections;
47 import java.util.HashMap;
48 import java.util.Iterator;
49 import java.util.List;
50 import java.util.Map;
51 import java.util.Objects;
52 import java.util.Optional;
53 import java.util.TreeMap;
54 import java.util.concurrent.TimeUnit;
55 
56 /**
57  * POJO for Source.
58  */
59 public class Source {
60 
61     public static final long DEFAULT_MAX_EVENT_STATES = 3L;
62 
63     private String mId;
64     private UnsignedLong mEventId;
65     private Uri mPublisher;
66     @EventSurfaceType private int mPublisherType;
67     private List<Uri> mAppDestinations;
68     private List<Uri> mWebDestinations;
69     private String mEnrollmentId;
70     private Uri mRegistrant;
71     private SourceType mSourceType;
72     private long mPriority;
73     @Status private int mStatus;
74     private long mEventTime;
75     private long mExpiryTime;
76     @Nullable private Long mEventReportWindow;
77     @Nullable private String mEventReportWindows;
78     private long mAggregatableReportWindow;
79     private long mReinstallReattributionWindow;
80     private List<UnsignedLong> mAggregateReportDedupKeys;
81     private List<UnsignedLong> mEventReportDedupKeys;
82     @AttributionMode private int mAttributionMode;
83     private long mInstallAttributionWindow;
84     private long mInstallCooldownWindow;
85     @Nullable private UnsignedLong mDebugKey;
86     private boolean mIsInstallAttributed;
87     private boolean mIsDebugReporting;
88     private String mFilterDataString;
89     @Nullable private String mSharedFilterDataKeys;
90     private FilterMap mFilterData;
91     private String mAggregateSource;
92     private int mAggregateContributions;
93     private Optional<AggregatableAttributionSource> mAggregatableAttributionSource;
94     private boolean mAdIdPermission;
95     private boolean mArDebugPermission;
96     @Nullable private String mRegistrationId;
97     @Nullable private String mSharedAggregationKeys;
98     @Nullable private Long mInstallTime;
99     @Nullable private String mParentId;
100     @Nullable private String mDebugJoinKey;
101     @Nullable private List<AttributedTrigger> mAttributedTriggers;
102     @Nullable private TriggerSpecs mTriggerSpecs;
103     @Nullable private String mTriggerSpecsString;
104     @Nullable private Long mNumStates;
105     @Nullable private Double mFlipProbability;
106     @Nullable private Integer mMaxEventLevelReports;
107     @Nullable private String mEventAttributionStatusString;
108     @Nullable private String mPrivacyParametersString = null;
109     private TriggerDataMatching mTriggerDataMatching;
110     @Nullable private String mPlatformAdId;
111     @Nullable private String mDebugAdId;
112     private Uri mRegistrationOrigin;
113     private boolean mCoarseEventReportDestinations;
114     @Nullable private UnsignedLong mSharedDebugKey;
115     private List<Pair<Long, Long>> mParsedEventReportWindows;
116     private boolean mDropSourceIfInstalled;
117     @Nullable private List<String> mAttributionScopes;
118     @Nullable private Long mAttributionScopeLimit;
119     @Nullable private Long mMaxEventStates;
120 
121     /**
122      * Parses and returns the event_report_windows Returns null if parsing fails or if there is no
123      * windows provided by user.
124      */
125     @Nullable
parsedProcessedEventReportWindows()126     public List<Pair<Long, Long>> parsedProcessedEventReportWindows() {
127         if (mParsedEventReportWindows != null) {
128             return mParsedEventReportWindows;
129         }
130 
131         if (mEventReportWindows == null) {
132             return null;
133         }
134 
135         List<Pair<Long, Long>> rawWindows = parseEventReportWindows(mEventReportWindows);
136         if (rawWindows == null) {
137             return null;
138         }
139         // Append Event Time
140         mParsedEventReportWindows = new ArrayList<>();
141 
142         for (Pair<Long, Long> window : rawWindows) {
143             mParsedEventReportWindows.add(
144                     new Pair<>(mEventTime + window.first, mEventTime + window.second));
145         }
146         return mParsedEventReportWindows;
147     }
148 
149     /**
150      * Returns parsed or default value of event report windows (can be used during {@code Source}
151      * construction since the method does not require a {@code Source} object).
152      *
153      * @param eventReportWindows string to be parsed
154      * @param sourceType Source's Type
155      * @param expiryDelta relative expiry value
156      * @param flags Flags
157      * @return parsed or default value
158      */
159     @Nullable
getOrDefaultEventReportWindowsForFlex( @ullable JSONObject eventReportWindows, @NonNull SourceType sourceType, long expiryDelta, @NonNull Flags flags)160     public static List<Pair<Long, Long>> getOrDefaultEventReportWindowsForFlex(
161             @Nullable JSONObject eventReportWindows,
162             @NonNull SourceType sourceType,
163             long expiryDelta,
164             @NonNull Flags flags) {
165         if (eventReportWindows == null) {
166             return getDefaultEventReportWindowsForFlex(expiryDelta, sourceType, flags);
167         }
168         return parseEventReportWindows(eventReportWindows);
169     }
170 
171     /** Parses the provided eventReportWindows. Returns null if parsing fails */
172     @Nullable
parseEventReportWindows( @onNull String eventReportWindows)173     public static List<Pair<Long, Long>> parseEventReportWindows(
174             @NonNull String eventReportWindows) {
175         try {
176             JSONObject jsonObject = new JSONObject(eventReportWindows);
177             return parseEventReportWindows(jsonObject);
178         } catch (JSONException e) {
179             LoggerFactory.getMeasurementLogger()
180                     .e(e, "Invalid JSON encountered: event_report_windows");
181             return null;
182         }
183     }
184 
185     /** Parses the provided eventReportWindows. Returns null if parsing fails */
186     @Nullable
parseEventReportWindows( @onNull JSONObject jsonObject)187     public static List<Pair<Long, Long>> parseEventReportWindows(
188             @NonNull JSONObject jsonObject) {
189         List<Pair<Long, Long>> result = new ArrayList<>();
190         try {
191             long startTime = 0L;
192             if (!jsonObject.isNull("start_time")) {
193                 startTime = jsonObject.getLong("start_time");
194             }
195             JSONArray endTimesJSON = jsonObject.getJSONArray("end_times");
196 
197             for (int i = 0; i < endTimesJSON.length(); i++) {
198                 long endTime = endTimesJSON.getLong(i);
199                 Pair<Long, Long> window = Pair.create(startTime, endTime);
200                 result.add(window);
201                 startTime = endTime;
202             }
203         } catch (JSONException e) {
204             LoggerFactory.getMeasurementLogger()
205                     .e(e, "Invalid JSON encountered: event_report_windows");
206             return null;
207         }
208         return result;
209     }
210 
getDefaultEventReportWindowsForFlex( long expiryDelta, SourceType sourceType, Flags flags)211     private static List<Pair<Long, Long>> getDefaultEventReportWindowsForFlex(
212             long expiryDelta, SourceType sourceType, Flags flags) {
213         List<Pair<Long, Long>> result = new ArrayList<>();
214         // Obtain default early report windows without regard to install-related behaviour.
215         List<Long> defaultEarlyWindowEnds =
216                 EventReportWindowCalcDelegate.getDefaultEarlyReportingWindowEnds(sourceType, false);
217         List<Long> earlyWindowEnds =
218                 new EventReportWindowCalcDelegate(flags)
219                         .getConfiguredOrDefaultEarlyReportingWindowEnds(
220                                 sourceType, defaultEarlyWindowEnds);
221         long windowStart = 0;
222         for (long earlyWindowEnd : earlyWindowEnds) {
223             if (earlyWindowEnd >= expiryDelta) {
224                 break;
225             }
226             result.add(Pair.create(windowStart, earlyWindowEnd));
227             windowStart = earlyWindowEnd;
228         }
229         result.add(Pair.create(windowStart, expiryDelta));
230         return result;
231     }
232 
233     /**
234      * Checks if the source has a valid number of report states and sets the value. mNumStates will
235      * not be set if invalid.
236      *
237      * @param flags flag values
238      */
validateAndSetNumReportStates(Flags flags)239     public boolean validateAndSetNumReportStates(Flags flags) {
240         if (mTriggerSpecs == null) {
241             long reportStateCountLimit = flags.getMeasurementMaxReportStatesPerSourceRegistration();
242             EventReportWindowCalcDelegate eventReportWindowCalcDelegate =
243                     new EventReportWindowCalcDelegate(flags);
244             int reportingWindowCountForNoising =
245                     eventReportWindowCalcDelegate.getReportingWindowCountForNoising(this);
246 
247             int numStars = eventReportWindowCalcDelegate.getMaxReportCount(this);
248             int numBars = getTriggerDataCardinality()
249                     * reportingWindowCountForNoising
250                     * getDestinationTypeMultiplier(flags);
251 
252             long numStates = Combinatorics.getNumberOfStarsAndBarsSequences(numStars, numBars);
253             if (numStates > reportStateCountLimit) {
254                 return false;
255             }
256 
257             setNumStates(numStates);
258 
259             return true;
260         } else {
261             return mTriggerSpecs.hasValidReportStateCount(this, flags);
262         }
263     }
264 
265     /**
266      * Verifies whether the source contains a valid maximum event states value and assigns the
267      * default value if it's not specified in certain instances.
268      *
269      * @param flags flag values
270      */
validateAndSetMaxEventStates(Flags flags)271     public boolean validateAndSetMaxEventStates(Flags flags) {
272         if (!flags.getMeasurementEnableAttributionScope() || getAttributionScopeLimit() == null) {
273             return true;
274         }
275         Long numStates =
276                 mTriggerSpecs == null
277                         ? getNumStates(flags)
278                         : mTriggerSpecs.getNumStates(this, flags);
279         if (numStates == null || numStates == 0L) {
280             throw new IllegalStateException(
281                     "Num states should be validated before validating max event states");
282         }
283         if (mMaxEventStates == null) {
284             // Fallback to default max event states.
285             setMaxEventStates(DEFAULT_MAX_EVENT_STATES);
286         }
287         if (getSourceType() == SourceType.EVENT && numStates > getMaxEventStates()) {
288             return false;
289         }
290         return true;
291     }
292 
293     /**
294      * Checks if the source has valid information gain
295      *
296      * @param flags flag values
297      */
hasValidInformationGain(@onNull Flags flags)298     public boolean hasValidInformationGain(@NonNull Flags flags) {
299         if (mTriggerSpecs != null) {
300             return isFlexEventApiValueValid(flags);
301         }
302         return isFlexLiteApiValueValid(flags);
303     }
304 
getInformationGainThreshold(Flags flags)305     private double getInformationGainThreshold(Flags flags) {
306         if (getDestinationTypeMultiplier(flags) == 2) {
307             return mSourceType == SourceType.EVENT
308                     ? flags.getMeasurementFlexApiMaxInformationGainDualDestinationEvent()
309                     : flags.getMeasurementFlexApiMaxInformationGainDualDestinationNavigation();
310         }
311         return mSourceType == SourceType.EVENT
312                 ? flags.getMeasurementFlexApiMaxInformationGainEvent()
313                 : flags.getMeasurementFlexApiMaxInformationGainNavigation();
314     }
315 
316     /**
317      * Compute information gain for the source given the numTriggerStates. Attribution scope limit
318      * and max event states will also be considered if attribution scope is enabled.
319      *
320      * @param flags flag values.
321      * @param flipProbability the flip probability, used only if attribution scope is not enabled.
322      * @param numTriggerStates num of trigger states.
323      */
getInformationGain(Flags flags, long numTriggerStates, double flipProbability)324     double getInformationGain(Flags flags, long numTriggerStates, double flipProbability) {
325         if (flags.getMeasurementEnableAttributionScope()) {
326             long attributionScopeLimit =
327                     getAttributionScopeLimit() == null ? 1L : getAttributionScopeLimit();
328             long maxEventStates = getMaxEventStates() == null ? 1L : getMaxEventStates();
329             return Combinatorics.getMaxInformationGainWithAttributionScope(
330                     numTriggerStates,
331                     attributionScopeLimit,
332                     maxEventStates,
333                     flags.getMeasurementPrivacyEpsilon());
334         }
335         return Combinatorics.getInformationGain(numTriggerStates, flipProbability);
336     }
337 
isFlexLiteApiValueValid(Flags flags)338     private boolean isFlexLiteApiValueValid(Flags flags) {
339         return getInformationGain(flags, getNumStates(flags), getFlipProbability(flags))
340                 <= getInformationGainThreshold(flags);
341     }
342 
buildPrivacyParameters(Flags flags)343     private void buildPrivacyParameters(Flags flags) {
344         if (mTriggerSpecs != null) {
345             // Flex source has num states set during registration but not during attribution; also
346             // num states is only needed for information gain calculation, which is handled during
347             // registration. We set flip probability here for use in noising during registration and
348             // availability for debug reporting during attribution.
349             setFlipProbability(mTriggerSpecs.getFlipProbability(this, flags));
350             return;
351         }
352         double epsilon = (double) flags.getMeasurementPrivacyEpsilon();
353         setFlipProbability(Combinatorics.getFlipProbability(getNumStates(flags), epsilon));
354     }
355 
356     /** Should source report coarse destinations */
shouldReportCoarseDestinations(Flags flags)357     public boolean shouldReportCoarseDestinations(Flags flags) {
358         return flags.getMeasurementEnableCoarseEventReportDestinations()
359                 && hasCoarseEventReportDestinations();
360     }
361 
362     /**
363      * Returns the number of destination types to use in privacy computations.
364      */
getDestinationTypeMultiplier(Flags flags)365     public int getDestinationTypeMultiplier(Flags flags) {
366         return !shouldReportCoarseDestinations(flags) && hasAppDestinations()
367                         && hasWebDestinations()
368                 ? SourceNoiseHandler.DUAL_DESTINATION_IMPRESSION_NOISE_MULTIPLIER
369                 : SourceNoiseHandler.SINGLE_DESTINATION_IMPRESSION_NOISE_MULTIPLIER;
370     }
371 
372     /** Returns true is manual event reporting windows are set otherwise false; */
hasManualEventReportWindows()373     public boolean hasManualEventReportWindows() {
374         return getEventReportWindows() != null;
375     }
376 
377     @IntDef(value = {Status.ACTIVE, Status.IGNORED, Status.MARKED_TO_DELETE})
378     @Retention(RetentionPolicy.SOURCE)
379     public @interface Status {
380         int ACTIVE = 0;
381         int IGNORED = 1;
382         int MARKED_TO_DELETE = 2;
383     }
384 
385     @IntDef(value = {
386             AttributionMode.UNASSIGNED,
387             AttributionMode.TRUTHFULLY,
388             AttributionMode.NEVER,
389             AttributionMode.FALSELY,
390     })
391     @Retention(RetentionPolicy.SOURCE)
392     public @interface AttributionMode {
393         int UNASSIGNED = 0;
394         int TRUTHFULLY = 1;
395         int NEVER = 2;
396         int FALSELY = 3;
397     }
398 
399     /** The choice of the summary operator with the reporting window */
400     public enum TriggerDataMatching {
401         MODULUS,
402         EXACT
403     }
404 
405     public enum SourceType {
406         EVENT("event"),
407         NAVIGATION("navigation");
408 
409         private final String mValue;
410 
SourceType(String value)411         SourceType(String value) {
412             mValue = value;
413         }
414 
getValue()415         public String getValue() {
416             return mValue;
417         }
418 
getIntValue()419         public int getIntValue() {
420             return this.equals(SourceType.NAVIGATION) ? 1 : 0;
421         }
422     }
423 
Source()424     private Source() {
425         mEventReportDedupKeys = new ArrayList<>();
426         mAggregateReportDedupKeys = new ArrayList<>();
427         mStatus = Status.ACTIVE;
428         mSourceType = SourceType.EVENT;
429         // Making this default explicit since it anyway would occur on an uninitialised int field.
430         mPublisherType = EventSurfaceType.APP;
431         mAttributionMode = AttributionMode.UNASSIGNED;
432         mTriggerDataMatching = TriggerDataMatching.MODULUS;
433         mIsInstallAttributed = false;
434         mIsDebugReporting = false;
435     }
436 
437     /** Class for storing fake report data. */
438     public static class FakeReport {
439         private final UnsignedLong mTriggerData;
440         private final long mReportingTime;
441         private final long mTriggerTime;
442         private final List<Uri> mDestinations;
443         private final Pair<Long, Long> mTriggerSummaryBucket;
444 
FakeReport( UnsignedLong triggerData, long reportingTime, long triggerTime, List<Uri> destinations, @Nullable Pair<Long, Long> triggerSummaryBucket)445         public FakeReport(
446                 UnsignedLong triggerData,
447                 long reportingTime,
448                 long triggerTime,
449                 List<Uri> destinations,
450                 @Nullable Pair<Long, Long> triggerSummaryBucket) {
451             mTriggerData = triggerData;
452             mReportingTime = reportingTime;
453             mDestinations = destinations;
454             mTriggerTime = triggerTime;
455             mTriggerSummaryBucket = triggerSummaryBucket;
456         }
457 
458         @Override
equals(Object o)459         public boolean equals(Object o) {
460             if (this == o) return true;
461             if (!(o instanceof FakeReport)) return false;
462             FakeReport that = (FakeReport) o;
463             return Objects.equals(mTriggerData, that.mTriggerData)
464                     && mReportingTime == that.mReportingTime
465                     && mTriggerTime == that.mTriggerTime
466                     && Objects.equals(mDestinations, that.mDestinations)
467                     && Objects.equals(mTriggerSummaryBucket, that.mTriggerSummaryBucket);
468         }
469 
470         @Override
hashCode()471         public int hashCode() {
472             return Objects.hash(
473                     mTriggerData,
474                     mReportingTime,
475                     mTriggerTime,
476                     mDestinations,
477                     mTriggerSummaryBucket);
478         }
479 
getReportingTime()480         public long getReportingTime() {
481             return mReportingTime;
482         }
483 
getTriggerTime()484         public long getTriggerTime() {
485             return mTriggerTime;
486         }
487 
getTriggerData()488         public UnsignedLong getTriggerData() {
489             return mTriggerData;
490         }
491 
getDestinations()492         public List<Uri> getDestinations() {
493             return mDestinations;
494         }
495 
496         @Nullable
getTriggerSummaryBucket()497         public Pair<Long, Long> getTriggerSummaryBucket() {
498             return mTriggerSummaryBucket;
499         }
500     }
501 
502     /**
503      * Range of trigger metadata: [0, cardinality).
504      *
505      * @return Cardinality of {@link Trigger} metadata
506      */
getTriggerDataCardinality()507     public int getTriggerDataCardinality() {
508         if (getTriggerSpecs() != null) {
509             return getTriggerSpecs().getTriggerDataCardinality();
510         }
511         return mSourceType == SourceType.EVENT
512                 ? PrivacyParams.EVENT_TRIGGER_DATA_CARDINALITY
513                 : PrivacyParams.getNavigationTriggerDataCardinality();
514     }
515 
516     /**
517      * @return the list of attributed triggers
518      */
519     @Nullable
getAttributedTriggers()520     public List<AttributedTrigger> getAttributedTriggers() {
521         return mAttributedTriggers;
522     }
523 
524     /**
525      * @return all the attributed trigger IDs
526      */
getAttributedTriggerIds()527     public List<String> getAttributedTriggerIds() {
528         List<String> result = new ArrayList<>();
529         for (AttributedTrigger attributedTrigger : mAttributedTriggers) {
530             result.add(attributedTrigger.getTriggerId());
531         }
532         return result;
533     }
534 
535     /**
536      * @return the JSON encoded current trigger status
537      */
538     @NonNull
attributedTriggersToJson()539     public String attributedTriggersToJson() {
540         JSONArray jsonArray = new JSONArray();
541         for (AttributedTrigger trigger : mAttributedTriggers) {
542             jsonArray.put(trigger.encodeToJson());
543         }
544         return jsonArray.toString();
545     }
546 
547     /**
548      * @return the JSON encoded current trigger status
549      */
550     @NonNull
attributedTriggersToJsonFlexApi()551     public String attributedTriggersToJsonFlexApi() {
552         JSONArray jsonArray = new JSONArray();
553         for (AttributedTrigger trigger : mAttributedTriggers) {
554             jsonArray.put(trigger.encodeToJsonFlexApi());
555         }
556         return jsonArray.toString();
557     }
558 
559     /**
560      * @return the flex event trigger specification
561      */
562     @Nullable
getTriggerSpecs()563     public TriggerSpecs getTriggerSpecs() {
564         return mTriggerSpecs;
565     }
566 
567     @Override
equals(Object obj)568     public boolean equals(Object obj) {
569         if (!(obj instanceof Source)) {
570             return false;
571         }
572         Source source = (Source) obj;
573         return Objects.equals(mPublisher, source.mPublisher)
574                 && mPublisherType == source.mPublisherType
575                 && areEqualNullableDestinations(mAppDestinations, source.mAppDestinations)
576                 && areEqualNullableDestinations(mWebDestinations, source.mWebDestinations)
577                 && Objects.equals(mEnrollmentId, source.mEnrollmentId)
578                 && mPriority == source.mPriority
579                 && mStatus == source.mStatus
580                 && mExpiryTime == source.mExpiryTime
581                 && Objects.equals(mEventReportWindow, source.mEventReportWindow)
582                 && Objects.equals(mEventReportWindows, source.mEventReportWindows)
583                 && Objects.equals(mAggregatableReportWindow, source.mAggregatableReportWindow)
584                 && mEventTime == source.mEventTime
585                 && mReinstallReattributionWindow == source.mReinstallReattributionWindow
586                 && mAdIdPermission == source.mAdIdPermission
587                 && mArDebugPermission == source.mArDebugPermission
588                 && Objects.equals(mEventId, source.mEventId)
589                 && Objects.equals(mDebugKey, source.mDebugKey)
590                 && mSourceType == source.mSourceType
591                 && Objects.equals(mEventReportDedupKeys, source.mEventReportDedupKeys)
592                 && Objects.equals(mAggregateReportDedupKeys, source.mAggregateReportDedupKeys)
593                 && Objects.equals(mRegistrant, source.mRegistrant)
594                 && mAttributionMode == source.mAttributionMode
595                 && mIsDebugReporting == source.mIsDebugReporting
596                 && Objects.equals(mFilterDataString, source.mFilterDataString)
597                 && Objects.equals(mSharedFilterDataKeys, source.mSharedFilterDataKeys)
598                 && Objects.equals(mAggregateSource, source.mAggregateSource)
599                 && mAggregateContributions == source.mAggregateContributions
600                 && Objects.equals(
601                         mAggregatableAttributionSource, source.mAggregatableAttributionSource)
602                 && Objects.equals(mRegistrationId, source.mRegistrationId)
603                 && Objects.equals(mSharedAggregationKeys, source.mSharedAggregationKeys)
604                 && Objects.equals(mParentId, source.mParentId)
605                 && Objects.equals(mInstallTime, source.mInstallTime)
606                 && Objects.equals(mDebugJoinKey, source.mDebugJoinKey)
607                 && Objects.equals(mPlatformAdId, source.mPlatformAdId)
608                 && Objects.equals(mDebugAdId, source.mDebugAdId)
609                 && Objects.equals(mRegistrationOrigin, source.mRegistrationOrigin)
610                 && mCoarseEventReportDestinations == source.mCoarseEventReportDestinations
611                 && Objects.equals(mAttributedTriggers, source.mAttributedTriggers)
612                 && Objects.equals(mTriggerSpecs, source.mTriggerSpecs)
613                 && Objects.equals(mTriggerSpecsString, source.mTriggerSpecsString)
614                 && Objects.equals(mMaxEventLevelReports, source.mMaxEventLevelReports)
615                 && Objects.equals(
616                         mEventAttributionStatusString, source.mEventAttributionStatusString)
617                 && Objects.equals(mPrivacyParametersString, source.mPrivacyParametersString)
618                 && Objects.equals(mTriggerDataMatching, source.mTriggerDataMatching)
619                 && Objects.equals(mSharedDebugKey, source.mSharedDebugKey)
620                 && mDropSourceIfInstalled == source.mDropSourceIfInstalled
621                 && Objects.equals(mAttributionScopes, source.mAttributionScopes)
622                 && Objects.equals(mAttributionScopeLimit, source.mAttributionScopeLimit)
623                 && Objects.equals(mMaxEventStates, source.mMaxEventStates);
624     }
625 
626     @Override
hashCode()627     public int hashCode() {
628         return Objects.hash(
629                 mId,
630                 mPublisher,
631                 mPublisherType,
632                 mAppDestinations,
633                 mWebDestinations,
634                 mEnrollmentId,
635                 mPriority,
636                 mStatus,
637                 mExpiryTime,
638                 mEventReportWindow,
639                 mEventReportWindows,
640                 mAggregatableReportWindow,
641                 mReinstallReattributionWindow,
642                 mEventTime,
643                 mEventId,
644                 mSourceType,
645                 mEventReportDedupKeys,
646                 mAggregateReportDedupKeys,
647                 mFilterDataString,
648                 mSharedFilterDataKeys,
649                 mAggregateSource,
650                 mAggregateContributions,
651                 mAggregatableAttributionSource,
652                 mDebugKey,
653                 mAdIdPermission,
654                 mArDebugPermission,
655                 mRegistrationId,
656                 mSharedAggregationKeys,
657                 mInstallTime,
658                 mDebugJoinKey,
659                 mPlatformAdId,
660                 mDebugAdId,
661                 mRegistrationOrigin,
662                 mDebugJoinKey,
663                 mAttributedTriggers,
664                 mTriggerSpecs,
665                 mTriggerSpecsString,
666                 mTriggerDataMatching,
667                 mMaxEventLevelReports,
668                 mEventAttributionStatusString,
669                 mPrivacyParametersString,
670                 mCoarseEventReportDestinations,
671                 mSharedDebugKey,
672                 mDropSourceIfInstalled,
673                 mAttributionScopes,
674                 mAttributionScopeLimit,
675                 mMaxEventStates);
676     }
677 
setAttributionMode(@ttributionMode int attributionMode)678     public void setAttributionMode(@AttributionMode int attributionMode) {
679         mAttributionMode = attributionMode;
680     }
681 
682     /**
683      * Retrieve the attribution destinations corresponding to their destination type.
684      *
685      * @return a list of Uris.
686      */
getAttributionDestinations(@ventSurfaceType int destinationType)687     public List<Uri> getAttributionDestinations(@EventSurfaceType int destinationType) {
688         return destinationType == EventSurfaceType.APP ? mAppDestinations : mWebDestinations;
689     }
690 
691     /**
692      * Unique identifier for the {@link Source}.
693      */
getId()694     public String getId() {
695         return mId;
696     }
697 
698     /**
699      * Identifier provided by the registrant.
700      */
getEventId()701     public UnsignedLong getEventId() {
702         return mEventId;
703     }
704 
705     /**
706      * Priority of the {@link Source}.
707      */
getPriority()708     public long getPriority() {
709         return mPriority;
710     }
711 
712     /**
713      * Ad Tech enrollment ID
714      */
getEnrollmentId()715     public String getEnrollmentId() {
716         return mEnrollmentId;
717     }
718 
719     /** Uri which registered the {@link Source}. */
getPublisher()720     public Uri getPublisher() {
721         return mPublisher;
722     }
723 
724     /** The publisher type (e.g., app or web) {@link Source}. */
725     @EventSurfaceType
getPublisherType()726     public int getPublisherType() {
727         return mPublisherType;
728     }
729 
730     /** Uris for the {@link Trigger}'s app destinations. */
731     @Nullable
getAppDestinations()732     public List<Uri> getAppDestinations() {
733         return mAppDestinations;
734     }
735 
736     /** Uris for the {@link Trigger}'s web destinations. */
737     @Nullable
getWebDestinations()738     public List<Uri> getWebDestinations() {
739         return mWebDestinations;
740     }
741 
742     /** Returns combined list of web and app attribution destinations. */
getAllAttributionDestinations()743     public List<Pair<Integer, String>> getAllAttributionDestinations() {
744         List<Pair<Integer, String>> destinations = new ArrayList<>();
745         if (hasAppDestinations()) {
746             for (Uri appDestination : getAppDestinations()) {
747                 destinations.add(Pair.create(EventSurfaceType.APP, appDestination.toString()));
748             }
749         }
750         if (hasWebDestinations()) {
751             for (Uri webDestination : getWebDestinations()) {
752                 destinations.add(Pair.create(EventSurfaceType.WEB, webDestination.toString()));
753             }
754         }
755         return destinations;
756     }
757 
758     /**
759      * Type of {@link Source}. Values: Event, Navigation.
760      */
getSourceType()761     public SourceType getSourceType() {
762         return mSourceType;
763     }
764 
765     /** Time when {@link Source} will expire. */
getExpiryTime()766     public long getExpiryTime() {
767         return mExpiryTime;
768     }
769 
770     /** Returns Event report window */
getEventReportWindow()771     public Long getEventReportWindow() {
772         return mEventReportWindow;
773     }
774 
775     /** Returns reinstall reattribution window */
getReinstallReattributionWindow()776     public long getReinstallReattributionWindow() {
777         return mReinstallReattributionWindow;
778     }
779 
780     /**
781      * Time when {@link Source} event report window will expire. (Appends the Event Time to window)
782      */
getEffectiveEventReportWindow()783     public long getEffectiveEventReportWindow() {
784         if (mEventReportWindow == null) {
785             return getExpiryTime();
786         }
787         // TODO(b/290098169): Cleanup after a few releases
788         // Handling cases where ReportWindow is already stored as mEventTime + mEventReportWindow
789         if (mEventReportWindow > mEventTime) {
790             return mEventReportWindow;
791         } else {
792             return mEventTime + mEventReportWindow;
793         }
794     }
795 
796     /** JSON string for event report windows */
getEventReportWindows()797     public String getEventReportWindows() {
798         return mEventReportWindows;
799     }
800 
801     /** Time when {@link Source} aggregate report window will expire. */
getAggregatableReportWindow()802     public long getAggregatableReportWindow() {
803         return mAggregatableReportWindow;
804     }
805 
806     /** Debug key of {@link Source}. */
807     @Nullable
getDebugKey()808     public UnsignedLong getDebugKey() {
809         return mDebugKey;
810     }
811 
812     /**
813      * Time the event occurred.
814      */
getEventTime()815     public long getEventTime() {
816         return mEventTime;
817     }
818 
819     /** Is Ad ID Permission Enabled. */
hasAdIdPermission()820     public boolean hasAdIdPermission() {
821         return mAdIdPermission;
822     }
823 
824     /** Is Ar Debug Permission Enabled. */
hasArDebugPermission()825     public boolean hasArDebugPermission() {
826         return mArDebugPermission;
827     }
828 
829     /** List of dedup keys for the attributed {@link Trigger}. */
getEventReportDedupKeys()830     public List<UnsignedLong> getEventReportDedupKeys() {
831         return mEventReportDedupKeys;
832     }
833 
834     /** List of dedup keys used for generating Aggregate Reports. */
getAggregateReportDedupKeys()835     public List<UnsignedLong> getAggregateReportDedupKeys() {
836         return mAggregateReportDedupKeys;
837     }
838 
839     /** Current status of the {@link Source}. */
840     @Status
getStatus()841     public int getStatus() {
842         return mStatus;
843     }
844 
845     /**
846      * Registrant of this source, primarily an App.
847      */
getRegistrant()848     public Uri getRegistrant() {
849         return mRegistrant;
850     }
851 
852     /** Selected mode for attribution. Values: Truthfully, Never, Falsely. */
853     @AttributionMode
getAttributionMode()854     public int getAttributionMode() {
855         return mAttributionMode;
856     }
857 
858     /** Specification for trigger matching behaviour. Values: Modulus, Exact. */
getTriggerDataMatching()859     public TriggerDataMatching getTriggerDataMatching() {
860         return mTriggerDataMatching;
861     }
862 
863     /**
864      * Attribution window for install events.
865      */
getInstallAttributionWindow()866     public long getInstallAttributionWindow() {
867         return mInstallAttributionWindow;
868     }
869 
870     /**
871      * Cooldown for attributing post-install {@link Trigger} events.
872      */
getInstallCooldownWindow()873     public long getInstallCooldownWindow() {
874         return mInstallCooldownWindow;
875     }
876 
877     /** Check if install detection is enabled for the source. */
isInstallDetectionEnabled()878     public boolean isInstallDetectionEnabled() {
879         return getInstallCooldownWindow() > 0 && hasAppDestinations();
880     }
881 
882     /**
883      * Is an App-install attributed to the {@link Source}.
884      */
isInstallAttributed()885     public boolean isInstallAttributed() {
886         return mIsInstallAttributed;
887     }
888 
889     /** Is Ad Tech Opt-in to Debug Reporting {@link Source}. */
isDebugReporting()890     public boolean isDebugReporting() {
891         return mIsDebugReporting;
892     }
893 
894     /**
895      * Check whether the parameter of flexible event API is valid or not. Currently, only max
896      * information gain is check because of the computation is complicated. Other straightforward
897      * value errors will be show in the debug log using LogUtil
898      *
899      * @return whether the parameters of flexible are valid
900      */
901     @VisibleForTesting
isFlexEventApiValueValid(Flags flags)902     public boolean isFlexEventApiValueValid(Flags flags) {
903         return mTriggerSpecs.getInformationGain(this, flags) <= getInformationGainThreshold(flags);
904     }
905 
906     /**
907      * Returns aggregate filter data string used for aggregation. aggregate filter data json is a
908      * JSONObject in Attribution-Reporting-Register-Source header. Example:
909      * Attribution-Reporting-Register-Source: { // some other fields. "filter_data" : {
910      * "conversion_subdomain": ["electronics.megastore"], "product": ["1234", "2345"], "ctid":
911      * ["id"], ...... } }
912      */
getFilterDataString()913     public String getFilterDataString() {
914         return mFilterDataString;
915     }
916 
917     /**
918      * Returns the shared filter data keys of the source as a unique list of strings. Example:
919      * ["click_duration", "campaign_type"]
920      */
921     @Nullable
getSharedFilterDataKeys()922     public String getSharedFilterDataKeys() {
923         return mSharedFilterDataKeys;
924     }
925 
926     /**
927      * Returns aggregate source string used for aggregation. aggregate source json is a JSONArray.
928      * Example: [{ // Generates a "0x159" key piece (low order bits of the key) named //
929      * "campaignCounts" "id": "campaignCounts", "key_piece": "0x159", // User saw ad from campaign
930      * 345 (out of 511) }, { // Generates a "0x5" key piece (low order bits of the key) named
931      * "geoValue" "id": "geoValue", // Source-side geo region = 5 (US), out of a possible ~100
932      * regions. "key_piece": "0x5", }]
933      */
getAggregateSource()934     public String getAggregateSource() {
935         return mAggregateSource;
936     }
937 
938     /**
939      * Returns the current sum of values the source contributed to aggregatable reports.
940      */
getAggregateContributions()941     public int getAggregateContributions() {
942         return mAggregateContributions;
943     }
944 
945     /**
946      * Returns the AggregatableAttributionSource object, which is constructed using the aggregate
947      * source string and aggregate filter data string in Source.
948      */
getAggregatableAttributionSource( @onNull Trigger trigger, Flags flags)949     public Optional<AggregatableAttributionSource> getAggregatableAttributionSource(
950             @NonNull Trigger trigger, Flags flags) throws JSONException {
951         return flags.getMeasurementEnableLookbackWindowFilter()
952                 ? getAggregatableAttributionSourceV2(trigger)
953                 : getAggregatableAttributionSource();
954     }
955 
getAggregatableAttributionSource()956     private Optional<AggregatableAttributionSource> getAggregatableAttributionSource()
957             throws JSONException {
958         if (mAggregatableAttributionSource == null) {
959             if (mAggregateSource == null) {
960                 mAggregatableAttributionSource = Optional.empty();
961                 return mAggregatableAttributionSource;
962             }
963             JSONObject jsonObject = new JSONObject(mAggregateSource);
964             TreeMap<String, BigInteger> aggregateSourceMap = new TreeMap<>();
965             Iterator<String> keys = jsonObject.keys();
966             while (keys.hasNext()) {
967                 String key = keys.next();
968                 // Remove "0x" prefix.
969                 String hexString = jsonObject.getString(key).substring(2);
970                 BigInteger bigInteger = new BigInteger(hexString, 16);
971                 aggregateSourceMap.put(key, bigInteger);
972             }
973             AggregatableAttributionSource aggregatableAttributionSource =
974                     new AggregatableAttributionSource.Builder()
975                             .setAggregatableSource(aggregateSourceMap)
976                             .setFilterMap(getFilterData())
977                             .build();
978             mAggregatableAttributionSource = Optional.of(aggregatableAttributionSource);
979         }
980 
981         return mAggregatableAttributionSource;
982     }
983 
getAggregatableAttributionSourceV2( @onNull Trigger trigger)984     private Optional<AggregatableAttributionSource> getAggregatableAttributionSourceV2(
985             @NonNull Trigger trigger) throws JSONException {
986         if (mAggregateSource == null) {
987             return Optional.empty();
988         }
989         JSONObject jsonObject = new JSONObject(mAggregateSource);
990         TreeMap<String, BigInteger> aggregateSourceMap = new TreeMap<>();
991         for (String key : jsonObject.keySet()) {
992             // Remove "0x" prefix.
993             String hexString = jsonObject.getString(key).substring(2);
994             BigInteger bigInteger = new BigInteger(hexString, 16);
995             aggregateSourceMap.put(key, bigInteger);
996         }
997         return Optional.of(
998                 new AggregatableAttributionSource.Builder()
999                         .setAggregatableSource(aggregateSourceMap)
1000                         .setFilterMap(getFilterData(trigger))
1001                         .build());
1002     }
1003 
1004     /** Returns the registration id. */
1005     @Nullable
getRegistrationId()1006     public String getRegistrationId() {
1007         return mRegistrationId;
1008     }
1009 
1010     /**
1011      * Returns the shared aggregation keys of the source as a unique list of strings. Example:
1012      * [“campaignCounts”]
1013      */
1014     @Nullable
getSharedAggregationKeys()1015     public String getSharedAggregationKeys() {
1016         return mSharedAggregationKeys;
1017     }
1018 
1019     /** Returns the install time of the source which is the same value as event time. */
1020     @Nullable
getInstallTime()1021     public Long getInstallTime() {
1022         return mInstallTime;
1023     }
1024 
1025     /**
1026      * Returns join key that should be matched with trigger's join key at the time of generating
1027      * reports.
1028      */
1029     @Nullable
getDebugJoinKey()1030     public String getDebugJoinKey() {
1031         return mDebugJoinKey;
1032     }
1033 
1034     /**
1035      * Returns actual platform AdID from getAdId() on app source registration, to be matched with a
1036      * web trigger's {@link Trigger#getDebugAdId()} value at the time of generating reports.
1037      */
1038     @Nullable
getPlatformAdId()1039     public String getPlatformAdId() {
1040         return mPlatformAdId;
1041     }
1042 
1043     /**
1044      * Returns SHA256 hash of AdID from registration response on web registration concatenated with
1045      * enrollment ID, to be matched with an app trigger's {@link Trigger#getPlatformAdId()} value at
1046      * the time of generating reports.
1047      */
1048     @Nullable
getDebugAdId()1049     public String getDebugAdId() {
1050         return mDebugAdId;
1051     }
1052 
1053     /**
1054      * Indicates whether event report for this source should be generated with the destinations
1055      * where the conversion occurred or merge app and web destinations. Set to true of both app and
1056      * web destination should be merged into the array of event report.
1057      */
hasCoarseEventReportDestinations()1058     public boolean hasCoarseEventReportDestinations() {
1059         return mCoarseEventReportDestinations;
1060     }
1061 
1062     /** Returns registration origin used to register the source */
getRegistrationOrigin()1063     public Uri getRegistrationOrigin() {
1064         return mRegistrationOrigin;
1065     }
1066 
1067     /** Returns trigger specs */
getTriggerSpecsString()1068     public String getTriggerSpecsString() {
1069         return mTriggerSpecsString;
1070     }
1071 
1072     /**
1073      * Returns the number of report states for the source (used only for computation and not
1074      * stored in the datastore)
1075      */
getNumStates(Flags flags)1076     private Long getNumStates(Flags flags) {
1077         if (mNumStates == null) {
1078             validateAndSetNumReportStates(flags);
1079         }
1080         return mNumStates;
1081     }
1082 
1083     /** Returns flip probability (used only for computation and not stored in the datastore) */
getFlipProbability(Flags flags)1084     public Double getFlipProbability(Flags flags) {
1085         if (mFlipProbability == null) {
1086             buildPrivacyParameters(flags);
1087         }
1088         return mFlipProbability;
1089     }
1090 
1091     /** Returns max bucket increments */
getMaxEventLevelReports()1092     public Integer getMaxEventLevelReports() {
1093         return mMaxEventLevelReports;
1094     }
1095 
1096     /**
1097      * Returns the RBR provided or default value for max_event_level_reports
1098      *
1099      * @param sourceType Source's Type
1100      * @param maxEventLevelReports RBR parsed value for max_event_level_reports
1101      * @param flags Flag values
1102      */
1103     @NonNull
getOrDefaultMaxEventLevelReports( @onNull SourceType sourceType, @Nullable Integer maxEventLevelReports, @NonNull Flags flags)1104     public static Integer getOrDefaultMaxEventLevelReports(
1105             @NonNull SourceType sourceType,
1106             @Nullable Integer maxEventLevelReports,
1107             @NonNull Flags flags) {
1108         if (maxEventLevelReports == null) {
1109             return sourceType == Source.SourceType.NAVIGATION
1110                     ? PrivacyParams.NAVIGATION_SOURCE_MAX_REPORTS
1111                     : flags.getMeasurementVtcConfigurableMaxEventReportsCount();
1112         }
1113         return maxEventLevelReports;
1114     }
1115 
1116     /** Returns event attribution status of current source */
getEventAttributionStatus()1117     public String getEventAttributionStatus() {
1118         return mEventAttributionStatusString;
1119     }
1120 
1121     /** Returns privacy parameters */
getPrivacyParameters()1122     public String getPrivacyParameters() {
1123         return mPrivacyParametersString;
1124     }
1125 
1126     /** See {@link Source#getAppDestinations()} */
setAppDestinations(@ullable List<Uri> appDestinations)1127     public void setAppDestinations(@Nullable List<Uri> appDestinations) {
1128         mAppDestinations = appDestinations;
1129     }
1130 
1131     /** See {@link Source#getWebDestinations()} */
setWebDestinations(@ullable List<Uri> webDestinations)1132     public void setWebDestinations(@Nullable List<Uri> webDestinations) {
1133         mWebDestinations = webDestinations;
1134     }
1135 
1136     /** Set app install attribution to the {@link Source}. */
setInstallAttributed(boolean isInstallAttributed)1137     public void setInstallAttributed(boolean isInstallAttributed) {
1138         mIsInstallAttributed = isInstallAttributed;
1139     }
1140 
1141     /** Set the number of report states for the {@link Source}. */
setNumStates(long numStates)1142     private void setNumStates(long numStates) {
1143         mNumStates = numStates;
1144     }
1145 
1146     /** Set max event states for the {@link Source}. */
setMaxEventStates(long maxEventStates)1147     private void setMaxEventStates(long maxEventStates) {
1148         mMaxEventStates = maxEventStates;
1149     }
1150 
1151     /** Set flip probability for the {@link Source}. */
setFlipProbability(double flipProbability)1152     private void setFlipProbability(double flipProbability) {
1153         mFlipProbability = flipProbability;
1154     }
1155 
1156     /**
1157      * @return if it's a derived source, returns the ID of the source it was created from. If it is
1158      *     null, it is an original source.
1159      */
1160     @Nullable
getParentId()1161     public String getParentId() {
1162         return mParentId;
1163     }
1164 
1165     /**
1166      * Set the status.
1167      */
setStatus(@tatus int status)1168     public void setStatus(@Status int status) {
1169         mStatus = status;
1170     }
1171 
1172     /**
1173      * Set the aggregate contributions value.
1174      */
setAggregateContributions(int aggregateContributions)1175     public void setAggregateContributions(int aggregateContributions) {
1176         mAggregateContributions = aggregateContributions;
1177     }
1178 
1179     /**
1180      * Generates AggregatableFilterData from aggregate filter string in Source, including entries
1181      * for source type and duration from source to trigger if lookback window filter is enabled.
1182      */
getFilterData(@onNull Trigger trigger, Flags flags)1183     public FilterMap getFilterData(@NonNull Trigger trigger, Flags flags) throws JSONException {
1184         return flags.getMeasurementEnableLookbackWindowFilter()
1185                 ? getFilterData(trigger)
1186                 : getFilterData();
1187     }
1188 
getFilterData()1189     private FilterMap getFilterData() throws JSONException {
1190         if (mFilterData != null) {
1191             return mFilterData;
1192         }
1193 
1194         if (mFilterDataString == null || mFilterDataString.isEmpty()) {
1195             mFilterData = new FilterMap.Builder().build();
1196         } else {
1197             mFilterData =
1198                     new FilterMap.Builder()
1199                             .buildFilterData(new JSONObject(mFilterDataString))
1200                             .build();
1201         }
1202         mFilterData
1203                 .getAttributionFilterMap()
1204                 .put("source_type", Collections.singletonList(mSourceType.getValue()));
1205         return mFilterData;
1206     }
1207 
getFilterData(@onNull Trigger trigger)1208     private FilterMap getFilterData(@NonNull Trigger trigger) throws JSONException {
1209         FilterMap.Builder builder = new FilterMap.Builder();
1210         if (mFilterDataString != null && !mFilterDataString.isEmpty()) {
1211             builder.buildFilterDataV2(new JSONObject(mFilterDataString));
1212         }
1213         builder.addStringListValue("source_type", Collections.singletonList(mSourceType.getValue()))
1214                 .addLongValue(
1215                         FilterMap.LOOKBACK_WINDOW,
1216                         TimeUnit.MILLISECONDS.toSeconds(trigger.getTriggerTime() - mEventTime));
1217         return builder.build();
1218     }
1219 
extractSharedFilterMapFromJson(Map<String, V> attributionFilterMap)1220     private <V> Map<String, V> extractSharedFilterMapFromJson(Map<String, V> attributionFilterMap)
1221             throws JSONException {
1222         Map<String, V> sharedAttributionFilterMap = new HashMap<>();
1223         JSONArray sharedFilterDataKeysArray = new JSONArray(mSharedFilterDataKeys);
1224         for (int i = 0; i < sharedFilterDataKeysArray.length(); ++i) {
1225             String filterKey = sharedFilterDataKeysArray.getString(i);
1226             if (attributionFilterMap.containsKey(filterKey)) {
1227                 sharedAttributionFilterMap.put(filterKey, attributionFilterMap.get(filterKey));
1228             }
1229         }
1230         return sharedAttributionFilterMap;
1231     }
1232 
1233     /**
1234      * Generates AggregatableFilterData from aggregate filter string in Source, including entries
1235      * for source type and duration from source to trigger if lookback window filter is enabled.
1236      */
getSharedFilterData(@onNull Trigger trigger, Flags flags)1237     public FilterMap getSharedFilterData(@NonNull Trigger trigger, Flags flags)
1238             throws JSONException {
1239         FilterMap filterMap = getFilterData(trigger, flags);
1240         if (mSharedFilterDataKeys == null) {
1241             return filterMap;
1242         }
1243         if (flags.getMeasurementEnableLookbackWindowFilter()) {
1244             return new FilterMap.Builder()
1245                     .setAttributionFilterMapWithLongValue(
1246                             extractSharedFilterMapFromJson(
1247                                     filterMap.getAttributionFilterMapWithLongValue()))
1248                     .build();
1249         } else {
1250             return new FilterMap.Builder()
1251                     .setAttributionFilterMap(
1252                             extractSharedFilterMapFromJson(filterMap.getAttributionFilterMap()))
1253                     .build();
1254         }
1255     }
1256 
1257     @Nullable
getSharedDebugKey()1258     public UnsignedLong getSharedDebugKey() {
1259         return mSharedDebugKey;
1260     }
1261 
1262     /** Returns true if the source should be dropped when the app is already installed. */
shouldDropSourceIfInstalled()1263     public boolean shouldDropSourceIfInstalled() {
1264         return mDropSourceIfInstalled;
1265     }
1266 
1267     /** Returns true if the source has app destination(s), false otherwise. */
hasAppDestinations()1268     public boolean hasAppDestinations() {
1269         return mAppDestinations != null && mAppDestinations.size() > 0;
1270     }
1271 
1272     /** Returns true if the source has web destination(s), false otherwise. */
hasWebDestinations()1273     public boolean hasWebDestinations() {
1274         return mWebDestinations != null && mWebDestinations.size() > 0;
1275     }
1276 
areEqualNullableDestinations( List<Uri> destinations, List<Uri> otherDestinations)1277     private static boolean areEqualNullableDestinations(
1278             List<Uri> destinations, List<Uri> otherDestinations) {
1279         if (destinations == null && otherDestinations == null) {
1280             return true;
1281         } else if (destinations == null || otherDestinations == null) {
1282             return false;
1283         } else {
1284             return ImmutableMultiset.copyOf(destinations)
1285                     .equals(ImmutableMultiset.copyOf(otherDestinations));
1286         }
1287     }
1288 
1289     /** Parses the event attribution status string. */
1290     @VisibleForTesting
parseEventAttributionStatus()1291     public void parseEventAttributionStatus() throws JSONException {
1292         JSONArray eventAttributionStatus = new JSONArray(mEventAttributionStatusString);
1293         for (int i = 0; i < eventAttributionStatus.length(); i++) {
1294             JSONObject json = eventAttributionStatus.getJSONObject(i);
1295             mAttributedTriggers.add(new AttributedTrigger(json));
1296         }
1297     }
1298 
1299     /** Build the attributed triggers list from the raw string */
buildAttributedTriggers()1300     public void buildAttributedTriggers() throws JSONException {
1301         if (mAttributedTriggers == null) {
1302             mAttributedTriggers = new ArrayList<>();
1303             if (mEventAttributionStatusString != null && !mEventAttributionStatusString.isEmpty()) {
1304                 parseEventAttributionStatus();
1305             }
1306         }
1307     }
1308 
1309     /** Build the trigger specs from the raw string */
buildTriggerSpecs()1310     public void buildTriggerSpecs() throws JSONException {
1311         buildAttributedTriggers();
1312         if (mTriggerSpecs == null) {
1313             mTriggerSpecs =
1314                     new TriggerSpecs(
1315                             mTriggerSpecsString,
1316                             getOrDefaultMaxEventLevelReports(
1317                                     mSourceType, mMaxEventLevelReports, FlagsFactory.getFlags()),
1318                             this,
1319                             mPrivacyParametersString);
1320         }
1321     }
1322 
1323     /** Returns the attribution scopes attached to the source. */
1324     @Nullable
getAttributionScopes()1325     public List<String> getAttributionScopes() {
1326         return mAttributionScopes;
1327     }
1328 
1329     /** Returns the attribution scope limit for the source. It should be positive. */
1330     @Nullable
getAttributionScopeLimit()1331     public Long getAttributionScopeLimit() {
1332         return mAttributionScopeLimit;
1333     }
1334 
1335     /** Returns max number of event states. It should be positive. */
1336     @Nullable
getMaxEventStates()1337     public Long getMaxEventStates() {
1338         return mMaxEventStates;
1339     }
1340 
1341     /** Builder for {@link Source}. */
1342     public static final class Builder {
1343         private final Source mBuilding;
1344 
Builder()1345         public Builder() {
1346             mBuilding = new Source();
1347         }
1348 
1349         /**
1350          * Copy builder.
1351          *
1352          * @param copyFrom copy from source
1353          * @return copied source
1354          */
from(Source copyFrom)1355         public static Builder from(Source copyFrom) {
1356             Builder builder = new Builder();
1357             builder.setId(copyFrom.mId);
1358             builder.setRegistrationId(copyFrom.mRegistrationId);
1359             builder.setAggregateSource(copyFrom.mAggregateSource);
1360             builder.setExpiryTime(copyFrom.mExpiryTime);
1361             builder.setAppDestinations(copyFrom.mAppDestinations);
1362             builder.setWebDestinations(copyFrom.mWebDestinations);
1363             builder.setSharedAggregationKeys(copyFrom.mSharedAggregationKeys);
1364             builder.setEventId(copyFrom.mEventId);
1365             builder.setRegistrant(copyFrom.mRegistrant);
1366             builder.setEventTime(copyFrom.mEventTime);
1367             builder.setPublisher(copyFrom.mPublisher);
1368             builder.setPublisherType(copyFrom.mPublisherType);
1369             builder.setInstallCooldownWindow(copyFrom.mInstallCooldownWindow);
1370             builder.setInstallAttributed(copyFrom.mIsInstallAttributed);
1371             builder.setInstallAttributionWindow(copyFrom.mInstallAttributionWindow);
1372             builder.setReinstallReattributionWindow(copyFrom.mReinstallReattributionWindow);
1373             builder.setSourceType(copyFrom.mSourceType);
1374             builder.setAdIdPermission(copyFrom.mAdIdPermission);
1375             builder.setAggregateContributions(copyFrom.mAggregateContributions);
1376             builder.setArDebugPermission(copyFrom.mArDebugPermission);
1377             builder.setAttributionMode(copyFrom.mAttributionMode);
1378             builder.setDebugKey(copyFrom.mDebugKey);
1379             builder.setEventReportDedupKeys(copyFrom.mEventReportDedupKeys);
1380             builder.setAggregateReportDedupKeys(copyFrom.mAggregateReportDedupKeys);
1381             builder.setEventReportWindow(copyFrom.mEventReportWindow);
1382             builder.setEventReportWindows(copyFrom.mEventReportWindows);
1383             builder.setMaxEventLevelReports(copyFrom.mMaxEventLevelReports);
1384             builder.setAggregatableReportWindow(copyFrom.mAggregatableReportWindow);
1385             builder.setEnrollmentId(copyFrom.mEnrollmentId);
1386             builder.setFilterDataString(copyFrom.mFilterDataString);
1387             builder.setSharedFilterDataKeys(copyFrom.mSharedFilterDataKeys);
1388             builder.setInstallTime(copyFrom.mInstallTime);
1389             builder.setIsDebugReporting(copyFrom.mIsDebugReporting);
1390             builder.setPriority(copyFrom.mPriority);
1391             builder.setStatus(copyFrom.mStatus);
1392             builder.setDebugJoinKey(copyFrom.mDebugJoinKey);
1393             builder.setPlatformAdId(copyFrom.mPlatformAdId);
1394             builder.setDebugAdId(copyFrom.mDebugAdId);
1395             builder.setRegistrationOrigin(copyFrom.mRegistrationOrigin);
1396             builder.setAttributedTriggers(copyFrom.mAttributedTriggers);
1397             builder.setTriggerSpecs(copyFrom.mTriggerSpecs);
1398             builder.setTriggerDataMatching(copyFrom.mTriggerDataMatching);
1399             builder.setCoarseEventReportDestinations(copyFrom.mCoarseEventReportDestinations);
1400             builder.setSharedDebugKey(copyFrom.mSharedDebugKey);
1401             builder.setDropSourceIfInstalled(copyFrom.mDropSourceIfInstalled);
1402             builder.setAttributionScopes(copyFrom.mAttributionScopes);
1403             builder.setAttributionScopeLimit(copyFrom.mAttributionScopeLimit);
1404             builder.setMaxEventStates(copyFrom.mMaxEventStates);
1405             return builder;
1406         }
1407 
1408         /** See {@link Source#getId()}. */
1409         @NonNull
setId(@onNull String id)1410         public Builder setId(@NonNull String id) {
1411             mBuilding.mId = id;
1412             return this;
1413         }
1414 
1415         /** See {@link Source#getEventId()}. */
1416         @NonNull
setEventId(UnsignedLong eventId)1417         public Builder setEventId(UnsignedLong eventId) {
1418             mBuilding.mEventId = eventId;
1419             return this;
1420         }
1421 
1422         /** See {@link Source#getPublisher()}. */
1423         @NonNull
setPublisher(@onNull Uri publisher)1424         public Builder setPublisher(@NonNull Uri publisher) {
1425             Validation.validateUri(publisher);
1426             mBuilding.mPublisher = publisher;
1427             return this;
1428         }
1429 
1430         /** See {@link Source#getPublisherType()}. */
1431         @NonNull
setPublisherType(@ventSurfaceType int publisherType)1432         public Builder setPublisherType(@EventSurfaceType int publisherType) {
1433             mBuilding.mPublisherType = publisherType;
1434             return this;
1435         }
1436 
1437         /** See {@link Source#getAppDestinations()}. */
1438         @NonNull
setAppDestinations(@ullable List<Uri> appDestinations)1439         public Builder setAppDestinations(@Nullable List<Uri> appDestinations) {
1440             Optional.ofNullable(appDestinations).ifPresent(uris -> {
1441                 Validation.validateNotEmpty(uris);
1442                 if (uris.size() > 1) {
1443                     throw new IllegalArgumentException("Received more than one app destination");
1444                 }
1445                 Validation.validateUri(uris.toArray(new Uri[0]));
1446             });
1447             mBuilding.mAppDestinations = appDestinations;
1448             return this;
1449         }
1450 
1451         /** See {@link Source#getWebDestinations()}. */
1452         @NonNull
setWebDestinations(@ullable List<Uri> webDestinations)1453         public Builder setWebDestinations(@Nullable List<Uri> webDestinations) {
1454             Optional.ofNullable(webDestinations).ifPresent(uris -> {
1455                 Validation.validateNotEmpty(uris);
1456                 Validation.validateUri(uris.toArray(new Uri[0]));
1457             });
1458             mBuilding.mWebDestinations = webDestinations;
1459             return this;
1460         }
1461 
1462         /** See {@link Source#getEnrollmentId()}. */
1463         @NonNull
setEnrollmentId(@onNull String enrollmentId)1464         public Builder setEnrollmentId(@NonNull String enrollmentId) {
1465             mBuilding.mEnrollmentId = enrollmentId;
1466             return this;
1467         }
1468 
1469         /** See {@link Source#hasAdIdPermission()} */
setAdIdPermission(boolean adIdPermission)1470         public Source.Builder setAdIdPermission(boolean adIdPermission) {
1471             mBuilding.mAdIdPermission = adIdPermission;
1472             return this;
1473         }
1474 
1475         /** See {@link Source#hasArDebugPermission()} */
setArDebugPermission(boolean arDebugPermission)1476         public Source.Builder setArDebugPermission(boolean arDebugPermission) {
1477             mBuilding.mArDebugPermission = arDebugPermission;
1478             return this;
1479         }
1480 
1481         /** See {@link Source#getEventId()}. */
1482         @NonNull
setEventTime(long eventTime)1483         public Builder setEventTime(long eventTime) {
1484             mBuilding.mEventTime = eventTime;
1485             return this;
1486         }
1487 
1488         /**
1489          * See {@link Source#getExpiryTime()}.
1490          */
setExpiryTime(long expiryTime)1491         public Builder setExpiryTime(long expiryTime) {
1492             mBuilding.mExpiryTime = expiryTime;
1493             return this;
1494         }
1495 
1496         /** See {@link Source#getEventReportWindow()}. */
setEventReportWindow(Long eventReportWindow)1497         public Builder setEventReportWindow(Long eventReportWindow) {
1498             mBuilding.mEventReportWindow = eventReportWindow;
1499             return this;
1500         }
1501 
1502         /** See {@link Source#getEventReportWindows()} ()}. */
setEventReportWindows(String eventReportWindows)1503         public Builder setEventReportWindows(String eventReportWindows) {
1504             mBuilding.mEventReportWindows = eventReportWindows;
1505             return this;
1506         }
1507 
1508         /** See {@link Source#getAggregatableReportWindow()}. */
setAggregatableReportWindow(Long aggregateReportWindow)1509         public Builder setAggregatableReportWindow(Long aggregateReportWindow) {
1510             mBuilding.mAggregatableReportWindow = aggregateReportWindow;
1511             return this;
1512         }
1513 
1514         /** See {@link Source#getReinstallReattributionWindow()}. */
setReinstallReattributionWindow(Long reinstallReattributionWindow)1515         public Builder setReinstallReattributionWindow(Long reinstallReattributionWindow) {
1516             mBuilding.mReinstallReattributionWindow = reinstallReattributionWindow;
1517             return this;
1518         }
1519 
1520         /** See {@link Source#getPriority()}. */
1521         @NonNull
setPriority(long priority)1522         public Builder setPriority(long priority) {
1523             mBuilding.mPriority = priority;
1524             return this;
1525         }
1526 
1527         /** See {@link Source#getDebugKey()}. */
setDebugKey(@ullable UnsignedLong debugKey)1528         public Builder setDebugKey(@Nullable UnsignedLong debugKey) {
1529             mBuilding.mDebugKey = debugKey;
1530             return this;
1531         }
1532 
1533         /** See {@link Source#isDebugReporting()}. */
setIsDebugReporting(boolean isDebugReporting)1534         public Builder setIsDebugReporting(boolean isDebugReporting) {
1535             mBuilding.mIsDebugReporting = isDebugReporting;
1536             return this;
1537         }
1538 
1539         /** See {@link Source#getSourceType()}. */
1540         @NonNull
setSourceType(@onNull SourceType sourceType)1541         public Builder setSourceType(@NonNull SourceType sourceType) {
1542             Validation.validateNonNull(sourceType);
1543             mBuilding.mSourceType = sourceType;
1544             return this;
1545         }
1546 
1547         /** See {@link Source#getEventReportDedupKeys()}. */
1548         @NonNull
setEventReportDedupKeys(@ullable List<UnsignedLong> mEventReportDedupKeys)1549         public Builder setEventReportDedupKeys(@Nullable List<UnsignedLong> mEventReportDedupKeys) {
1550             mBuilding.mEventReportDedupKeys = mEventReportDedupKeys;
1551             return this;
1552         }
1553 
1554         /** See {@link Source#getAggregateReportDedupKeys()}. */
1555         @NonNull
setAggregateReportDedupKeys( @onNull List<UnsignedLong> mAggregateReportDedupKeys)1556         public Builder setAggregateReportDedupKeys(
1557                 @NonNull List<UnsignedLong> mAggregateReportDedupKeys) {
1558             mBuilding.mAggregateReportDedupKeys = mAggregateReportDedupKeys;
1559             return this;
1560         }
1561 
1562         /** See {@link Source#getStatus()}. */
1563         @NonNull
setStatus(@tatus int status)1564         public Builder setStatus(@Status int status) {
1565             mBuilding.mStatus = status;
1566             return this;
1567         }
1568 
1569         /** See {@link Source#getRegistrant()} */
1570         @NonNull
setRegistrant(@onNull Uri registrant)1571         public Builder setRegistrant(@NonNull Uri registrant) {
1572             Validation.validateUri(registrant);
1573             mBuilding.mRegistrant = registrant;
1574             return this;
1575         }
1576 
1577         /** See {@link Source#getAttributionMode()} */
1578         @NonNull
setAttributionMode(@ttributionMode int attributionMode)1579         public Builder setAttributionMode(@AttributionMode int attributionMode) {
1580             mBuilding.mAttributionMode = attributionMode;
1581             return this;
1582         }
1583 
1584         /** See {@link Source#getTriggerDataMatching()} */
1585         @NonNull
setTriggerDataMatching(TriggerDataMatching triggerDataMatching)1586         public Builder setTriggerDataMatching(TriggerDataMatching triggerDataMatching) {
1587             mBuilding.mTriggerDataMatching = triggerDataMatching;
1588             return this;
1589         }
1590 
1591         /** See {@link Source#getInstallAttributionWindow()} */
1592         @NonNull
setInstallAttributionWindow(long installAttributionWindow)1593         public Builder setInstallAttributionWindow(long installAttributionWindow) {
1594             mBuilding.mInstallAttributionWindow = installAttributionWindow;
1595             return this;
1596         }
1597 
1598         /** See {@link Source#getInstallCooldownWindow()} */
1599         @NonNull
setInstallCooldownWindow(long installCooldownWindow)1600         public Builder setInstallCooldownWindow(long installCooldownWindow) {
1601             mBuilding.mInstallCooldownWindow = installCooldownWindow;
1602             return this;
1603         }
1604 
1605         /** See {@link Source#isInstallAttributed()} */
1606         @NonNull
setInstallAttributed(boolean installAttributed)1607         public Builder setInstallAttributed(boolean installAttributed) {
1608             mBuilding.mIsInstallAttributed = installAttributed;
1609             return this;
1610         }
1611 
1612         /** See {@link Source#getFilterDataString()}. */
setFilterDataString(@ullable String filterMap)1613         public Builder setFilterDataString(@Nullable String filterMap) {
1614             mBuilding.mFilterDataString = filterMap;
1615             return this;
1616         }
1617 
1618         /** See {@link Source#getSharedFilterDataKeys()}. */
setSharedFilterDataKeys(@ullable String sharedFilterDataKeys)1619         public Builder setSharedFilterDataKeys(@Nullable String sharedFilterDataKeys) {
1620             mBuilding.mSharedFilterDataKeys = sharedFilterDataKeys;
1621             return this;
1622         }
1623 
1624         /** See {@link Source#getAggregateSource()} */
1625         @NonNull
setAggregateSource(@ullable String aggregateSource)1626         public Builder setAggregateSource(@Nullable String aggregateSource) {
1627             mBuilding.mAggregateSource = aggregateSource;
1628             return this;
1629         }
1630 
1631         /** See {@link Source#getAggregateContributions()} */
1632         @NonNull
setAggregateContributions(int aggregateContributions)1633         public Builder setAggregateContributions(int aggregateContributions) {
1634             mBuilding.mAggregateContributions = aggregateContributions;
1635             return this;
1636         }
1637 
1638         /** See {@link Source#getRegistrationId()} */
1639         @NonNull
setRegistrationId(@ullable String registrationId)1640         public Builder setRegistrationId(@Nullable String registrationId) {
1641             mBuilding.mRegistrationId = registrationId;
1642             return this;
1643         }
1644 
1645         /** See {@link Source#getSharedAggregationKeys()} */
1646         @NonNull
setSharedAggregationKeys(@ullable String sharedAggregationKeys)1647         public Builder setSharedAggregationKeys(@Nullable String sharedAggregationKeys) {
1648             mBuilding.mSharedAggregationKeys = sharedAggregationKeys;
1649             return this;
1650         }
1651 
1652         /** See {@link Source#getInstallTime()} */
1653         @NonNull
setInstallTime(@ullable Long installTime)1654         public Builder setInstallTime(@Nullable Long installTime) {
1655             mBuilding.mInstallTime = installTime;
1656             return this;
1657         }
1658 
1659         /** See {@link Source#getParentId()} */
1660         @NonNull
setParentId(@ullable String parentId)1661         public Builder setParentId(@Nullable String parentId) {
1662             mBuilding.mParentId = parentId;
1663             return this;
1664         }
1665 
1666         /** See {@link Source#getAggregatableAttributionSource()} */
1667         @NonNull
setAggregatableAttributionSource( @ullable AggregatableAttributionSource aggregatableAttributionSource)1668         public Builder setAggregatableAttributionSource(
1669                 @Nullable AggregatableAttributionSource aggregatableAttributionSource) {
1670             mBuilding.mAggregatableAttributionSource =
1671                     Optional.ofNullable(aggregatableAttributionSource);
1672             return this;
1673         }
1674 
1675         /** See {@link Source#getDebugJoinKey()} */
1676         @NonNull
setDebugJoinKey(@ullable String debugJoinKey)1677         public Builder setDebugJoinKey(@Nullable String debugJoinKey) {
1678             mBuilding.mDebugJoinKey = debugJoinKey;
1679             return this;
1680         }
1681 
1682         /** See {@link Source#getPlatformAdId()} */
1683         @NonNull
setPlatformAdId(@ullable String platformAdId)1684         public Builder setPlatformAdId(@Nullable String platformAdId) {
1685             mBuilding.mPlatformAdId = platformAdId;
1686             return this;
1687         }
1688 
1689         /** See {@link Source#getDebugAdId()} */
1690         @NonNull
setDebugAdId(@ullable String debugAdId)1691         public Builder setDebugAdId(@Nullable String debugAdId) {
1692             mBuilding.mDebugAdId = debugAdId;
1693             return this;
1694         }
1695 
1696         /** See {@link Source#getRegistrationOrigin()} ()} */
1697         @NonNull
setRegistrationOrigin(Uri registrationOrigin)1698         public Builder setRegistrationOrigin(Uri registrationOrigin) {
1699             mBuilding.mRegistrationOrigin = registrationOrigin;
1700             return this;
1701         }
1702 
1703         /** See {@link Source#getAttributedTriggers()} */
1704         @NonNull
setAttributedTriggers(@onNull List<AttributedTrigger> attributedTriggers)1705         public Builder setAttributedTriggers(@NonNull List<AttributedTrigger> attributedTriggers) {
1706             mBuilding.mAttributedTriggers = attributedTriggers;
1707             return this;
1708         }
1709 
1710         /** See {@link Source#getTriggerSpecs()} */
1711         @NonNull
setTriggerSpecs(@ullable TriggerSpecs triggerSpecs)1712         public Builder setTriggerSpecs(@Nullable TriggerSpecs triggerSpecs) {
1713             mBuilding.mTriggerSpecs = triggerSpecs;
1714             return this;
1715         }
1716 
1717         /** See {@link Source#hasCoarseEventReportDestinations()} */
1718         @NonNull
setCoarseEventReportDestinations(boolean coarseEventReportDestinations)1719         public Builder setCoarseEventReportDestinations(boolean coarseEventReportDestinations) {
1720             mBuilding.mCoarseEventReportDestinations = coarseEventReportDestinations;
1721             return this;
1722         }
1723 
1724         /** See {@link Source#getTriggerSpecsString()} */
1725         @NonNull
setTriggerSpecsString(@ullable String triggerSpecsString)1726         public Builder setTriggerSpecsString(@Nullable String triggerSpecsString) {
1727             mBuilding.mTriggerSpecsString = triggerSpecsString;
1728             return this;
1729         }
1730 
1731         /** See {@link Source#getMaxEventLevelReports()} */
1732         @NonNull
setMaxEventLevelReports(@ullable Integer maxEventLevelReports)1733         public Builder setMaxEventLevelReports(@Nullable Integer maxEventLevelReports) {
1734             mBuilding.mMaxEventLevelReports = maxEventLevelReports;
1735             return this;
1736         }
1737 
1738         /** See {@link Source#getEventAttributionStatus()} */
1739         @NonNull
setEventAttributionStatus(@ullable String eventAttributionStatus)1740         public Builder setEventAttributionStatus(@Nullable String eventAttributionStatus) {
1741             mBuilding.mEventAttributionStatusString = eventAttributionStatus;
1742             return this;
1743         }
1744 
1745         /** See {@link Source#getPrivacyParameters()} */
1746         @NonNull
setPrivacyParameters(@ullable String privacyParameters)1747         public Builder setPrivacyParameters(@Nullable String privacyParameters) {
1748             mBuilding.mPrivacyParametersString = privacyParameters;
1749             return this;
1750         }
1751 
1752         /** See {@link Source#getSharedDebugKey()}. */
1753         @NonNull
setSharedDebugKey(@ullable UnsignedLong sharedDebugKey)1754         public Builder setSharedDebugKey(@Nullable UnsignedLong sharedDebugKey) {
1755             mBuilding.mSharedDebugKey = sharedDebugKey;
1756             return this;
1757         }
1758 
1759         /** See {@link Source#shouldDropSourceIfInstalled()}. */
1760         @NonNull
setDropSourceIfInstalled(boolean dropSourceIfInstalled)1761         public Builder setDropSourceIfInstalled(boolean dropSourceIfInstalled) {
1762             mBuilding.mDropSourceIfInstalled = dropSourceIfInstalled;
1763             return this;
1764         }
1765 
1766         /** See {@link Source#getAttributionScopes()}. */
1767         @NonNull
setAttributionScopes(@ullable List<String> attributionScopes)1768         public Builder setAttributionScopes(@Nullable List<String> attributionScopes) {
1769             mBuilding.mAttributionScopes = attributionScopes;
1770             return this;
1771         }
1772 
1773         /** See {@link Source#getAttributionScopeLimit()}. */
1774         @NonNull
setAttributionScopeLimit(@ullable Long attributionScopeLimit)1775         public Builder setAttributionScopeLimit(@Nullable Long attributionScopeLimit) {
1776             mBuilding.mAttributionScopeLimit = attributionScopeLimit;
1777             return this;
1778         }
1779 
1780         /** See {@link Source#getMaxEventStates()}. */
1781         @NonNull
setMaxEventStates(@ullable Long maxEventStates)1782         public Builder setMaxEventStates(@Nullable Long maxEventStates) {
1783             mBuilding.mMaxEventStates = maxEventStates;
1784             return this;
1785         }
1786 
1787         /** Build the {@link Source}. */
1788         @NonNull
build()1789         public Source build() {
1790             Validation.validateNonNull(
1791                     mBuilding.mPublisher,
1792                     mBuilding.mEnrollmentId,
1793                     mBuilding.mRegistrant,
1794                     mBuilding.mSourceType,
1795                     mBuilding.mAggregateReportDedupKeys,
1796                     mBuilding.mEventReportDedupKeys,
1797                     mBuilding.mRegistrationOrigin);
1798 
1799             return mBuilding;
1800         }
1801     }
1802 }
1803