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 /** 285 * Returns true if this EventReport is randomized. 286 * Randomized EventReports are not triggered by a specific event. 287 */ isRandomized()288 public boolean isRandomized() { 289 return mTriggerId == null; 290 } 291 292 /** Builder for {@link EventReport} */ 293 public static final class Builder { 294 295 private final EventReport mBuilding; 296 Builder()297 public Builder() { 298 mBuilding = new EventReport(); 299 } 300 301 /** See {@link EventReport#getId()} */ setId(String id)302 public Builder setId(String id) { 303 mBuilding.mId = id; 304 return this; 305 } 306 307 /** See {@link EventReport#getSourceEventId()} */ setSourceEventId(UnsignedLong sourceEventId)308 public Builder setSourceEventId(UnsignedLong sourceEventId) { 309 mBuilding.mSourceEventId = sourceEventId; 310 return this; 311 } 312 313 /** See {@link EventReport#getEnrollmentId()} */ setEnrollmentId(String enrollmentId)314 public Builder setEnrollmentId(String enrollmentId) { 315 mBuilding.mEnrollmentId = enrollmentId; 316 return this; 317 } 318 319 /** See {@link EventReport#getAttributionDestinations()} */ setAttributionDestinations(List<Uri> attributionDestinations)320 public Builder setAttributionDestinations(List<Uri> attributionDestinations) { 321 mBuilding.mAttributionDestinations = attributionDestinations; 322 return this; 323 } 324 325 /** 326 * See {@link EventReport#getTriggerTime()} 327 */ setTriggerTime(long triggerTime)328 public Builder setTriggerTime(long triggerTime) { 329 mBuilding.mTriggerTime = triggerTime; 330 return this; 331 } 332 333 /** 334 * See {@link EventReport#getTriggerData()} 335 */ setTriggerData(UnsignedLong triggerData)336 public Builder setTriggerData(UnsignedLong triggerData) { 337 mBuilding.mTriggerData = triggerData; 338 return this; 339 } 340 341 /** 342 * See {@link EventReport#getTriggerPriority()} 343 */ setTriggerPriority(long triggerPriority)344 public Builder setTriggerPriority(long triggerPriority) { 345 mBuilding.mTriggerPriority = triggerPriority; 346 return this; 347 } 348 349 /** 350 * See {@link EventReport#getTriggerDedupKey()} 351 */ setTriggerDedupKey(UnsignedLong triggerDedupKey)352 public Builder setTriggerDedupKey(UnsignedLong triggerDedupKey) { 353 mBuilding.mTriggerDedupKey = triggerDedupKey; 354 return this; 355 } 356 357 /** 358 * See {@link EventReport#getReportTime()} 359 */ setReportTime(long reportTime)360 public Builder setReportTime(long reportTime) { 361 mBuilding.mReportTime = reportTime; 362 return this; 363 } 364 365 /** 366 * See {@link EventReport#getStatus()} 367 */ setStatus(@tatus int status)368 public Builder setStatus(@Status int status) { 369 mBuilding.mStatus = status; 370 return this; 371 } 372 373 /** See {@link EventReport#getDebugReportStatus()}} */ setDebugReportStatus(@ebugReportStatus int debugReportStatus)374 public Builder setDebugReportStatus(@DebugReportStatus int debugReportStatus) { 375 mBuilding.mDebugReportStatus = debugReportStatus; 376 return this; 377 } 378 379 /** 380 * See {@link EventReport#getSourceType()} 381 */ setSourceType(Source.SourceType sourceType)382 public Builder setSourceType(Source.SourceType sourceType) { 383 mBuilding.mSourceType = sourceType; 384 return this; 385 } 386 387 /** See {@link EventReport#getRandomizedTriggerRate()}} */ setRandomizedTriggerRate(double randomizedTriggerRate)388 public Builder setRandomizedTriggerRate(double randomizedTriggerRate) { 389 mBuilding.mRandomizedTriggerRate = randomizedTriggerRate; 390 return this; 391 } 392 393 /** See {@link EventReport#getSourceDebugKey()}} */ setSourceDebugKey(UnsignedLong sourceDebugKey)394 public Builder setSourceDebugKey(UnsignedLong sourceDebugKey) { 395 mBuilding.mSourceDebugKey = sourceDebugKey; 396 return this; 397 } 398 399 /** See {@link EventReport#getTriggerDebugKey()}} */ setTriggerDebugKey(UnsignedLong triggerDebugKey)400 public Builder setTriggerDebugKey(UnsignedLong triggerDebugKey) { 401 mBuilding.mTriggerDebugKey = triggerDebugKey; 402 return this; 403 } 404 405 /** See {@link EventReport#getTriggerDebugKeys()}} */ setTriggerDebugKeys(List<UnsignedLong> triggerDebugKeys)406 public Builder setTriggerDebugKeys(List<UnsignedLong> triggerDebugKeys) { 407 mBuilding.mTriggerDebugKeys = triggerDebugKeys; 408 return this; 409 } 410 411 /** See {@link EventReport#getSourceId()} */ setSourceId(String sourceId)412 public Builder setSourceId(String sourceId) { 413 mBuilding.mSourceId = sourceId; 414 return this; 415 } 416 417 /** See {@link EventReport#getTriggerId()} */ setTriggerId(String triggerId)418 public Builder setTriggerId(String triggerId) { 419 mBuilding.mTriggerId = triggerId; 420 return this; 421 } 422 423 /** 424 * set the summary bucket from input DB text encode summary bucket 425 * 426 * @param summaryBucket the string encoded summary bucket 427 * @return builder 428 */ setTriggerSummaryBucket(@ullable String summaryBucket)429 public Builder setTriggerSummaryBucket(@Nullable String summaryBucket) { 430 if (summaryBucket == null || summaryBucket.isEmpty()) { 431 mBuilding.mTriggerSummaryBucket = null; 432 return this; 433 } 434 String[] numbers = summaryBucket.split(","); 435 436 Long firstNumber = Long.parseLong(numbers[0].trim()); 437 Long secondNumber = Long.parseLong(numbers[1].trim()); 438 mBuilding.mTriggerSummaryBucket = new Pair<>(firstNumber, secondNumber); 439 440 return this; 441 } 442 443 /** See {@link EventReport#getTriggerSummaryBucket()} */ setTriggerSummaryBucket(@ullable Pair<Long, Long> summaryBucket)444 public Builder setTriggerSummaryBucket(@Nullable Pair<Long, Long> summaryBucket) { 445 mBuilding.mTriggerSummaryBucket = summaryBucket; 446 return this; 447 } 448 449 /** See {@link EventReport#getTriggerId()} */ setTriggerValue(long triggerValue)450 public Builder setTriggerValue(long triggerValue) { 451 mBuilding.mTriggerValue = triggerValue; 452 return this; 453 } 454 455 /** See {@link Source#getRegistrationOrigin()} ()} */ 456 @NonNull setRegistrationOrigin(Uri registrationOrigin)457 public Builder setRegistrationOrigin(Uri registrationOrigin) { 458 mBuilding.mRegistrationOrigin = registrationOrigin; 459 return this; 460 } 461 462 // TODO (b/285607306): cleanup since this doesn't just do "populateFromSourceAndTrigger" 463 /** Populates fields using {@link Source}, {@link Trigger} and {@link EventTrigger}. */ populateFromSourceAndTrigger( @onNull Source source, @NonNull Trigger trigger, @NonNull UnsignedLong effectiveTriggerData, @NonNull EventTrigger eventTrigger, @NonNull Pair<UnsignedLong, UnsignedLong> debugKeyPair, @NonNull EventReportWindowCalcDelegate eventReportWindowCalcDelegate, @NonNull SourceNoiseHandler sourceNoiseHandler, List<Uri> eventReportDestinations)464 public Builder populateFromSourceAndTrigger( 465 @NonNull Source source, 466 @NonNull Trigger trigger, 467 @NonNull UnsignedLong effectiveTriggerData, 468 @NonNull EventTrigger eventTrigger, 469 @NonNull Pair<UnsignedLong, UnsignedLong> debugKeyPair, 470 @NonNull EventReportWindowCalcDelegate eventReportWindowCalcDelegate, 471 @NonNull SourceNoiseHandler sourceNoiseHandler, 472 List<Uri> eventReportDestinations) { 473 mBuilding.mId = UUID.randomUUID().toString(); 474 mBuilding.mTriggerDedupKey = eventTrigger.getDedupKey(); 475 mBuilding.mTriggerTime = trigger.getTriggerTime(); 476 mBuilding.mSourceEventId = source.getEventId(); 477 mBuilding.mEnrollmentId = source.getEnrollmentId(); 478 mBuilding.mStatus = Status.PENDING; 479 mBuilding.mAttributionDestinations = eventReportDestinations; 480 mBuilding.mSourceType = source.getSourceType(); 481 mBuilding.mSourceDebugKey = debugKeyPair.first; 482 mBuilding.mTriggerDebugKey = debugKeyPair.second; 483 mBuilding.mDebugReportStatus = DebugReportStatus.NONE; 484 if (mBuilding.mSourceDebugKey != null && mBuilding.mTriggerDebugKey != null) { 485 mBuilding.mDebugReportStatus = DebugReportStatus.PENDING; 486 } 487 mBuilding.mSourceId = source.getId(); 488 mBuilding.mTriggerId = trigger.getId(); 489 mBuilding.mRegistrationOrigin = trigger.getRegistrationOrigin(); 490 mBuilding.mTriggerPriority = eventTrigger.getTriggerPriority(); 491 mBuilding.mTriggerData = effectiveTriggerData; 492 mBuilding.mReportTime = 493 eventReportWindowCalcDelegate.getReportingTime( 494 source, trigger.getTriggerTime(), trigger.getDestinationType()); 495 mBuilding.mRandomizedTriggerRate = 496 sourceNoiseHandler.getRandomizedTriggerRate(source); 497 return this; 498 } 499 500 /** 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)501 public Builder getForFlex( 502 @NonNull Source source, 503 @NonNull Trigger trigger, 504 @NonNull AttributedTrigger attributedTrigger, 505 long reportTime, 506 @NonNull Pair<Long, Long> triggerSummaryBucket, 507 @Nullable UnsignedLong sourceDebugKey, 508 @NonNull List<UnsignedLong> debugKeys, 509 double flipProbability, 510 List<Uri> eventReportDestinations) { 511 mBuilding.mId = UUID.randomUUID().toString(); 512 mBuilding.mTriggerTime = trigger.getTriggerTime(); 513 mBuilding.mSourceEventId = source.getEventId(); 514 mBuilding.mEnrollmentId = source.getEnrollmentId(); 515 mBuilding.mStatus = Status.PENDING; 516 mBuilding.mAttributionDestinations = eventReportDestinations; 517 mBuilding.mSourceType = source.getSourceType(); 518 mBuilding.mSourceDebugKey = sourceDebugKey; 519 mBuilding.mTriggerDebugKeys = debugKeys; 520 mBuilding.mDebugReportStatus = DebugReportStatus.NONE; 521 if (mBuilding.mSourceDebugKey != null && debugKeys.size() > 0) { 522 mBuilding.mDebugReportStatus = DebugReportStatus.PENDING; 523 } 524 mBuilding.mSourceId = source.getId(); 525 mBuilding.mTriggerId = trigger.getId(); 526 mBuilding.mRegistrationOrigin = trigger.getRegistrationOrigin(); 527 mBuilding.mRandomizedTriggerRate = flipProbability; 528 mBuilding.mTriggerData = attributedTrigger.getTriggerData(); 529 mBuilding.mReportTime = reportTime; 530 mBuilding.mTriggerSummaryBucket = triggerSummaryBucket; 531 return this; 532 } 533 534 /** 535 * Build the {@link EventReport}. 536 */ build()537 public EventReport build() { 538 return mBuilding; 539 } 540 } 541 } 542