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 package android.adservices.measurement; 17 18 import static android.adservices.common.AdServicesPermissions.ACCESS_ADSERVICES_ATTRIBUTION; 19 20 import android.adservices.common.AdServicesOutcomeReceiver; 21 import android.adservices.common.OutcomeReceiverConverter; 22 import android.annotation.CallbackExecutor; 23 import android.annotation.FlaggedApi; 24 import android.annotation.IntDef; 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.annotation.RequiresPermission; 28 import android.app.sdksandbox.SandboxedSdkContext; 29 import android.content.Context; 30 import android.net.Uri; 31 import android.os.Build; 32 import android.os.OutcomeReceiver; 33 import android.view.InputEvent; 34 35 import androidx.annotation.RequiresApi; 36 37 import com.android.adservices.flags.Flags; 38 import com.android.internal.annotations.VisibleForTesting; 39 40 import java.lang.annotation.Retention; 41 import java.lang.annotation.RetentionPolicy; 42 import java.util.Objects; 43 import java.util.concurrent.Executor; 44 45 /** MeasurementManager provides APIs to manage source and trigger registrations. */ 46 public class MeasurementManager { 47 /** @hide */ 48 public static final String MEASUREMENT_SERVICE = "measurement_service"; 49 50 /** 51 * This state indicates that Measurement APIs are unavailable. Invoking them will result in an 52 * {@link UnsupportedOperationException}. 53 */ 54 public static final int MEASUREMENT_API_STATE_DISABLED = 0; 55 56 /** 57 * This state indicates that Measurement APIs are enabled. 58 */ 59 public static final int MEASUREMENT_API_STATE_ENABLED = 1; 60 61 /** @hide */ 62 @Retention(RetentionPolicy.SOURCE) 63 @IntDef( 64 prefix = "MEASUREMENT_API_STATE_", 65 value = { 66 MEASUREMENT_API_STATE_DISABLED, 67 MEASUREMENT_API_STATE_ENABLED, 68 }) 69 public @interface MeasurementApiState {} 70 71 private MeasurementCompatibleManager mImpl; 72 73 /** 74 * Factory method for creating an instance of MeasurementManager. 75 * 76 * @param context The {@link Context} to use 77 * @return A {@link MeasurementManager} instance 78 */ 79 @NonNull get(@onNull Context context)80 public static MeasurementManager get(@NonNull Context context) { 81 // On T+, context.getSystemService() does more than just call constructor. 82 return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) 83 ? context.getSystemService(MeasurementManager.class) 84 : new MeasurementManager(context); 85 } 86 87 /** 88 * Create MeasurementManager. 89 * 90 * @hide 91 */ MeasurementManager(Context context)92 public MeasurementManager(Context context) { 93 // In case the MeasurementManager is initiated from inside a sdk_sandbox process the 94 // fields will be immediately rewritten by the initialize method below. 95 initialize(context); 96 } 97 98 /** 99 * Create MeasurementManager 100 * 101 * @param compatibleManager the underlying implementation that can be mocked for tests 102 * @hide 103 */ 104 @VisibleForTesting MeasurementManager(@onNull MeasurementCompatibleManager compatibleManager)105 public MeasurementManager(@NonNull MeasurementCompatibleManager compatibleManager) { 106 Objects.requireNonNull(compatibleManager); 107 mImpl = compatibleManager; 108 } 109 110 /** 111 * Initializes {@link MeasurementManager} with the given {@code context}. 112 * 113 * <p>This method is called by the {@link SandboxedSdkContext} to propagate the correct context. 114 * For more information check the javadoc on the {@link 115 * android.app.sdksandbox.SdkSandboxSystemServiceRegistry}. 116 * 117 * @hide 118 * @see android.app.sdksandbox.SdkSandboxSystemServiceRegistry 119 */ initialize(@onNull Context context)120 public MeasurementManager initialize(@NonNull Context context) { 121 mImpl = MeasurementCompatibleManager.get(context); 122 return this; 123 } 124 125 /** 126 * Register an attribution source (click or view). 127 * 128 * @param attributionSource the platform issues a request to this URI in order to fetch metadata 129 * associated with the attribution source. The source metadata is stored on device, making 130 * it eligible to be matched to future triggers. 131 * @param inputEvent either an {@link InputEvent} object (for a click event) or null (for a view 132 * event). 133 * @param executor used by callback to dispatch results. 134 * @param callback intended to notify asynchronously the API result. 135 * @throws IllegalArgumentException if the scheme for {@code attributionSource} is not HTTPS 136 */ 137 @RequiresApi(Build.VERSION_CODES.S) 138 @RequiresPermission(ACCESS_ADSERVICES_ATTRIBUTION) registerSource( @onNull Uri attributionSource, @Nullable InputEvent inputEvent, @Nullable @CallbackExecutor Executor executor, @Nullable OutcomeReceiver<Object, Exception> callback)139 public void registerSource( 140 @NonNull Uri attributionSource, 141 @Nullable InputEvent inputEvent, 142 @Nullable @CallbackExecutor Executor executor, 143 @Nullable OutcomeReceiver<Object, Exception> callback) { 144 mImpl.registerSource( 145 attributionSource, 146 inputEvent, 147 executor, 148 OutcomeReceiverConverter.toAdServicesOutcomeReceiver(callback)); 149 } 150 151 /** 152 * Register an attribution source (click or view). For use on Android R or lower. 153 * 154 * @param attributionSource the platform issues a request to this URI in order to fetch metadata 155 * associated with the attribution source. The source metadata is stored on device, making 156 * it eligible to be matched to future triggers. 157 * @param inputEvent either an {@link InputEvent} object (for a click event) or null (for a view 158 * event). 159 * @param executor used by callback to dispatch results. 160 * @param callback intended to notify asynchronously the API result. 161 */ 162 @FlaggedApi(Flags.FLAG_ADSERVICES_OUTCOMERECEIVER_R_API_ENABLED) 163 @RequiresPermission(ACCESS_ADSERVICES_ATTRIBUTION) registerSource( @onNull Uri attributionSource, @Nullable InputEvent inputEvent, @Nullable @CallbackExecutor Executor executor, @Nullable AdServicesOutcomeReceiver<Object, Exception> callback)164 public void registerSource( 165 @NonNull Uri attributionSource, 166 @Nullable InputEvent inputEvent, 167 @Nullable @CallbackExecutor Executor executor, 168 @Nullable AdServicesOutcomeReceiver<Object, Exception> callback) { 169 mImpl.registerSource(attributionSource, inputEvent, executor, callback); 170 } 171 172 /** 173 * Register attribution sources(click or view) from an app context. This API will not process 174 * any redirects, all registration URLs should be supplied with the request. 175 * 176 * @param request app source registration request 177 * @param executor used by callback to dispatch results 178 * @param callback intended to notify asynchronously the API result 179 */ 180 @RequiresApi(Build.VERSION_CODES.S) 181 @RequiresPermission(ACCESS_ADSERVICES_ATTRIBUTION) registerSource( @onNull SourceRegistrationRequest request, @Nullable @CallbackExecutor Executor executor, @Nullable OutcomeReceiver<Object, Exception> callback)182 public void registerSource( 183 @NonNull SourceRegistrationRequest request, 184 @Nullable @CallbackExecutor Executor executor, 185 @Nullable OutcomeReceiver<Object, Exception> callback) { 186 mImpl.registerSource( 187 request, executor, OutcomeReceiverConverter.toAdServicesOutcomeReceiver(callback)); 188 } 189 190 /** 191 * Register attribution sources(click or view) from an app context. This API will not process 192 * any redirects, all registration URLs should be supplied with the request. For use on Android 193 * R or lower. 194 * 195 * @param request app source registration request 196 * @param executor used by callback to dispatch results 197 * @param callback intended to notify asynchronously the API result 198 */ 199 @FlaggedApi(Flags.FLAG_ADSERVICES_OUTCOMERECEIVER_R_API_ENABLED) 200 @RequiresPermission(ACCESS_ADSERVICES_ATTRIBUTION) registerSource( @onNull SourceRegistrationRequest request, @Nullable @CallbackExecutor Executor executor, @Nullable AdServicesOutcomeReceiver<Object, Exception> callback)201 public void registerSource( 202 @NonNull SourceRegistrationRequest request, 203 @Nullable @CallbackExecutor Executor executor, 204 @Nullable AdServicesOutcomeReceiver<Object, Exception> callback) { 205 mImpl.registerSource(request, executor, callback); 206 } 207 208 /** 209 * Register an attribution source(click or view) from web context. This API will not process any 210 * redirects, all registration URLs should be supplied with the request. At least one of 211 * appDestination or webDestination parameters are required to be provided. If the registration 212 * is successful, {@code callback}'s {@link OutcomeReceiver#onResult} is invoked with null. In 213 * case of failure, a {@link Exception} is sent through {@code callback}'s {@link 214 * OutcomeReceiver#onError}. Both success and failure feedback are executed on the provided 215 * {@link Executor}. 216 * 217 * @param request source registration request 218 * @param executor used by callback to dispatch results. 219 * @param callback intended to notify asynchronously the API result. 220 */ 221 @RequiresApi(Build.VERSION_CODES.S) 222 @RequiresPermission(ACCESS_ADSERVICES_ATTRIBUTION) registerWebSource( @onNull WebSourceRegistrationRequest request, @Nullable Executor executor, @Nullable OutcomeReceiver<Object, Exception> callback)223 public void registerWebSource( 224 @NonNull WebSourceRegistrationRequest request, 225 @Nullable Executor executor, 226 @Nullable OutcomeReceiver<Object, Exception> callback) { 227 mImpl.registerWebSource( 228 request, executor, OutcomeReceiverConverter.toAdServicesOutcomeReceiver(callback)); 229 } 230 231 /** 232 * Register an attribution source(click or view) from web context. This API will not process any 233 * redirects, all registration URLs should be supplied with the request. At least one of 234 * appDestination or webDestination parameters are required to be provided. If the registration 235 * is successful, {@code callback}'s {@link OutcomeReceiver#onResult} is invoked with null. In 236 * case of failure, a {@link Exception} is sent through {@code callback}'s {@link 237 * OutcomeReceiver#onError}. Both success and failure feedback are executed on the provided 238 * {@link Executor}. 239 * 240 * <p>For use on Android R or lower. 241 * 242 * @param request source registration request 243 * @param executor used by callback to dispatch results. 244 * @param callback intended to notify asynchronously the API result. 245 */ 246 @FlaggedApi(Flags.FLAG_ADSERVICES_OUTCOMERECEIVER_R_API_ENABLED) 247 @RequiresPermission(ACCESS_ADSERVICES_ATTRIBUTION) registerWebSource( @onNull WebSourceRegistrationRequest request, @Nullable Executor executor, @Nullable AdServicesOutcomeReceiver<Object, Exception> callback)248 public void registerWebSource( 249 @NonNull WebSourceRegistrationRequest request, 250 @Nullable Executor executor, 251 @Nullable AdServicesOutcomeReceiver<Object, Exception> callback) { 252 mImpl.registerWebSource(request, executor, callback); 253 } 254 255 /** 256 * Register an attribution trigger(click or view) from web context. This API will not process 257 * any redirects, all registration URLs should be supplied with the request. If the registration 258 * is successful, {@code callback}'s {@link OutcomeReceiver#onResult} is invoked with null. In 259 * case of failure, a {@link Exception} is sent through {@code callback}'s {@link 260 * OutcomeReceiver#onError}. Both success and failure feedback are executed on the provided 261 * {@link Executor}. 262 * 263 * @param request trigger registration request 264 * @param executor used by callback to dispatch results 265 * @param callback intended to notify asynchronously the API result 266 */ 267 @RequiresApi(Build.VERSION_CODES.S) 268 @RequiresPermission(ACCESS_ADSERVICES_ATTRIBUTION) registerWebTrigger( @onNull WebTriggerRegistrationRequest request, @Nullable Executor executor, @Nullable OutcomeReceiver<Object, Exception> callback)269 public void registerWebTrigger( 270 @NonNull WebTriggerRegistrationRequest request, 271 @Nullable Executor executor, 272 @Nullable OutcomeReceiver<Object, Exception> callback) { 273 mImpl.registerWebTrigger( 274 request, executor, OutcomeReceiverConverter.toAdServicesOutcomeReceiver(callback)); 275 } 276 277 /** 278 * Register an attribution trigger(click or view) from web context. This API will not process 279 * any redirects, all registration URLs should be supplied with the request. If the registration 280 * is successful, {@code callback}'s {@link OutcomeReceiver#onResult} is invoked with null. In 281 * case of failure, a {@link Exception} is sent through {@code callback}'s {@link 282 * OutcomeReceiver#onError}. Both success and failure feedback are executed on the provided 283 * {@link Executor}. 284 * 285 * <p>For use on Android R or lower. 286 * 287 * @param request trigger registration request 288 * @param executor used by callback to dispatch results 289 * @param callback intended to notify asynchronously the API result 290 */ 291 @FlaggedApi(Flags.FLAG_ADSERVICES_OUTCOMERECEIVER_R_API_ENABLED) 292 @RequiresPermission(ACCESS_ADSERVICES_ATTRIBUTION) registerWebTrigger( @onNull WebTriggerRegistrationRequest request, @Nullable Executor executor, @Nullable AdServicesOutcomeReceiver<Object, Exception> callback)293 public void registerWebTrigger( 294 @NonNull WebTriggerRegistrationRequest request, 295 @Nullable Executor executor, 296 @Nullable AdServicesOutcomeReceiver<Object, Exception> callback) { 297 mImpl.registerWebTrigger(request, executor, callback); 298 } 299 300 /** 301 * Register a trigger (conversion). 302 * 303 * @param trigger the API issues a request to this URI to fetch metadata associated with the 304 * trigger. The trigger metadata is stored on-device, and is eligible to be matched with 305 * sources during the attribution process. 306 * @param executor used by callback to dispatch results. 307 * @param callback intended to notify asynchronously the API result. 308 * @throws IllegalArgumentException if the scheme for {@code trigger} is not HTTPS 309 */ 310 @RequiresApi(Build.VERSION_CODES.S) 311 @RequiresPermission(ACCESS_ADSERVICES_ATTRIBUTION) registerTrigger( @onNull Uri trigger, @Nullable @CallbackExecutor Executor executor, @Nullable OutcomeReceiver<Object, Exception> callback)312 public void registerTrigger( 313 @NonNull Uri trigger, 314 @Nullable @CallbackExecutor Executor executor, 315 @Nullable OutcomeReceiver<Object, Exception> callback) { 316 mImpl.registerTrigger( 317 trigger, executor, OutcomeReceiverConverter.toAdServicesOutcomeReceiver(callback)); 318 } 319 320 /** 321 * Register a trigger (conversion). For use on Android R or lower. 322 * 323 * @param trigger the API issues a request to this URI to fetch metadata associated with the 324 * trigger. The trigger metadata is stored on-device, and is eligible to be matched with 325 * sources during the attribution process. 326 * @param executor used by callback to dispatch results. 327 * @param callback intended to notify asynchronously the API result. 328 */ 329 @FlaggedApi(Flags.FLAG_ADSERVICES_OUTCOMERECEIVER_R_API_ENABLED) 330 @RequiresPermission(ACCESS_ADSERVICES_ATTRIBUTION) registerTrigger( @onNull Uri trigger, @Nullable @CallbackExecutor Executor executor, @Nullable AdServicesOutcomeReceiver<Object, Exception> callback)331 public void registerTrigger( 332 @NonNull Uri trigger, 333 @Nullable @CallbackExecutor Executor executor, 334 @Nullable AdServicesOutcomeReceiver<Object, Exception> callback) { 335 mImpl.registerTrigger(trigger, executor, callback); 336 } 337 338 /** 339 * Delete previous registrations. If the deletion is successful, the callback's {@link 340 * OutcomeReceiver#onResult} is invoked with null. In case of failure, a {@link Exception} is 341 * sent through the callback's {@link OutcomeReceiver#onError}. Both success and failure 342 * feedback are executed on the provided {@link Executor}. 343 * 344 * @param deletionRequest The request for deleting data. 345 * @param executor The executor to run callback. 346 * @param callback intended to notify asynchronously the API result. 347 */ 348 @RequiresApi(Build.VERSION_CODES.S) deleteRegistrations( @onNull DeletionRequest deletionRequest, @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Object, Exception> callback)349 public void deleteRegistrations( 350 @NonNull DeletionRequest deletionRequest, 351 @NonNull @CallbackExecutor Executor executor, 352 @NonNull OutcomeReceiver<Object, Exception> callback) { 353 mImpl.deleteRegistrations( 354 deletionRequest, 355 executor, 356 OutcomeReceiverConverter.toAdServicesOutcomeReceiver(callback)); 357 } 358 359 /** 360 * Delete previous registrations. If the deletion is successful, the callback's {@link 361 * OutcomeReceiver#onResult} is invoked with null. In case of failure, a {@link Exception} is 362 * sent through the callback's {@link OutcomeReceiver#onError}. Both success and failure 363 * feedback are executed on the provided {@link Executor}. 364 * 365 * <p>For use on Android R or lower. 366 * 367 * @param deletionRequest The request for deleting data. 368 * @param executor The executor to run callback. 369 * @param callback intended to notify asynchronously the API result. 370 */ 371 @FlaggedApi(Flags.FLAG_ADSERVICES_OUTCOMERECEIVER_R_API_ENABLED) deleteRegistrations( @onNull DeletionRequest deletionRequest, @NonNull @CallbackExecutor Executor executor, @NonNull AdServicesOutcomeReceiver<Object, Exception> callback)372 public void deleteRegistrations( 373 @NonNull DeletionRequest deletionRequest, 374 @NonNull @CallbackExecutor Executor executor, 375 @NonNull AdServicesOutcomeReceiver<Object, Exception> callback) { 376 mImpl.deleteRegistrations(deletionRequest, executor, callback); 377 } 378 379 /** 380 * Get Measurement API status. 381 * 382 * <p>The callback's {@code Integer} value is one of {@code MeasurementApiState}. 383 * 384 * @param executor used by callback to dispatch results. 385 * @param callback intended to notify asynchronously the API result. 386 */ 387 @RequiresApi(Build.VERSION_CODES.S) 388 @RequiresPermission(ACCESS_ADSERVICES_ATTRIBUTION) getMeasurementApiStatus( @onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<Integer, Exception> callback)389 public void getMeasurementApiStatus( 390 @NonNull @CallbackExecutor Executor executor, 391 @NonNull OutcomeReceiver<Integer, Exception> callback) { 392 mImpl.getMeasurementApiStatus( 393 executor, OutcomeReceiverConverter.toAdServicesOutcomeReceiver(callback)); 394 } 395 396 /** 397 * Get Measurement API status. 398 * 399 * <p>The callback's {@code Integer} value is one of {@code MeasurementApiState}. 400 * 401 * <p>For use on Android R or lower. 402 * 403 * @param executor used by callback to dispatch results. 404 * @param callback intended to notify asynchronously the API result. 405 */ 406 @FlaggedApi(Flags.FLAG_ADSERVICES_OUTCOMERECEIVER_R_API_ENABLED) 407 @RequiresPermission(ACCESS_ADSERVICES_ATTRIBUTION) getMeasurementApiStatus( @onNull @allbackExecutor Executor executor, @NonNull AdServicesOutcomeReceiver<Integer, Exception> callback)408 public void getMeasurementApiStatus( 409 @NonNull @CallbackExecutor Executor executor, 410 @NonNull AdServicesOutcomeReceiver<Integer, Exception> callback) { 411 mImpl.getMeasurementApiStatus(executor, callback); 412 } 413 414 /** 415 * If the service is in an APK (as opposed to the system service), unbind it from the service to 416 * allow the APK process to die. 417 * 418 * @hide Not sure if we'll need this functionality in the final API. For now, we need it for 419 * performance testing to simulate "cold-start" situations. 420 */ 421 @VisibleForTesting unbindFromService()422 public void unbindFromService() { 423 mImpl.unbindFromService(); 424 } 425 } 426