diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-01-10 19:01:23 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-01-10 19:01:23 +0000 |
commit | 41e7bbcf3d375486769059090e15260dc92f16c7 (patch) | |
tree | 5c368873297b82c25a8ba866cbeda97cce94d9fc /adservices/service-core/java/com/android/adservices/service/measurement/reporting | |
parent | 4f73884441d6a5c6ba4af7e5026807822aa034a0 (diff) | |
parent | 7f6cf1d740d6f047507d8bd2bc07ab12496e8024 (diff) | |
download | AdServices-aml_tz5_341510010.tar.gz |
Snap for 11296156 from 7f6cf1d740d6f047507d8bd2bc07ab12496e8024 to mainline-tzdata5-releaseaml_tz5_341510070aml_tz5_341510050aml_tz5_341510010aml_tz5_341510010
Change-Id: I84e6c0df7ccbfafbe8dd398518474c2b7a676013
Diffstat (limited to 'adservices/service-core/java/com/android/adservices/service/measurement/reporting')
7 files changed, 183 insertions, 132 deletions
diff --git a/adservices/service-core/java/com/android/adservices/service/measurement/reporting/AggregateReportBody.java b/adservices/service-core/java/com/android/adservices/service/measurement/reporting/AggregateReportBody.java index a4d1971070..0498d4a85c 100644 --- a/adservices/service-core/java/com/android/adservices/service/measurement/reporting/AggregateReportBody.java +++ b/adservices/service-core/java/com/android/adservices/service/measurement/reporting/AggregateReportBody.java @@ -50,7 +50,8 @@ public class AggregateReportBody { private static final String API_NAME = "attribution-reporting"; - private interface PayloadBodyKeys { + @VisibleForTesting + interface PayloadBodyKeys { String SHARED_INFO = "shared_info"; String AGGREGATION_SERVICE_PAYLOADS = "aggregation_service_payloads"; String SOURCE_DEBUG_KEY = "source_debug_key"; @@ -64,7 +65,8 @@ public class AggregateReportBody { String DEBUG_CLEARTEXT_PAYLOAD = "debug_cleartext_payload"; } - private interface SharedInfoKeys { + @VisibleForTesting + interface SharedInfoKeys { String API_NAME = "api"; String ATTRIBUTION_DESTINATION = "attribution_destination"; String REPORT_ID = "report_id"; diff --git a/adservices/service-core/java/com/android/adservices/service/measurement/reporting/AggregateReportingJobHandler.java b/adservices/service-core/java/com/android/adservices/service/measurement/reporting/AggregateReportingJobHandler.java index 4367ee1b8b..849ec8164b 100644 --- a/adservices/service-core/java/com/android/adservices/service/measurement/reporting/AggregateReportingJobHandler.java +++ b/adservices/service-core/java/com/android/adservices/service/measurement/reporting/AggregateReportingJobHandler.java @@ -16,7 +16,10 @@ package com.android.adservices.service.measurement.reporting; -import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ERROR_CODE_UNSPECIFIED; +import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__MEASUREMENT_REPORTING_ENCRYPTION_ERROR; +import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__MEASUREMENT_REPORTING_NETWORK_ERROR; +import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__MEASUREMENT_REPORTING_PARSING_ERROR; +import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__MEASUREMENT_REPORTING_UNKNOWN_ERROR; import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__MEASUREMENT; import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_MESUREMENT_REPORTS_UPLOADED; @@ -289,7 +292,7 @@ public class AggregateReportingJobHandler { // TODO(b/298330312): Change to defined error codes ErrorLogUtil.e( e, - AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ERROR_CODE_UNSPECIFIED, + AD_SERVICES_ERROR_REPORTED__ERROR_CODE__MEASUREMENT_REPORTING_NETWORK_ERROR, AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__MEASUREMENT); return AdServicesStatusUtils.STATUS_IO_ERROR; } catch (JSONException e) { @@ -299,7 +302,7 @@ public class AggregateReportingJobHandler { // TODO(b/298330312): Change to defined error codes ErrorLogUtil.e( e, - AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ERROR_CODE_UNSPECIFIED, + AD_SERVICES_ERROR_REPORTED__ERROR_CODE__MEASUREMENT_REPORTING_PARSING_ERROR, AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__MEASUREMENT); if (mFlags.getMeasurementEnableReportDeletionOnUnrecoverableException()) { // Unrecoverable state - delete the report. @@ -324,7 +327,7 @@ public class AggregateReportingJobHandler { // TODO(b/298330312): Change to defined error codes ErrorLogUtil.e( e, - AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ERROR_CODE_UNSPECIFIED, + AD_SERVICES_ERROR_REPORTED__ERROR_CODE__MEASUREMENT_REPORTING_ENCRYPTION_ERROR, AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__MEASUREMENT); if (mFlags.getMeasurementEnableReportingJobsThrowCryptoException() && ThreadLocalRandom.current().nextFloat() @@ -338,7 +341,7 @@ public class AggregateReportingJobHandler { // TODO(b/298330312): Change to defined error codes ErrorLogUtil.e( e, - AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ERROR_CODE_UNSPECIFIED, + AD_SERVICES_ERROR_REPORTED__ERROR_CODE__MEASUREMENT_REPORTING_UNKNOWN_ERROR, AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__MEASUREMENT); if (mFlags.getMeasurementEnableReportingJobsThrowUnaccountedException() && ThreadLocalRandom.current().nextFloat() @@ -371,8 +374,7 @@ public class AggregateReportingJobHandler { .setTriggerDebugKey(aggregateReport.getTriggerDebugKey()) .setAggregationCoordinatorOrigin(aggregateReport.getAggregationCoordinatorOrigin()) .setDebugMode( - mIsDebugInstance - && aggregateReport.getSourceDebugKey() != null + aggregateReport.getSourceDebugKey() != null && aggregateReport.getTriggerDebugKey() != null ? "enabled" : null) diff --git a/adservices/service-core/java/com/android/adservices/service/measurement/reporting/DebugReportApi.java b/adservices/service-core/java/com/android/adservices/service/measurement/reporting/DebugReportApi.java index c4a6d7201e..778570c249 100644 --- a/adservices/service-core/java/com/android/adservices/service/measurement/reporting/DebugReportApi.java +++ b/adservices/service-core/java/com/android/adservices/service/measurement/reporting/DebugReportApi.java @@ -80,6 +80,7 @@ public class DebugReportApi { String TRIGGER_UNKNOWN_ERROR = "trigger-unknown-error"; String TRIGGER_AGGREGATE_STORAGE_LIMIT = "trigger-aggregate-storage-limit"; String TRIGGER_AGGREGATE_EXCESSIVE_REPORTS = "trigger-aggregate-excessive-reports"; + String TRIGGER_EVENT_REPORT_WINDOW_NOT_STARTED = "trigger-event-report-window-not-started"; } /** Defines different verbose debug report body parameters. */ diff --git a/adservices/service-core/java/com/android/adservices/service/measurement/reporting/DebugReportingJobHandler.java b/adservices/service-core/java/com/android/adservices/service/measurement/reporting/DebugReportingJobHandler.java index 0650f67e90..4391b37254 100644 --- a/adservices/service-core/java/com/android/adservices/service/measurement/reporting/DebugReportingJobHandler.java +++ b/adservices/service-core/java/com/android/adservices/service/measurement/reporting/DebugReportingJobHandler.java @@ -16,7 +16,9 @@ package com.android.adservices.service.measurement.reporting; -import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ERROR_CODE_UNSPECIFIED; +import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__MEASUREMENT_REPORTING_NETWORK_ERROR; +import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__MEASUREMENT_REPORTING_PARSING_ERROR; +import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__MEASUREMENT_REPORTING_UNKNOWN_ERROR; import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__MEASUREMENT; import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_MESUREMENT_REPORTS_UPLOADED; @@ -184,7 +186,7 @@ public class DebugReportingJobHandler { .d(e, "Network error occurred when attempting to deliver debug report."); ErrorLogUtil.e( e, - AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ERROR_CODE_UNSPECIFIED, + AD_SERVICES_ERROR_REPORTED__ERROR_CODE__MEASUREMENT_REPORTING_NETWORK_ERROR, AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__MEASUREMENT); reportingStatus.setFailureStatus(ReportingStatus.FailureStatus.NETWORK); // TODO(b/298330312): Change to defined error codes @@ -195,7 +197,7 @@ public class DebugReportingJobHandler { // TODO(b/298330312): Change to defined error codes ErrorLogUtil.e( e, - AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ERROR_CODE_UNSPECIFIED, + AD_SERVICES_ERROR_REPORTED__ERROR_CODE__MEASUREMENT_REPORTING_PARSING_ERROR, AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__MEASUREMENT); reportingStatus.setFailureStatus(ReportingStatus.FailureStatus.SERIALIZATION_ERROR); if (mFlags.getMeasurementEnableReportDeletionOnUnrecoverableException()) { @@ -216,7 +218,7 @@ public class DebugReportingJobHandler { // TODO(b/298330312): Change to defined error codes ErrorLogUtil.e( e, - AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ERROR_CODE_UNSPECIFIED, + AD_SERVICES_ERROR_REPORTED__ERROR_CODE__MEASUREMENT_REPORTING_UNKNOWN_ERROR, AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__MEASUREMENT); reportingStatus.setFailureStatus(ReportingStatus.FailureStatus.UNKNOWN); if (mFlags.getMeasurementEnableReportingJobsThrowUnaccountedException() diff --git a/adservices/service-core/java/com/android/adservices/service/measurement/reporting/EventReportWindowCalcDelegate.java b/adservices/service-core/java/com/android/adservices/service/measurement/reporting/EventReportWindowCalcDelegate.java index 9d7564c43c..93f7913854 100644 --- a/adservices/service-core/java/com/android/adservices/service/measurement/reporting/EventReportWindowCalcDelegate.java +++ b/adservices/service-core/java/com/android/adservices/service/measurement/reporting/EventReportWindowCalcDelegate.java @@ -54,36 +54,42 @@ public class EventReportWindowCalcDelegate { } /** - * Max reports count based on conversion destination type and installation state. + * Max reports count given the Source object. * - * @param isInstallCase is app installed + * @param source the Source object * @return maximum number of reports allowed */ - public int getMaxReportCount(@NonNull Source source, boolean isInstallCase) { + public int getMaxReportCount(Source source) { + return getMaxReportCount(source, source.isInstallDetectionEnabled()); + } + + /** + * Max reports count based on conversion destination type. + * + * @param source the Source object + * @param destinationType destination type + * @return maximum number of reports allowed + */ + public int getMaxReportCount(@NonNull Source source, @EventSurfaceType int destinationType) { + return getMaxReportCount(source, isInstallCase(source, destinationType)); + } + + private int getMaxReportCount(@NonNull Source source, boolean isInstallCase) { // TODO(b/290101531): Cleanup flags if (mFlags.getMeasurementFlexLiteApiEnabled() && source.getMaxEventLevelReports() != null) { return source.getMaxEventLevelReports(); } - if (source.getSourceType() == Source.SourceType.EVENT - && mFlags.getMeasurementEnableVtcConfigurableMaxEventReports()) { - // Max VTC event reports are configurable - int configuredMaxReports = mFlags.getMeasurementVtcConfigurableMaxEventReportsCount(); + + if (source.getSourceType() == Source.SourceType.EVENT) { // Additional report essentially for first open + 1 post install conversion. If there // is already more than 1 report allowed, no need to have that additional report. - if (isInstallCase && configuredMaxReports == PrivacyParams.EVENT_SOURCE_MAX_REPORTS) { + if (isInstallCase && !source.hasWebDestinations() && isDefaultConfiguredVtc()) { return PrivacyParams.INSTALL_ATTR_EVENT_SOURCE_MAX_REPORTS; } - return configuredMaxReports; + return mFlags.getMeasurementVtcConfigurableMaxEventReportsCount(); } - if (isInstallCase) { - return source.getSourceType() == Source.SourceType.EVENT - ? PrivacyParams.INSTALL_ATTR_EVENT_SOURCE_MAX_REPORTS - : PrivacyParams.INSTALL_ATTR_NAVIGATION_SOURCE_MAX_REPORTS; - } - return source.getSourceType() == Source.SourceType.EVENT - ? PrivacyParams.EVENT_SOURCE_MAX_REPORTS - : PrivacyParams.NAVIGATION_SOURCE_MAX_REPORTS; + return PrivacyParams.NAVIGATION_SOURCE_MAX_REPORTS; } /** @@ -100,18 +106,14 @@ public class EventReportWindowCalcDelegate { // Cases where source could have both web and app destinations, there if the trigger // destination is an app, and it was installed, then installState should be considered true. - boolean isAppInstalled = isAppInstalled(source, destinationType); - List<Pair<Long, Long>> earlyReportingWindows = - getEarlyReportingWindows(source, isAppInstalled); - for (Pair<Long, Long> window : earlyReportingWindows) { + List<Pair<Long, Long>> reportingWindows = + getEffectiveReportingWindows(source, isInstallCase(source, destinationType)); + for (Pair<Long, Long> window : reportingWindows) { if (isWithinWindow(triggerTime, window)) { return window.second + mFlags.getMeasurementMinEventReportDelayMillis(); } } - Pair<Long, Long> finalWindow = getFinalReportingWindow(source, earlyReportingWindows); - if (isWithinWindow(triggerTime, finalWindow)) { - return finalWindow.second + mFlags.getMeasurementMinEventReportDelayMillis(); - } + return -1; } @@ -120,45 +122,60 @@ public class EventReportWindowCalcDelegate { } /** + * Enum shows trigger time and source window time relationship. It is used to generate different + * verbose debug reports. + */ + public enum MomentPlacement { + BEFORE, + AFTER, + WITHIN; + } + + /** + * @param source source for which the window is calculated + * @param triggerTime time for the trigger + * @param destinationType trigger destination type + * @return how trigger time falls in source windows + */ + public MomentPlacement fallsWithinWindow( + @NonNull Source source, long triggerTime, @EventSurfaceType int destinationType) { + List<Pair<Long, Long>> reportingWindows = + getEffectiveReportingWindows(source, isInstallCase(source, destinationType)); + if (triggerTime < reportingWindows.get(0).first) { + return MomentPlacement.BEFORE; + } + if (triggerTime >= reportingWindows.get(reportingWindows.size() - 1).second) { + return MomentPlacement.AFTER; + } + return MomentPlacement.WITHIN; + } + + /** * Return reporting time by index for noising based on the index * * @param windowIndex index of the reporting window for which * @return reporting time in milliseconds */ public long getReportingTimeForNoising( - @NonNull Source source, int windowIndex, boolean isInstallCase) { - List<Pair<Long, Long>> earlyWindows = getEarlyReportingWindows(source, isInstallCase); - Pair<Long, Long> finalWindow = getFinalReportingWindow(source, earlyWindows); - return windowIndex < earlyWindows.size() - ? earlyWindows.get(windowIndex).second + @NonNull Source source, int windowIndex) { + List<Pair<Long, Long>> reportingWindows = getEffectiveReportingWindows( + source, source.isInstallDetectionEnabled()); + Pair<Long, Long> finalWindow = reportingWindows.get(reportingWindows.size() - 1); + // TODO: (b/288646239) remove this check, confirming noising indexing accuracy. + return windowIndex < reportingWindows.size() + ? reportingWindows.get(windowIndex).second + mFlags.getMeasurementMinEventReportDelayMillis() : finalWindow.second + mFlags.getMeasurementMinEventReportDelayMillis(); } - private Pair<Long, Long> getFinalReportingWindow( - Source source, List<Pair<Long, Long>> earlyWindows) { - if (mFlags.getMeasurementFlexLiteApiEnabled() && source.hasManualEventReportWindows()) { - List<Pair<Long, Long>> windowList = source.parsedProcessedEventReportWindows(); - return windowList.get(windowList.size() - 1); - } - long secondToLastWindowEnd = - !earlyWindows.isEmpty() ? earlyWindows.get(earlyWindows.size() - 1).second : 0; - if (source.getProcessedEventReportWindow() != null) { - return new Pair<>(secondToLastWindowEnd, source.getProcessedEventReportWindow()); - } - return new Pair<>(secondToLastWindowEnd, source.getExpiryTime()); - } - /** - * Returns effective, i.e. the ones that occur before {@link - * Source#getProcessedEventReportWindow()}, event reporting windows count for noising cases. + * Returns effective, that is, the ones that occur before {@link + * Source#getEffectiveEventReportWindow()}, event reporting windows count for noising cases. * * @param source source for which the count is requested - * @param isInstallCase true of cool down window was specified */ - public int getReportingWindowCountForNoising(@NonNull Source source, boolean isInstallCase) { - // Early Count + lastWindow - return getEarlyReportingWindows(source, isInstallCase).size() + 1; + public int getReportingWindowCountForNoising(@NonNull Source source) { + return getEffectiveReportingWindows(source, source.isInstallDetectionEnabled()).size(); } /** @@ -213,47 +230,53 @@ public class EventReportWindowCalcDelegate { return -1L; } - private boolean isAppInstalled(Source source, int destinationType) { + private static boolean isInstallCase(Source source, @EventSurfaceType int destinationType) { return destinationType == EventSurfaceType.APP && source.isInstallAttributed(); } /** * If the flag is enabled and the specified report windows are valid, picks from flag controlled - * configurable early reporting windows. Otherwise, falls back to the statical {@link - * com.android.adservices.service.measurement.PrivacyParams} values. It curtails the windows - * that occur after {@link Source#getProcessedEventReportWindow()} because they would - * effectively be unusable. + * configurable early reporting windows. Otherwise, falls back to the values provided in + * {@code getDefaultEarlyReportingWindowEnds}, which can have install-related custom behaviour. + * It curtails the windows that occur after {@link Source#getEffectiveEventReportWindow()} + * because they would effectively be unusable. */ - private List<Pair<Long, Long>> getEarlyReportingWindows(Source source, boolean installState) { + private List<Pair<Long, Long>> getEffectiveReportingWindows(Source source, + boolean installState) { // TODO(b/290221611) Remove early reporting windows from code, only use them for flags. if (mFlags.getMeasurementFlexLiteApiEnabled() && source.hasManualEventReportWindows()) { - List<Pair<Long, Long>> windows = source.parsedProcessedEventReportWindows(); - // Select early windows only i.e. skip the last element - return windows.subList(0, windows.size() - 1); + return source.parsedProcessedEventReportWindows(); } - List<Long> earlyWindows; - List<Long> defaultEarlyWindows = - getDefaultEarlyReportingWindows(source.getSourceType(), installState); - earlyWindows = - getConfiguredOrDefaultEarlyReportingWindows( - source.getSourceType(), defaultEarlyWindows, true); + List<Long> defaultEarlyWindowEnds = + getDefaultEarlyReportingWindowEnds( + source.getSourceType(), + installState && !source.hasWebDestinations()); + List<Long> earlyWindowEnds = + getConfiguredOrDefaultEarlyReportingWindowEnds( + source.getSourceType(), defaultEarlyWindowEnds); // Add source event time to windows - earlyWindows = - earlyWindows.stream() + earlyWindowEnds = + earlyWindowEnds.stream() .map((x) -> source.getEventTime() + x) .collect(Collectors.toList()); List<Pair<Long, Long>> windowList = new ArrayList<>(); - long windowStart = 0; + long windowStart = 0L; Pair<Long, Long> finalWindow = - getFinalReportingWindow(source, createStartEndWindow(earlyWindows)); - for (long windowEnd : earlyWindows) { - if (finalWindow.second <= windowEnd) { - continue; + getFinalReportingWindow(source, earlyWindowEnds); + + for (long windowEnd : earlyWindowEnds) { + // Start time of `finalWindow` is either 0 or one of `earlyWindowEnds` times; stop + // iterating if we see it, and add `finalWindow`. + if (windowStart == finalWindow.first) { + break; } - windowList.add(new Pair<>(windowStart, windowEnd)); + windowList.add(Pair.create(windowStart, windowEnd)); windowStart = windowEnd; } + + windowList.add(finalWindow); + return ImmutableList.copyOf(windowList); } @@ -261,13 +284,13 @@ public class EventReportWindowCalcDelegate { * Returns the default early reporting windows * * @param sourceType Source's Type - * @param installState Install State of the source + * @param installAttributionEnabled whether windows for install attribution should be provided * @return a list of windows */ - public static List<Long> getDefaultEarlyReportingWindows( - Source.SourceType sourceType, boolean installState) { + public static List<Long> getDefaultEarlyReportingWindowEnds( + Source.SourceType sourceType, boolean installAttributionEnabled) { long[] earlyWindows; - if (installState) { + if (installAttributionEnabled) { earlyWindows = sourceType == Source.SourceType.EVENT ? INSTALL_ATTR_EVENT_EARLY_REPORTING_WINDOW_MILLISECONDS @@ -281,53 +304,34 @@ public class EventReportWindowCalcDelegate { return asList(earlyWindows); } - private List<Pair<Long, Long>> createStartEndWindow(List<Long> windowEnds) { - List<Pair<Long, Long>> windows = new ArrayList<>(); - long start = 0; - for (Long end : windowEnds) { - windows.add(new Pair<>(start, end)); - start = end; - } - return windows; - } - /** * Returns default or configured (via flag) early reporting windows for the SourceType * * @param sourceType Source's Type * @param defaultEarlyWindows default value for early windows - * @param checkEnableFlag set true if configurable window flag should be checked * @return list of windows */ - public List<Long> getConfiguredOrDefaultEarlyReportingWindows( - Source.SourceType sourceType, List<Long> defaultEarlyWindows, boolean checkEnableFlag) { - // TODO(b/290101531): Cleanup flags - if (checkEnableFlag && !mFlags.getMeasurementEnableConfigurableEventReportingWindows()) { - return defaultEarlyWindows; + public List<Long> getConfiguredOrDefaultEarlyReportingWindowEnds( + Source.SourceType sourceType, List<Long> defaultEarlyWindowEnds) { + // `defaultEarlyWindowEnds` may contain custom install-related logic, which we only apply if + // the configurable report windows (and max reports) are in their default state. Without + // this check, we may construct default-value report windows without the custom + // install-related logic applied. + if ((sourceType == Source.SourceType.EVENT && isDefaultConfiguredVtc()) + || (sourceType == Source.SourceType.NAVIGATION && isDefaultConfiguredCtc())) { + return defaultEarlyWindowEnds; } String earlyReportingWindowsString = pickEarlyReportingWindowsConfig(mFlags, sourceType); - if (earlyReportingWindowsString == null) { - LoggerFactory.getMeasurementLogger() - .d("Invalid configurable early reporting windows; null"); - return defaultEarlyWindows; - } - if (earlyReportingWindowsString.isEmpty()) { // No early reporting windows specified. It needs to be handled separately because - // splitting an empty string results into an array containing a single element, - // i.e. "". We want to handle it as an array having no element. - - if (Source.SourceType.EVENT.equals(sourceType)) { - // We need to add a reporting window at 2d for post-install case. Non-install case - // has no early reporting window by default. - return defaultEarlyWindows; - } + // splitting an empty string results in an array containing a single empty string. We + // want to handle it as an empty array. return Collections.emptyList(); } - ImmutableList.Builder<Long> earlyWindows = new ImmutableList.Builder<>(); + ImmutableList.Builder<Long> earlyWindowEnds = new ImmutableList.Builder<>(); String[] split = earlyReportingWindowsString.split(EARLY_REPORTING_WINDOWS_CONFIG_DELIMITER); if (split.length > MAX_CONFIGURABLE_EVENT_REPORT_EARLY_REPORTING_WINDOWS) { @@ -335,22 +339,54 @@ public class EventReportWindowCalcDelegate { .d( "Invalid configurable early reporting window; more than allowed size: " + MAX_CONFIGURABLE_EVENT_REPORT_EARLY_REPORTING_WINDOWS); - return defaultEarlyWindows; + return defaultEarlyWindowEnds; } - for (String window : split) { + for (String windowEnd : split) { try { - earlyWindows.add(TimeUnit.SECONDS.toMillis(Long.parseLong(window))); + earlyWindowEnds.add(TimeUnit.SECONDS.toMillis(Long.parseLong(windowEnd))); } catch (NumberFormatException e) { LoggerFactory.getMeasurementLogger() .d(e, "Configurable early reporting window parsing failed."); - return defaultEarlyWindows; + return defaultEarlyWindowEnds; + } + } + return earlyWindowEnds.build(); + } + + private Pair<Long, Long> getFinalReportingWindow( + Source source, List<Long> earlyWindowEnds) { + // The latest end-time we can associate with a report for this source + long effectiveExpiry = Math.min( + source.getEffectiveEventReportWindow(), source.getExpiryTime()); + // Find the latest end-time that can start a window ending at effectiveExpiry + for (int i = earlyWindowEnds.size() - 1; i >= 0; i--) { + long windowEnd = earlyWindowEnds.get(i); + if (windowEnd < effectiveExpiry) { + return Pair.create(windowEnd, effectiveExpiry); } } - return earlyWindows.build(); + return Pair.create(0L, effectiveExpiry); + } + + /** Indicates whether VTC report windows and max reports are default configured, which can + * affect custom install-related attribution. + */ + public boolean isDefaultConfiguredVtc() { + return mFlags.getMeasurementEventReportsVtcEarlyReportingWindows().isEmpty() + && mFlags.getMeasurementVtcConfigurableMaxEventReportsCount() == 1; + } + + /** Indicates whether CTC report windows are default configured, which can affect custom + * install-related attribution. + */ + private boolean isDefaultConfiguredCtc() { + return mFlags.getMeasurementEventReportsCtcEarlyReportingWindows().equals( + Flags.MEASUREMENT_EVENT_REPORTS_CTC_EARLY_REPORTING_WINDOWS); } - private String pickEarlyReportingWindowsConfig(Flags flags, Source.SourceType sourceType) { + private static String pickEarlyReportingWindowsConfig(Flags flags, + Source.SourceType sourceType) { return sourceType == Source.SourceType.EVENT ? flags.getMeasurementEventReportsVtcEarlyReportingWindows() : flags.getMeasurementEventReportsCtcEarlyReportingWindows(); diff --git a/adservices/service-core/java/com/android/adservices/service/measurement/reporting/EventReportingJobHandler.java b/adservices/service-core/java/com/android/adservices/service/measurement/reporting/EventReportingJobHandler.java index f5042f3afd..c67f0acd67 100644 --- a/adservices/service-core/java/com/android/adservices/service/measurement/reporting/EventReportingJobHandler.java +++ b/adservices/service-core/java/com/android/adservices/service/measurement/reporting/EventReportingJobHandler.java @@ -16,7 +16,9 @@ package com.android.adservices.service.measurement.reporting; -import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ERROR_CODE_UNSPECIFIED; +import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__MEASUREMENT_REPORTING_NETWORK_ERROR; +import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__MEASUREMENT_REPORTING_PARSING_ERROR; +import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__MEASUREMENT_REPORTING_UNKNOWN_ERROR; import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__MEASUREMENT; import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_MESUREMENT_REPORTS_UPLOADED; @@ -270,7 +272,7 @@ public class EventReportingJobHandler { // TODO(b/298330312): Change to defined error codes ErrorLogUtil.e( e, - AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ERROR_CODE_UNSPECIFIED, + AD_SERVICES_ERROR_REPORTED__ERROR_CODE__MEASUREMENT_REPORTING_NETWORK_ERROR, AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__MEASUREMENT); return AdServicesStatusUtils.STATUS_IO_ERROR; } catch (JSONException e) { @@ -281,7 +283,7 @@ public class EventReportingJobHandler { // TODO(b/298330312): Change to defined error codes ErrorLogUtil.e( e, - AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ERROR_CODE_UNSPECIFIED, + AD_SERVICES_ERROR_REPORTED__ERROR_CODE__MEASUREMENT_REPORTING_PARSING_ERROR, AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__MEASUREMENT); if (mFlags.getMeasurementEnableReportDeletionOnUnrecoverableException()) { // Unrecoverable state - delete the report. @@ -305,7 +307,7 @@ public class EventReportingJobHandler { reportingStatus.setFailureStatus(ReportingStatus.FailureStatus.UNKNOWN); ErrorLogUtil.e( e, - AD_SERVICES_ERROR_REPORTED__ERROR_CODE__ERROR_CODE_UNSPECIFIED, + AD_SERVICES_ERROR_REPORTED__ERROR_CODE__MEASUREMENT_REPORTING_UNKNOWN_ERROR, AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__MEASUREMENT); if (mFlags.getMeasurementEnableReportingJobsThrowUnaccountedException() && ThreadLocalRandom.current().nextFloat() diff --git a/adservices/service-core/java/com/android/adservices/service/measurement/reporting/ReportingStatus.java b/adservices/service-core/java/com/android/adservices/service/measurement/reporting/ReportingStatus.java index 8e7b1780fe..4e83edb8c9 100644 --- a/adservices/service-core/java/com/android/adservices/service/measurement/reporting/ReportingStatus.java +++ b/adservices/service-core/java/com/android/adservices/service/measurement/reporting/ReportingStatus.java @@ -52,7 +52,9 @@ public class ReportingStatus { VERBOSE_DEBUG_TRIGGER_UNKNOWN_ERROR(26), VERBOSE_DEBUG_TRIGGER_AGGREGATE_STORAGE_LIMIT(27), VERBOSE_DEBUG_TRIGGER_AGGREGATE_EXCESSIVE_REPORTS(28), - VERBOSE_DEBUG_UNKNOWN(29); + VERBOSE_DEBUG_TRIGGER_EVENT_REPORT_WINDOW_NOT_STARTED(29), + VERBOSE_DEBUG_UNKNOWN(9999); + private final int mValue; ReportType(int value) { @@ -202,6 +204,10 @@ public class ReportingStatus { mReportType = ReportType.VERBOSE_DEBUG_TRIGGER_AGGREGATE_STORAGE_LIMIT; } else if (reportType.equals(DebugReportApi.Type.TRIGGER_AGGREGATE_EXCESSIVE_REPORTS)) { mReportType = ReportType.VERBOSE_DEBUG_TRIGGER_AGGREGATE_EXCESSIVE_REPORTS; + } else if (reportType.equals(DebugReportApi.Type.TRIGGER_EVENT_REPORT_WINDOW_NOT_STARTED)) { + mReportType = ReportType.VERBOSE_DEBUG_TRIGGER_EVENT_REPORT_WINDOW_NOT_STARTED; + } else { + mReportType = ReportType.VERBOSE_DEBUG_UNKNOWN; } } |