• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.adservices.service.measurement.noising;
18 
19 import com.android.adservices.service.measurement.ReportSpec;
20 import com.android.internal.annotations.VisibleForTesting;
21 
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Random;
26 
27 /**
28  * Util class for generating impression noise
29  */
30 public final class ImpressionNoiseUtil {
31 
32     /**
33      * This is used in the scenario where both app and web destinations are available with the
34      * {@link com.android.adservices.service.measurement.Source} and the source is of {@link
35      * com.android.adservices.service.measurement.Source.SourceType#EVENT} type and post-install
36      * detection is enabled (cooldown window being available). It's a special case because in this
37      * condition an extra early window is added only if install detection is enabled (install
38      * cool-down window is available) and only app conversions are relevant in that window.
39      *
40      * <p>Reading guide - The outermost array signifies different states of reporting - one of them
41      * will be picked at a time. The middle array holds reports in 1st and 2nd window, so there will
42      * be either 0 elements (no conversions in either window), 1 element (a conversion report in one
43      * of the windows) and 2 elements (conversions in both windows). The innermost array represents
44      * a single report. 3 elements in the innermost array are trigger metadata (0 - trigger1 or 1 -
45      * trigger2), window index (0 - window1, 1 - window2) and destination type (0 - app or 1 - web).
46      *
47      * <p>E.g. The element at index 5 is {{0, 1, 0}, {0, 1, 0}}, it means 2 conversions with trigger
48      * metadata as 0 in window2 (1) of app destination type(0).
49      */
50     public static final int[][][] DUAL_DESTINATION_POST_INSTALL_FAKE_REPORT_CONFIG =
51             new int[][][] {
52                 // window1 - no conversion, window 2 - no conversion
53                 {},
54                 // window1 - no conversion, window 2 - 1 conversion with metadata 0
55                 {{0, 1, 0}},
56                 {{0, 1, 1}},
57                 // window1 - no conversion, window 2 - 1 conversion with metadata 1
58                 {{1, 1, 0}},
59                 {{1, 1, 1}},
60                 // window1 - no conversion, window 2 - 2 conversions with metadata 0 and 0
61                 {{0, 1, 0}, {0, 1, 0}},
62                 {{0, 1, 0}, {0, 1, 1}},
63                 // window1 - no conversion, window 2 - 2 conversions with metadata 0 and 1
64                 {{0, 1, 0}, {1, 1, 0}},
65                 {{0, 1, 0}, {1, 1, 1}},
66                 {{0, 1, 1}, {1, 1, 0}},
67                 // window1 - no conversion, window 2 - 2 conversions with metadata 1 and 1
68                 {{1, 1, 0}, {1, 1, 0}},
69                 {{1, 1, 0}, {1, 1, 1}},
70                 // window1 - 1 app conversion with metadata 0, window 2 - no conversion
71                 {{0, 0, 0}},
72                 // window1 - 1 app conversion with metadata 1, window 2 - no conversion
73                 {{1, 0, 0}},
74                 // window1 - 2 conversions with metadata 0 and 0, window 2 - no conversion
75                 {{0, 0, 0}, {0, 0, 0}},
76                 // window1 - 2 app conversions with metadata 0 and 1, window 2 - no conversion
77                 {{0, 0, 0}, {1, 0, 0}},
78                 // window1 - 2 app conversions with metadata 1 and 1, window 2 - no conversion
79                 {{1, 0, 0}, {1, 0, 0}},
80                 // window1 - 1 app conversion with metadata 0, window 2 - 1 conversion with
81                 // metadata 0
82                 {{0, 0, 0}, {0, 1, 0}},
83                 {{0, 0, 0}, {0, 1, 1}},
84                 // window1 - 1 app conversion with metadata 0, window 2 - 1 conversion with
85                 // metadata 1
86                 {{0, 0, 0}, {1, 1, 0}},
87                 {{0, 0, 0}, {1, 1, 1}},
88                 // window1 - 1 app conversion with metadata 1, window 2 - 1 conversions with
89                 // metadata 0
90                 {{1, 0, 0}, {0, 1, 0}},
91                 {{1, 0, 0}, {0, 1, 1}},
92                 // window1 - 1 app conversion with metadata 1, window 2 - 1 conversions with
93                 // metadata 1
94                 {{1, 0, 0}, {1, 1, 0}},
95                 {{1, 0, 0}, {1, 1, 1}}
96             };
97 
ImpressionNoiseUtil()98     private ImpressionNoiseUtil() {}
99 
100     /**
101      * Randomly generate report configs based on noise params
102      *
103      * @param noiseParams Noise parameters to use for state generation
104      * @param rand random number generator
105      * @return list of reporting configs
106      */
selectRandomStateAndGenerateReportConfigs( ImpressionNoiseParams noiseParams, Random rand)107     public static List<int[]> selectRandomStateAndGenerateReportConfigs(
108             ImpressionNoiseParams noiseParams, Random rand) {
109         // Get total possible combinations
110         int numCombinations =
111                 Combinatorics.getNumberOfStarsAndBarsSequences(
112                         /*numStars=*/ noiseParams.getReportCount(),
113                         /*numBars=*/ noiseParams.getTriggerDataCardinality()
114                                 * noiseParams.getReportingWindowCount()
115                                 * noiseParams.getDestinationTypeMultiplier());
116         // Choose a sequence index
117         int sequenceIndex = rand.nextInt(numCombinations);
118         return getReportConfigsForSequenceIndex(noiseParams, sequenceIndex);
119     }
120 
121     @VisibleForTesting
getReportConfigsForSequenceIndex( ImpressionNoiseParams noiseParams, int sequenceIndex)122     static List<int[]> getReportConfigsForSequenceIndex(
123             ImpressionNoiseParams noiseParams, int sequenceIndex) {
124         List<int[]> reportConfigs = new ArrayList<>();
125         // Get the configuration for the sequenceIndex
126         int[] starIndices = Combinatorics.getStarIndices(
127                 /*numStars=*/noiseParams.getReportCount(),
128                 /*sequenceIndex=*/sequenceIndex);
129         int[] barsPrecedingEachStar = Combinatorics.getBarsPrecedingEachStar(starIndices);
130         // Generate fake reports
131         // Stars: number of reports
132         // Bars: (Number of windows) * (Trigger data cardinality) * (Destination multiplier)
133         for (int numBars : barsPrecedingEachStar) {
134             if (numBars == 0) {
135                 continue;
136             }
137 
138             // Extract bits for trigger data, destination type and windowIndex from encoded numBars
139             int[] reportConfig = createReportingConfig(numBars, noiseParams);
140             reportConfigs.add(reportConfig);
141         }
142         return reportConfigs;
143     }
144 
145     /**
146      * Extract bits for trigger data, destination type and windowIndex from encoded numBars.
147      *
148      * @param numBars data encoding triggerData, destinationType and window index
149      * @param noiseParams noise params
150      * @return array having triggerData, destinationType and windowIndex
151      */
createReportingConfig(int numBars, ImpressionNoiseParams noiseParams)152     private static int[] createReportingConfig(int numBars, ImpressionNoiseParams noiseParams) {
153         int triggerData = (numBars - 1) % noiseParams.getTriggerDataCardinality();
154         int remainingData = (numBars - 1) / noiseParams.getTriggerDataCardinality();
155 
156         int reportingWindowIndex = remainingData % noiseParams.getReportingWindowCount();
157         int destinationTypeIndex = remainingData / noiseParams.getReportingWindowCount();
158         return new int[] {triggerData, reportingWindowIndex, destinationTypeIndex};
159     }
160 
161     /**
162      * Randomly generate report configs based on noise params
163      *
164      * @param reportSpec Report spec to use for state generation
165      * @param destinationMultiplier destination multiplier
166      * @param rand random number generator
167      * @return list of reporting configs
168      */
selectFlexEventReportRandomStateAndGenerateReportConfigs( ReportSpec reportSpec, int destinationMultiplier, Random rand)169     public static List<int[]> selectFlexEventReportRandomStateAndGenerateReportConfigs(
170             ReportSpec reportSpec, int destinationMultiplier, Random rand) {
171 
172         int[][] params = reportSpec.getPrivacyParamsForComputation();
173         for (int i = 0; i < params[1].length; i++) {
174             params[1][i] *= destinationMultiplier;
175         }
176         int numStates = Combinatorics.getNumStatesFlexAPI(params[0][0], params[1], params[2]);
177         int sequenceIndex = rand.nextInt(numStates);
178         List<Combinatorics.AtomReportState> rawFakeReports =
179                 Combinatorics.getReportSetBasedOnRank(
180                         params[0][0], params[1], params[2], sequenceIndex, new HashMap<>());
181         List<int[]> fakeReportConfigs = new ArrayList<>();
182         for (Combinatorics.AtomReportState rawFakeReport : rawFakeReports) {
183             int[] fakeReportConfig = new int[3];
184             fakeReportConfig[0] = rawFakeReport.getTriggerDataType();
185             fakeReportConfig[1] = (rawFakeReport.getWindowIndex()) / destinationMultiplier;
186             fakeReportConfig[2] = (rawFakeReport.getWindowIndex()) % destinationMultiplier;
187             fakeReportConfigs.add(fakeReportConfig);
188         }
189         return fakeReportConfigs;
190     }
191 }
192