• 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;
18 
19 import static com.android.adservices.service.measurement.AttributionConfig.AttributionConfigContract.END;
20 import static com.android.adservices.service.measurement.AttributionConfig.AttributionConfigContract.EXPIRY;
21 import static com.android.adservices.service.measurement.AttributionConfig.AttributionConfigContract.FILTER_DATA;
22 import static com.android.adservices.service.measurement.AttributionConfig.AttributionConfigContract.POST_INSTALL_EXCLUSIVITY_WINDOW;
23 import static com.android.adservices.service.measurement.AttributionConfig.AttributionConfigContract.PRIORITY;
24 import static com.android.adservices.service.measurement.AttributionConfig.AttributionConfigContract.SOURCE_EXPIRY_OVERRIDE;
25 import static com.android.adservices.service.measurement.AttributionConfig.AttributionConfigContract.SOURCE_FILTERS;
26 import static com.android.adservices.service.measurement.AttributionConfig.AttributionConfigContract.SOURCE_NETWORK;
27 import static com.android.adservices.service.measurement.AttributionConfig.AttributionConfigContract.SOURCE_NOT_FILTERS;
28 import static com.android.adservices.service.measurement.AttributionConfig.AttributionConfigContract.SOURCE_PRIORITY_RANGE;
29 import static com.android.adservices.service.measurement.AttributionConfig.AttributionConfigContract.START;
30 import static com.android.adservices.service.measurement.PrivacyParams.MAX_REPORTING_REGISTER_SOURCE_EXPIRATION_IN_SECONDS;
31 import static com.android.adservices.service.measurement.PrivacyParams.MIN_REPORTING_REGISTER_SOURCE_EXPIRATION_IN_SECONDS;
32 
33 import android.annotation.NonNull;
34 import android.annotation.Nullable;
35 import android.util.Pair;
36 
37 import com.android.adservices.LogUtil;
38 import com.android.adservices.service.measurement.util.Filter;
39 import com.android.adservices.service.measurement.util.MathUtils;
40 
41 import org.json.JSONArray;
42 import org.json.JSONException;
43 import org.json.JSONObject;
44 
45 import java.util.List;
46 import java.util.Objects;
47 
48 /** POJO for AttributionConfig. */
49 public class AttributionConfig {
50 
51     @NonNull private final String mSourceAdtech;
52     @Nullable private final Pair<Long, Long> mSourcePriorityRange;
53     @Nullable private final List<FilterMap> mSourceFilters;
54     @Nullable private final List<FilterMap> mSourceNotFilters;
55     @Nullable private final Long mSourceExpiryOverride;
56     @Nullable private final Long mPriority;
57     @Nullable private final Long mExpiry;
58     @Nullable private final List<FilterMap> mFilterData;
59     @Nullable private final Long mPostInstallExclusivityWindow;
60 
AttributionConfig(@onNull AttributionConfig.Builder builder)61     private AttributionConfig(@NonNull AttributionConfig.Builder builder) {
62         mSourceAdtech = builder.mSourceAdtech;
63         mSourcePriorityRange = builder.mSourcePriorityRange;
64         mSourceFilters = builder.mSourceFilters;
65         mSourceNotFilters = builder.mSourceNotFilters;
66         mSourceExpiryOverride = builder.mSourceExpiryOverride;
67         mPriority = builder.mPriority;
68         mExpiry = builder.mExpiry;
69         mFilterData = builder.mFilterData;
70         mPostInstallExclusivityWindow = builder.mPostInstallExclusivityWindow;
71     }
72 
73     @Override
equals(Object obj)74     public boolean equals(Object obj) {
75         if (!(obj instanceof AttributionConfig)) {
76             return false;
77         }
78         AttributionConfig attributionConfig = (AttributionConfig) obj;
79         return Objects.equals(mSourceAdtech, attributionConfig.mSourceAdtech)
80                 && Objects.equals(mSourcePriorityRange, attributionConfig.mSourcePriorityRange)
81                 && Objects.equals(mSourceFilters, attributionConfig.mSourceFilters)
82                 && Objects.equals(mSourceNotFilters, attributionConfig.mSourceNotFilters)
83                 && Objects.equals(mSourceExpiryOverride, attributionConfig.mSourceExpiryOverride)
84                 && Objects.equals(mPriority, attributionConfig.mPriority)
85                 && Objects.equals(mExpiry, attributionConfig.mExpiry)
86                 && Objects.equals(mFilterData, attributionConfig.mFilterData)
87                 && Objects.equals(
88                         mPostInstallExclusivityWindow,
89                         attributionConfig.mPostInstallExclusivityWindow);
90     }
91 
92     @Override
hashCode()93     public int hashCode() {
94         return Objects.hash(
95                 mSourceAdtech,
96                 mSourcePriorityRange,
97                 mSourceFilters,
98                 mSourceNotFilters,
99                 mSourceExpiryOverride,
100                 mPriority,
101                 mExpiry,
102                 mFilterData,
103                 mPostInstallExclusivityWindow);
104     }
105 
106     /** Returns the source adtech as String. */
107     @NonNull
getSourceAdtech()108     public String getSourceAdtech() {
109         return mSourceAdtech;
110     }
111 
112     /**
113      * Returns source priority range JSONObject as a Pair of Long values. example:
114      * "source_priority_range": { “start”: 100, “end”: 1000 }
115      */
116     @Nullable
getSourcePriorityRange()117     public Pair<Long, Long> getSourcePriorityRange() {
118         return mSourcePriorityRange;
119     }
120 
121     /**
122      * Returns source filter JSONObject as List of FilterMap. example: "source_filters": {
123      * "campaign_type": ["install"], "source_type": ["navigation"] }
124      */
125     @Nullable
getSourceFilters()126     public List<FilterMap> getSourceFilters() {
127         return mSourceFilters;
128     }
129 
130     /**
131      * Returns source not filter JSONObject as List of FilterMap. example: "source_not_filters": {
132      * "campaign_type": ["install"] }
133      */
134     @Nullable
getSourceNotFilters()135     public List<FilterMap> getSourceNotFilters() {
136         return mSourceNotFilters;
137     }
138 
139     /**
140      * Returns source expiry override as long. Source registration time + source expiry override <
141      * trigger time.
142      */
143     @Nullable
getSourceExpiryOverride()144     public Long getSourceExpiryOverride() {
145         return mSourceExpiryOverride;
146     }
147 
148     /** Returns the derived priority of the source as long */
149     @Nullable
getPriority()150     public Long getPriority() {
151         return mPriority;
152     }
153 
154     /**
155      * Returns the derived source expiry in {@link java.util.concurrent.TimeUnit#SECONDS} as long.
156      */
157     @Nullable
getExpiry()158     public Long getExpiry() {
159         return mExpiry;
160     }
161 
162     /**
163      * Returns the derived filter data of the source as List of FilterMap. example: "filter_data": {
164      * "conversion_subdomain": ["electronics.megastore"], "product": ["1234", "234"] }
165      */
166     @Nullable
getFilterData()167     public List<FilterMap> getFilterData() {
168         return mFilterData;
169     }
170 
171     /** Returns the derived post install exclusivity window as long. */
172     @Nullable
getPostInstallExclusivityWindow()173     public Long getPostInstallExclusivityWindow() {
174         return mPostInstallExclusivityWindow;
175     }
176 
177     /**
178      * Serializes the object as JSON. This is consistent with the format that is received in the
179      * response headers as well as stored as is in the database.
180      *
181      * @return serialized JSON object
182      */
183     @Nullable
serializeAsJson()184     public JSONObject serializeAsJson() {
185         try {
186             JSONObject attributionConfig = new JSONObject();
187             attributionConfig.put(SOURCE_NETWORK, mSourceAdtech);
188 
189             if (mSourcePriorityRange != null) {
190                 JSONObject sourcePriorityRange = new JSONObject();
191                 sourcePriorityRange.put(START, mSourcePriorityRange.first);
192                 sourcePriorityRange.put(END, mSourcePriorityRange.second);
193                 attributionConfig.put(SOURCE_PRIORITY_RANGE, sourcePriorityRange);
194             }
195 
196             if (mSourceFilters != null) {
197                 attributionConfig.put(SOURCE_FILTERS, Filter.serializeFilterSet(mSourceFilters));
198             }
199 
200             if (mSourceNotFilters != null) {
201                 attributionConfig.put(
202                         SOURCE_NOT_FILTERS, Filter.serializeFilterSet(mSourceNotFilters));
203             }
204 
205             if (mSourceExpiryOverride != null) {
206                 attributionConfig.put(SOURCE_EXPIRY_OVERRIDE, mSourceExpiryOverride);
207             }
208 
209             if (mPriority != null) {
210                 attributionConfig.put(PRIORITY, mPriority);
211             }
212 
213             if (mExpiry != null) {
214                 attributionConfig.put(EXPIRY, mExpiry);
215             }
216 
217             if (mFilterData != null) {
218                 attributionConfig.put(FILTER_DATA, Filter.serializeFilterSet(mFilterData));
219             }
220 
221             if (mPostInstallExclusivityWindow != null) {
222                 attributionConfig.put(
223                         POST_INSTALL_EXCLUSIVITY_WINDOW, mPostInstallExclusivityWindow);
224             }
225 
226             return attributionConfig;
227         } catch (JSONException e) {
228             LogUtil.d(e, "Serializing attribution config failed");
229             return null;
230         }
231     }
232 
233     /** Builder for {@link AttributionConfig}. */
234     public static final class Builder {
235         private String mSourceAdtech;
236         private Pair<Long, Long> mSourcePriorityRange;
237         private List<FilterMap> mSourceFilters;
238         private List<FilterMap> mSourceNotFilters;
239         private Long mSourceExpiryOverride;
240         private Long mPriority;
241         private Long mExpiry;
242         private List<FilterMap> mFilterData;
243         private Long mPostInstallExclusivityWindow;
244 
Builder()245         public Builder() {}
246 
247         /**
248          * Parses the string serialized json object under an {@link AttributionConfig}.
249          *
250          * @throws JSONException if JSON parsing fails
251          */
Builder(@onNull JSONObject attributionConfigsJson)252         public Builder(@NonNull JSONObject attributionConfigsJson) throws JSONException {
253             if (attributionConfigsJson == null) {
254                 throw new JSONException(
255                         "AttributionConfig.Builder: Empty or null attributionConfigsJson");
256             }
257             if (attributionConfigsJson.isNull(SOURCE_NETWORK)) {
258                 throw new JSONException(
259                         "AttributionConfig.Builder: Required field source_network is not present.");
260             }
261 
262             mSourceAdtech = attributionConfigsJson.getString(SOURCE_NETWORK);
263 
264             if (!attributionConfigsJson.isNull(SOURCE_PRIORITY_RANGE)) {
265                 JSONObject sourcePriorityRangeJson =
266                         attributionConfigsJson.getJSONObject(SOURCE_PRIORITY_RANGE);
267                 mSourcePriorityRange =
268                         new Pair<>(
269                                 sourcePriorityRangeJson.getLong(START),
270                                 sourcePriorityRangeJson.getLong(END));
271             }
272             if (!attributionConfigsJson.isNull(SOURCE_FILTERS)) {
273                 JSONArray filterSet =
274                         Filter.maybeWrapFilters(attributionConfigsJson, SOURCE_FILTERS);
275                 mSourceFilters = Filter.deserializeFilterSet(filterSet);
276             }
277             if (!attributionConfigsJson.isNull(SOURCE_NOT_FILTERS)) {
278                 JSONArray filterSet =
279                         Filter.maybeWrapFilters(attributionConfigsJson, SOURCE_NOT_FILTERS);
280                 mSourceNotFilters = Filter.deserializeFilterSet(filterSet);
281             }
282             if (!attributionConfigsJson.isNull(SOURCE_EXPIRY_OVERRIDE)) {
283                 long override = attributionConfigsJson.getLong(SOURCE_EXPIRY_OVERRIDE);
284                 mSourceExpiryOverride =
285                         MathUtils.extractValidNumberInRange(
286                                 override,
287                                 MIN_REPORTING_REGISTER_SOURCE_EXPIRATION_IN_SECONDS,
288                                 MAX_REPORTING_REGISTER_SOURCE_EXPIRATION_IN_SECONDS);
289             }
290             if (!attributionConfigsJson.isNull(PRIORITY)) {
291                 mPriority = attributionConfigsJson.getLong(PRIORITY);
292             }
293             if (!attributionConfigsJson.isNull(EXPIRY)) {
294                 long expiry = attributionConfigsJson.getLong(EXPIRY);
295                 mExpiry =
296                         MathUtils.extractValidNumberInRange(
297                                 expiry,
298                                 MIN_REPORTING_REGISTER_SOURCE_EXPIRATION_IN_SECONDS,
299                                 MAX_REPORTING_REGISTER_SOURCE_EXPIRATION_IN_SECONDS);
300             }
301             if (!attributionConfigsJson.isNull(FILTER_DATA)) {
302                 JSONArray filterSet = Filter.maybeWrapFilters(attributionConfigsJson, FILTER_DATA);
303                 mFilterData = Filter.deserializeFilterSet(filterSet);
304             }
305             if (!attributionConfigsJson.isNull(POST_INSTALL_EXCLUSIVITY_WINDOW)) {
306                 mPostInstallExclusivityWindow =
307                         attributionConfigsJson.getLong(POST_INSTALL_EXCLUSIVITY_WINDOW);
308             }
309         }
310 
311         /** See {@link AttributionConfig#getSourceAdtech()} */
312         @NonNull
setSourceAdtech(@onNull String sourceAdtech)313         public Builder setSourceAdtech(@NonNull String sourceAdtech) {
314             Objects.requireNonNull(sourceAdtech);
315             mSourceAdtech = sourceAdtech;
316             return this;
317         }
318 
319         /** See {@link AttributionConfig#getSourcePriorityRange()} */
320         @NonNull
setSourcePriorityRange(@ullable Pair<Long, Long> sourcePriorityRange)321         public Builder setSourcePriorityRange(@Nullable Pair<Long, Long> sourcePriorityRange) {
322             mSourcePriorityRange = sourcePriorityRange;
323             return this;
324         }
325 
326         /** See {@link AttributionConfig#getSourceFilters()} */
327         @NonNull
setSourceFilters(@ullable List<FilterMap> sourceFilters)328         public Builder setSourceFilters(@Nullable List<FilterMap> sourceFilters) {
329             mSourceFilters = sourceFilters;
330             return this;
331         }
332 
333         /** See {@link AttributionConfig#getSourceNotFilters()} */
334         @NonNull
setSourceNotFilters(@ullable List<FilterMap> sourceNotFilters)335         public Builder setSourceNotFilters(@Nullable List<FilterMap> sourceNotFilters) {
336             mSourceNotFilters = sourceNotFilters;
337             return this;
338         }
339 
340         /** See {@link AttributionConfig#getSourceExpiryOverride()} */
341         @NonNull
setSourceExpiryOverride(@ullable Long sourceExpiryOverride)342         public Builder setSourceExpiryOverride(@Nullable Long sourceExpiryOverride) {
343             mSourceExpiryOverride = sourceExpiryOverride;
344             return this;
345         }
346 
347         /** See {@link AttributionConfig#getPriority()} */
348         @NonNull
setPriority(@ullable Long priority)349         public Builder setPriority(@Nullable Long priority) {
350             mPriority = priority;
351             return this;
352         }
353 
354         /** See {@link AttributionConfig#getExpiry()} */
355         @NonNull
setExpiry(@ullable Long expiry)356         public Builder setExpiry(@Nullable Long expiry) {
357             mExpiry = expiry;
358             return this;
359         }
360 
361         /** See {@link AttributionConfig#getFilterData()} */
362         @NonNull
setFilterData(@ullable List<FilterMap> filterData)363         public Builder setFilterData(@Nullable List<FilterMap> filterData) {
364             mFilterData = filterData;
365             return this;
366         }
367 
368         /** See {@link AttributionConfig#getPostInstallExclusivityWindow()} */
369         @NonNull
setPostInstallExclusivityWindow( @ullable Long postInstallExclusivityWindow)370         public Builder setPostInstallExclusivityWindow(
371                 @Nullable Long postInstallExclusivityWindow) {
372             mPostInstallExclusivityWindow = postInstallExclusivityWindow;
373             return this;
374         }
375 
376         /** Build the {@link AttributionConfig}. */
377         @NonNull
build()378         public AttributionConfig build() {
379             Objects.requireNonNull(mSourceAdtech);
380             return new AttributionConfig(this);
381         }
382     }
383 
384     /** Attribution Config field keys. */
385     public interface AttributionConfigContract {
386         String SOURCE_NETWORK = "source_network";
387         String SOURCE_PRIORITY_RANGE = "source_priority_range";
388         String SOURCE_FILTERS = "source_filters";
389         String SOURCE_NOT_FILTERS = "source_not_filters";
390         String SOURCE_EXPIRY_OVERRIDE = "source_expiry_override";
391         String PRIORITY = "priority";
392         String EXPIRY = "expiry";
393         String FILTER_DATA = "filter_data";
394         String POST_INSTALL_EXCLUSIVITY_WINDOW = "post_install_exclusivity_window";
395         String START = "start";
396         String END = "end";
397     }
398 }
399