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.net.Uri;
22 import android.util.Pair;
23 
24 import androidx.annotation.Nullable;
25 
26 import com.android.adservices.service.measurement.noising.SourceNoiseHandler;
27 import com.android.adservices.service.measurement.reporting.EventReportWindowCalcDelegate;
28 import com.android.adservices.service.measurement.util.UnsignedLong;
29 
30 import com.google.common.collect.ImmutableMultiset;
31 
32 import java.lang.annotation.Retention;
33 import java.lang.annotation.RetentionPolicy;
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.Objects;
37 import java.util.UUID;
38 
39 /**
40  * POJO for EventReport.
41  */
42 public class EventReport {
43 
44     private String mId;
45     private UnsignedLong mSourceEventId;
46     private long mReportTime;
47     private long mTriggerTime;
48     private long mTriggerPriority;
49     private List<Uri> mAttributionDestinations;
50     private String mEnrollmentId;
51     private UnsignedLong mTriggerData;
52     private UnsignedLong mTriggerDedupKey;
53     private double mRandomizedTriggerRate;
54     private @Status int mStatus;
55     private @DebugReportStatus int mDebugReportStatus;
56     private Source.SourceType mSourceType;
57     @Nullable private UnsignedLong mSourceDebugKey;
58     @Nullable private UnsignedLong mTriggerDebugKey;
59     @NonNull private List<UnsignedLong> mTriggerDebugKeys;
60     private String mSourceId;
61     private String mTriggerId;
62     private Uri mRegistrationOrigin;
63     private long mTriggerValue;
64     private Pair<Long, Long> mTriggerSummaryBucket;
65 
66     @IntDef(value = {Status.PENDING, Status.DELIVERED, Status.MARKED_TO_DELETE})
67     @Retention(RetentionPolicy.SOURCE)
68     public @interface Status {
69         int PENDING = 0;
70         int DELIVERED = 1;
71         int MARKED_TO_DELETE = 2;
72     }
73 
74     @IntDef(
75             value = {
76                 DebugReportStatus.NONE,
77                 DebugReportStatus.PENDING,
78                 DebugReportStatus.DELIVERED,
79             })
80     @Retention(RetentionPolicy.SOURCE)
81     public @interface DebugReportStatus {
82         int NONE = 0;
83         int PENDING = 1;
84         int DELIVERED = 2;
85     }
86 
EventReport()87     private EventReport() {
88         mTriggerDedupKey = null;
89         mTriggerDebugKeys = new ArrayList<>();
90     }
91 
92     @Override
equals(Object obj)93     public boolean equals(Object obj) {
94         if (!(obj instanceof EventReport)) {
95             return false;
96         }
97         EventReport eventReport = (EventReport) obj;
98         return mStatus == eventReport.mStatus
99                 && mDebugReportStatus == eventReport.mDebugReportStatus
100                 && mReportTime == eventReport.mReportTime
101                 && Objects.equals(mAttributionDestinations, eventReport.mAttributionDestinations)
102                 && ImmutableMultiset.copyOf(mAttributionDestinations)
103                         .equals(ImmutableMultiset.copyOf(eventReport.mAttributionDestinations))
104                 && Objects.equals(mEnrollmentId, eventReport.mEnrollmentId)
105                 && mTriggerTime == eventReport.mTriggerTime
106                 && Objects.equals(mTriggerData, eventReport.mTriggerData)
107                 && Objects.equals(mSourceEventId, eventReport.mSourceEventId)
108                 && mTriggerPriority == eventReport.mTriggerPriority
109                 && Objects.equals(mTriggerDedupKey, eventReport.mTriggerDedupKey)
110                 && mSourceType == eventReport.mSourceType
111                 && mRandomizedTriggerRate == eventReport.mRandomizedTriggerRate
112                 && Objects.equals(mSourceDebugKey, eventReport.mSourceDebugKey)
113                 && Objects.equals(mTriggerDebugKey, eventReport.mTriggerDebugKey)
114                 && Objects.equals(mTriggerDebugKeys, eventReport.mTriggerDebugKeys)
115                 && Objects.equals(mSourceId, eventReport.mSourceId)
116                 && Objects.equals(mTriggerId, eventReport.mTriggerId)
117                 && Objects.equals(mRegistrationOrigin, eventReport.mRegistrationOrigin)
118                 && mTriggerValue == eventReport.mTriggerValue
119                 && Objects.equals(mTriggerSummaryBucket, eventReport.mTriggerSummaryBucket);
120     }
121 
122     @Override
hashCode()123     public int hashCode() {
124         return Objects.hash(
125                 mStatus,
126                 mDebugReportStatus,
127                 mReportTime,
128                 mAttributionDestinations,
129                 mEnrollmentId,
130                 mTriggerTime,
131                 mTriggerData,
132                 mSourceEventId,
133                 mTriggerPriority,
134                 mTriggerDedupKey,
135                 mSourceType,
136                 mRandomizedTriggerRate,
137                 mSourceDebugKey,
138                 mTriggerDebugKey,
139                 mTriggerDebugKeys,
140                 mSourceId,
141                 mTriggerId,
142                 mRegistrationOrigin,
143                 mTriggerValue,
144                 mTriggerSummaryBucket);
145     }
146 
147     /** Unique identifier for the report. */
getId()148     public String getId() {
149         return mId;
150     }
151 
152     /** Identifier of the associated {@link Source} event. */
getSourceEventId()153     public UnsignedLong getSourceEventId() {
154         return mSourceEventId;
155     }
156 
157     /**
158      * Scheduled time for the report to be sent.
159      */
getReportTime()160     public long getReportTime() {
161         return mReportTime;
162     }
163 
164     /**
165      * TriggerTime of the associated {@link Trigger}.
166      */
getTriggerTime()167     public long getTriggerTime() {
168         return mTriggerTime;
169     }
170 
171     /**
172      * Priority of the associated {@link Trigger}.
173      */
getTriggerPriority()174     public long getTriggerPriority() {
175         return mTriggerPriority;
176     }
177 
178     /**
179      * AttributionDestinations of the {@link Source} and {@link Trigger}.
180      */
getAttributionDestinations()181     public List<Uri> getAttributionDestinations() {
182         return mAttributionDestinations;
183     }
184 
185     /**
186      * Ad Tech enrollment ID.
187      */
getEnrollmentId()188     public String getEnrollmentId() {
189         return mEnrollmentId;
190     }
191 
192     /**
193      * Metadata for the report.
194      */
getTriggerData()195     public UnsignedLong getTriggerData() {
196         return mTriggerData;
197     }
198 
199     /**
200      * Deduplication key of the associated {@link Trigger}
201      */
getTriggerDedupKey()202     public UnsignedLong getTriggerDedupKey() {
203         return mTriggerDedupKey;
204     }
205 
206     /**
207      * Current {@link Status} of the report.
208      */
getStatus()209     public @Status int getStatus() {
210         return mStatus;
211     }
212 
213     /** Current {@link DebugReportStatus} of the report. */
getDebugReportStatus()214     public @DebugReportStatus int getDebugReportStatus() {
215         return mDebugReportStatus;
216     }
217 
218     /**
219      * SourceType of the event's source.
220      */
getSourceType()221     public Source.SourceType getSourceType() {
222         return mSourceType;
223     }
224 
225     /**
226      * Randomized trigger rate for noising
227      */
getRandomizedTriggerRate()228     public double getRandomizedTriggerRate() {
229         return mRandomizedTriggerRate;
230     }
231 
232     /** Source Debug Key */
233     @Nullable
getSourceDebugKey()234     public UnsignedLong getSourceDebugKey() {
235         return mSourceDebugKey;
236     }
237 
238     /** Trigger Debug Key */
239     @Nullable
getTriggerDebugKey()240     public UnsignedLong getTriggerDebugKey() {
241         return mTriggerDebugKey;
242     }
243 
244     /** Trigger Debug Keys */
245     @NonNull
getTriggerDebugKeys()246     public List<UnsignedLong> getTriggerDebugKeys() {
247         return mTriggerDebugKeys;
248     }
249 
250     /** Source ID */
getSourceId()251     public String getSourceId() {
252         return mSourceId;
253     }
254 
255     /** Trigger ID */
getTriggerId()256     public String getTriggerId() {
257         return mTriggerId;
258     }
259 
260     /** Trigger summary bucket */
getTriggerSummaryBucket()261     public Pair<Long, Long> getTriggerSummaryBucket() {
262         return mTriggerSummaryBucket;
263     }
264 
265     /** Returns registration origin used to register the source and trigger */
getRegistrationOrigin()266     public Uri getRegistrationOrigin() {
267         return mRegistrationOrigin;
268     }
269 
270     /** Trigger Value */
getTriggerValue()271     public long getTriggerValue() {
272         return mTriggerValue;
273     }
274 
275     /** Get Summary Bucket As String */
getStringEncodedTriggerSummaryBucket()276     public String getStringEncodedTriggerSummaryBucket() {
277         if (mTriggerSummaryBucket == null) {
278             return null;
279         } else {
280             return mTriggerSummaryBucket.first + "," + mTriggerSummaryBucket.second;
281         }
282     }
283 
284     /** Builder for {@link EventReport} */
285     public static final class Builder {
286 
287         private final EventReport mBuilding;
288 
Builder()289         public Builder() {
290             mBuilding = new EventReport();
291         }
292 
293         /** See {@link EventReport#getId()} */
setId(String id)294         public Builder setId(String id) {
295             mBuilding.mId = id;
296             return this;
297         }
298 
299         /** See {@link EventReport#getSourceEventId()} */
setSourceEventId(UnsignedLong sourceEventId)300         public Builder setSourceEventId(UnsignedLong sourceEventId) {
301             mBuilding.mSourceEventId = sourceEventId;
302             return this;
303         }
304 
305         /** See {@link EventReport#getEnrollmentId()} */
setEnrollmentId(String enrollmentId)306         public Builder setEnrollmentId(String enrollmentId) {
307             mBuilding.mEnrollmentId = enrollmentId;
308             return this;
309         }
310 
311         /** See {@link EventReport#getAttributionDestinations()} */
setAttributionDestinations(List<Uri> attributionDestinations)312         public Builder setAttributionDestinations(List<Uri> attributionDestinations) {
313             mBuilding.mAttributionDestinations = attributionDestinations;
314             return this;
315         }
316 
317         /**
318          * See {@link EventReport#getTriggerTime()}
319          */
setTriggerTime(long triggerTime)320         public Builder setTriggerTime(long triggerTime) {
321             mBuilding.mTriggerTime = triggerTime;
322             return this;
323         }
324 
325         /**
326          * See {@link EventReport#getTriggerData()}
327          */
setTriggerData(UnsignedLong triggerData)328         public Builder setTriggerData(UnsignedLong triggerData) {
329             mBuilding.mTriggerData = triggerData;
330             return this;
331         }
332 
333         /**
334          * See {@link EventReport#getTriggerPriority()}
335          */
setTriggerPriority(long triggerPriority)336         public Builder setTriggerPriority(long triggerPriority) {
337             mBuilding.mTriggerPriority = triggerPriority;
338             return this;
339         }
340 
341         /**
342          * See {@link EventReport#getTriggerDedupKey()}
343          */
setTriggerDedupKey(UnsignedLong triggerDedupKey)344         public Builder setTriggerDedupKey(UnsignedLong triggerDedupKey) {
345             mBuilding.mTriggerDedupKey = triggerDedupKey;
346             return this;
347         }
348 
349         /**
350          * See {@link EventReport#getReportTime()}
351          */
setReportTime(long reportTime)352         public Builder setReportTime(long reportTime) {
353             mBuilding.mReportTime = reportTime;
354             return this;
355         }
356 
357         /**
358          * See {@link EventReport#getStatus()}
359          */
setStatus(@tatus int status)360         public Builder setStatus(@Status int status) {
361             mBuilding.mStatus = status;
362             return this;
363         }
364 
365         /** See {@link EventReport#getDebugReportStatus()}} */
setDebugReportStatus(@ebugReportStatus int debugReportStatus)366         public Builder setDebugReportStatus(@DebugReportStatus int debugReportStatus) {
367             mBuilding.mDebugReportStatus = debugReportStatus;
368             return this;
369         }
370 
371         /**
372          * See {@link EventReport#getSourceType()}
373          */
setSourceType(Source.SourceType sourceType)374         public Builder setSourceType(Source.SourceType sourceType) {
375             mBuilding.mSourceType = sourceType;
376             return this;
377         }
378 
379         /** See {@link EventReport#getRandomizedTriggerRate()}} */
setRandomizedTriggerRate(double randomizedTriggerRate)380         public Builder setRandomizedTriggerRate(double randomizedTriggerRate) {
381             mBuilding.mRandomizedTriggerRate = randomizedTriggerRate;
382             return this;
383         }
384 
385         /** See {@link EventReport#getSourceDebugKey()}} */
setSourceDebugKey(UnsignedLong sourceDebugKey)386         public Builder setSourceDebugKey(UnsignedLong sourceDebugKey) {
387             mBuilding.mSourceDebugKey = sourceDebugKey;
388             return this;
389         }
390 
391         /** See {@link EventReport#getTriggerDebugKey()}} */
setTriggerDebugKey(UnsignedLong triggerDebugKey)392         public Builder setTriggerDebugKey(UnsignedLong triggerDebugKey) {
393             mBuilding.mTriggerDebugKey = triggerDebugKey;
394             return this;
395         }
396 
397         /** See {@link EventReport#getTriggerDebugKeys()}} */
setTriggerDebugKeys(List<UnsignedLong> triggerDebugKeys)398         public Builder setTriggerDebugKeys(List<UnsignedLong> triggerDebugKeys) {
399             mBuilding.mTriggerDebugKeys = triggerDebugKeys;
400             return this;
401         }
402 
403         /** See {@link EventReport#getSourceId()} */
setSourceId(String sourceId)404         public Builder setSourceId(String sourceId) {
405             mBuilding.mSourceId = sourceId;
406             return this;
407         }
408 
409         /** See {@link EventReport#getTriggerId()} */
setTriggerId(String triggerId)410         public Builder setTriggerId(String triggerId) {
411             mBuilding.mTriggerId = triggerId;
412             return this;
413         }
414 
415         /**
416          * set the summary bucket from input DB text encode summary bucket
417          *
418          * @param summaryBucket the string encoded summary bucket
419          * @return builder
420          */
setTriggerSummaryBucket(@ullable String summaryBucket)421         public Builder setTriggerSummaryBucket(@Nullable String summaryBucket) {
422             if (summaryBucket == null || summaryBucket.isEmpty()) {
423                 mBuilding.mTriggerSummaryBucket = null;
424                 return this;
425             }
426             String[] numbers = summaryBucket.split(",");
427 
428             Long firstNumber = Long.parseLong(numbers[0].trim());
429             Long secondNumber = Long.parseLong(numbers[1].trim());
430             mBuilding.mTriggerSummaryBucket = new Pair<>(firstNumber, secondNumber);
431 
432             return this;
433         }
434 
435         /** See {@link EventReport#getTriggerSummaryBucket()} */
setTriggerSummaryBucket(@ullable Pair<Long, Long> summaryBucket)436         public Builder setTriggerSummaryBucket(@Nullable Pair<Long, Long> summaryBucket) {
437             mBuilding.mTriggerSummaryBucket = summaryBucket;
438             return this;
439         }
440 
441         /** See {@link EventReport#getTriggerId()} */
setTriggerValue(long triggerValue)442         public Builder setTriggerValue(long triggerValue) {
443             mBuilding.mTriggerValue = triggerValue;
444             return this;
445         }
446 
447         /** See {@link Source#getRegistrationOrigin()} ()} */
448         @NonNull
setRegistrationOrigin(Uri registrationOrigin)449         public Builder setRegistrationOrigin(Uri registrationOrigin) {
450             mBuilding.mRegistrationOrigin = registrationOrigin;
451             return this;
452         }
453 
454         // TODO (b/285607306): cleanup since this doesn't just do "populateFromSourceAndTrigger"
455         /** Populates fields using {@link Source}, {@link Trigger} and {@link EventTrigger}. */
populateFromSourceAndTrigger( @onNull Source source, @NonNull Trigger trigger, @NonNull EventTrigger eventTrigger, @NonNull Pair<UnsignedLong, UnsignedLong> debugKeyPair, @NonNull EventReportWindowCalcDelegate eventReportWindowCalcDelegate, @NonNull SourceNoiseHandler sourceNoiseHandler, List<Uri> eventReportDestinations)456         public Builder populateFromSourceAndTrigger(
457                 @NonNull Source source,
458                 @NonNull Trigger trigger,
459                 @NonNull EventTrigger eventTrigger,
460                 @NonNull Pair<UnsignedLong, UnsignedLong> debugKeyPair,
461                 @NonNull EventReportWindowCalcDelegate eventReportWindowCalcDelegate,
462                 @NonNull SourceNoiseHandler sourceNoiseHandler,
463                 List<Uri> eventReportDestinations) {
464             mBuilding.mId = UUID.randomUUID().toString();
465             mBuilding.mTriggerDedupKey = eventTrigger.getDedupKey();
466             mBuilding.mTriggerTime = trigger.getTriggerTime();
467             mBuilding.mSourceEventId = source.getEventId();
468             mBuilding.mEnrollmentId = source.getEnrollmentId();
469             mBuilding.mStatus = Status.PENDING;
470             mBuilding.mAttributionDestinations = eventReportDestinations;
471             mBuilding.mSourceType = source.getSourceType();
472             mBuilding.mSourceDebugKey = debugKeyPair.first;
473             mBuilding.mTriggerDebugKey = debugKeyPair.second;
474             mBuilding.mDebugReportStatus = DebugReportStatus.NONE;
475             if (mBuilding.mSourceDebugKey != null && mBuilding.mTriggerDebugKey != null) {
476                 mBuilding.mDebugReportStatus = DebugReportStatus.PENDING;
477             }
478             mBuilding.mSourceId = source.getId();
479             mBuilding.mTriggerId = trigger.getId();
480             mBuilding.mRegistrationOrigin = trigger.getRegistrationOrigin();
481             mBuilding.mTriggerPriority = eventTrigger.getTriggerPriority();
482             // truncate trigger data to 3-bit or 1-bit based on {@link Source.SourceType}
483             mBuilding.mTriggerData = getTruncatedTriggerData(source, eventTrigger);
484             mBuilding.mReportTime =
485                     eventReportWindowCalcDelegate.getReportingTime(
486                             source, trigger.getTriggerTime(), trigger.getDestinationType());
487             mBuilding.mRandomizedTriggerRate =
488                     sourceNoiseHandler.getRandomizedTriggerRate(source);
489             return this;
490         }
491 
492         /** Provides event report builder for flexible event-level reports */
getForFlex( @onNull Source source, @NonNull Trigger trigger, @NonNull AttributedTrigger attributedTrigger, long reportTime, @NonNull Pair<Long, Long> triggerSummaryBucket, @Nullable UnsignedLong sourceDebugKey, @NonNull List<UnsignedLong> debugKeys, double flipProbability, List<Uri> eventReportDestinations)493         public Builder getForFlex(
494                 @NonNull Source source,
495                 @NonNull Trigger trigger,
496                 @NonNull AttributedTrigger attributedTrigger,
497                 long reportTime,
498                 @NonNull Pair<Long, Long> triggerSummaryBucket,
499                 @Nullable UnsignedLong sourceDebugKey,
500                 @NonNull List<UnsignedLong> debugKeys,
501                 double flipProbability,
502                 List<Uri> eventReportDestinations) {
503             mBuilding.mId = UUID.randomUUID().toString();
504             mBuilding.mTriggerTime = trigger.getTriggerTime();
505             mBuilding.mSourceEventId = source.getEventId();
506             mBuilding.mEnrollmentId = source.getEnrollmentId();
507             mBuilding.mStatus = Status.PENDING;
508             mBuilding.mAttributionDestinations = eventReportDestinations;
509             mBuilding.mSourceType = source.getSourceType();
510             mBuilding.mSourceDebugKey = sourceDebugKey;
511             mBuilding.mTriggerDebugKeys = debugKeys;
512             mBuilding.mDebugReportStatus = DebugReportStatus.NONE;
513             if (mBuilding.mSourceDebugKey != null && debugKeys.size() > 0) {
514                 mBuilding.mDebugReportStatus = DebugReportStatus.PENDING;
515             }
516             mBuilding.mSourceId = source.getId();
517             mBuilding.mTriggerId = trigger.getId();
518             mBuilding.mRegistrationOrigin = trigger.getRegistrationOrigin();
519             mBuilding.mRandomizedTriggerRate = flipProbability;
520             mBuilding.mTriggerData = attributedTrigger.getTriggerData();
521             mBuilding.mReportTime = reportTime;
522             mBuilding.mTriggerSummaryBucket = triggerSummaryBucket;
523             return this;
524         }
525 
getTruncatedTriggerData(Source source, EventTrigger eventTrigger)526         private UnsignedLong getTruncatedTriggerData(Source source, EventTrigger eventTrigger) {
527             UnsignedLong triggerData = eventTrigger.getTriggerData();
528             return triggerData.mod(source.getTriggerDataCardinality());
529         }
530 
531         /**
532          * Build the {@link EventReport}.
533          */
build()534         public EventReport build() {
535             return mBuilding;
536         }
537     }
538 }
539