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 android.adservices.ondevicepersonalization; 18 19 import static android.adservices.ondevicepersonalization.OnDevicePersonalizationPermissions.NOTIFY_MEASUREMENT_EVENT; 20 21 import android.adservices.ondevicepersonalization.aidl.IOnDevicePersonalizationManagingService; 22 import android.adservices.ondevicepersonalization.aidl.IRegisterMeasurementEventCallback; 23 import android.annotation.CallbackExecutor; 24 import android.annotation.FlaggedApi; 25 import android.annotation.NonNull; 26 import android.annotation.RequiresPermission; 27 import android.annotation.SystemApi; 28 import android.content.Context; 29 import android.os.Binder; 30 import android.os.Bundle; 31 import android.os.OutcomeReceiver; 32 import android.os.SystemClock; 33 34 import com.android.adservices.ondevicepersonalization.flags.Flags; 35 import com.android.federatedcompute.internal.util.AbstractServiceBinder; 36 import com.android.internal.annotations.VisibleForTesting; 37 import com.android.ondevicepersonalization.internal.util.LoggerFactory; 38 39 import java.util.List; 40 import java.util.Objects; 41 import java.util.concurrent.Executor; 42 43 /** 44 * Provides APIs for the platform to signal events that are to be handled by the ODP service. 45 * @hide 46 */ 47 @SystemApi 48 @FlaggedApi(Flags.FLAG_ON_DEVICE_PERSONALIZATION_APIS_ENABLED) 49 public class OnDevicePersonalizationSystemEventManager { 50 /** @hide */ 51 public static final String ON_DEVICE_PERSONALIZATION_SYSTEM_EVENT_SERVICE = 52 "on_device_personalization_system_event_service"; 53 private static final String INTENT_FILTER_ACTION = 54 "android.OnDevicePersonalizationService"; 55 private static final String ODP_MANAGING_SERVICE_PACKAGE_SUFFIX = 56 "com.android.ondevicepersonalization.services"; 57 private static final String ALT_ODP_MANAGING_SERVICE_PACKAGE_SUFFIX = 58 "com.google.android.ondevicepersonalization.services"; 59 private static final String TAG = 60 OnDevicePersonalizationSystemEventManager.class.getSimpleName(); 61 private static final LoggerFactory.Logger sLogger = LoggerFactory.getLogger(); 62 63 // TODO(b/301732670): Define a new service for this manager and bind to it. 64 private final AbstractServiceBinder<IOnDevicePersonalizationManagingService> mServiceBinder; 65 private final Context mContext; 66 67 /** @hide */ OnDevicePersonalizationSystemEventManager(Context context)68 public OnDevicePersonalizationSystemEventManager(Context context) { 69 this( 70 context, 71 AbstractServiceBinder.getServiceBinderByIntent( 72 context, 73 INTENT_FILTER_ACTION, 74 List.of( 75 ODP_MANAGING_SERVICE_PACKAGE_SUFFIX, 76 ALT_ODP_MANAGING_SERVICE_PACKAGE_SUFFIX), 77 0, 78 IOnDevicePersonalizationManagingService.Stub::asInterface)); 79 } 80 81 /** @hide */ 82 @VisibleForTesting OnDevicePersonalizationSystemEventManager( Context context, AbstractServiceBinder<IOnDevicePersonalizationManagingService> serviceBinder)83 public OnDevicePersonalizationSystemEventManager( 84 Context context, 85 AbstractServiceBinder<IOnDevicePersonalizationManagingService> serviceBinder) { 86 mContext = context; 87 mServiceBinder = serviceBinder; 88 } 89 90 /** 91 * Receives a web trigger event from the Measurement API. This is intended to be called by the 92 * <a href="https://developer.android.com/design-for-safety/privacy-sandbox/guides/attribution"> 93 * Measurement Service</a> when a browser registers an attribution event using the 94 * <a href="https://github.com/WICG/attribution-reporting-api">Attribution and Reporting API</a> 95 * with a payload that should be processed by an {@link IsolatedService}. 96 * 97 * @param measurementWebTriggerEvent the web trigger payload to be processed. 98 * @param executor the {@link Executor} on which to invoke the callback. 99 * @param receiver This either returns a {@code null} on success, or an exception on failure. 100 */ 101 @RequiresPermission(NOTIFY_MEASUREMENT_EVENT) notifyMeasurementEvent( @onNull MeasurementWebTriggerEventParams measurementWebTriggerEvent, @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Void, Exception> receiver)102 public void notifyMeasurementEvent( 103 @NonNull MeasurementWebTriggerEventParams measurementWebTriggerEvent, 104 @NonNull @CallbackExecutor Executor executor, 105 @NonNull OutcomeReceiver<Void, Exception> receiver) { 106 Objects.requireNonNull(measurementWebTriggerEvent); 107 Objects.requireNonNull(executor); 108 Objects.requireNonNull(receiver); 109 long startTimeMillis = SystemClock.elapsedRealtime(); 110 111 final IOnDevicePersonalizationManagingService service = 112 mServiceBinder.getService(executor); 113 114 try { 115 Bundle bundle = new Bundle(); 116 bundle.putParcelable(Constants.EXTRA_MEASUREMENT_WEB_TRIGGER_PARAMS, 117 new MeasurementWebTriggerEventParamsParcel(measurementWebTriggerEvent)); 118 // TODO(b/301732670): Update method name in service. 119 service.registerMeasurementEvent( 120 Constants.MEASUREMENT_EVENT_TYPE_WEB_TRIGGER, 121 bundle, 122 new CallerMetadata.Builder().setStartTimeMillis(startTimeMillis).build(), 123 new IRegisterMeasurementEventCallback.Stub() { 124 @Override 125 public void onSuccess(CalleeMetadata calleeMetadata) { 126 final long token = Binder.clearCallingIdentity(); 127 try { 128 executor.execute(() -> receiver.onResult(null)); 129 } finally { 130 Binder.restoreCallingIdentity(token); 131 logApiCallStats( 132 service, 133 "", 134 Constants.API_NAME_NOTIFY_MEASUREMENT_EVENT, 135 SystemClock.elapsedRealtime() - startTimeMillis, 136 calleeMetadata.getServiceEntryTimeMillis() - startTimeMillis, 137 SystemClock.elapsedRealtime() 138 - calleeMetadata.getCallbackInvokeTimeMillis(), 139 Constants.STATUS_SUCCESS); 140 } 141 } 142 @Override 143 public void onError(int errorCode, CalleeMetadata calleeMetadata) { 144 final long token = Binder.clearCallingIdentity(); 145 try { 146 executor.execute(() -> receiver.onError( 147 new IllegalStateException("Error: " + errorCode))); 148 } finally { 149 Binder.restoreCallingIdentity(token); 150 logApiCallStats( 151 service, 152 "", 153 Constants.API_NAME_NOTIFY_MEASUREMENT_EVENT, 154 SystemClock.elapsedRealtime() - startTimeMillis, 155 calleeMetadata.getServiceEntryTimeMillis() - startTimeMillis, 156 SystemClock.elapsedRealtime() 157 - calleeMetadata.getCallbackInvokeTimeMillis(), 158 errorCode); 159 } 160 } 161 } 162 ); 163 } catch (IllegalArgumentException | NullPointerException e) { 164 logApiCallStats( 165 service, 166 "", 167 Constants.API_NAME_NOTIFY_MEASUREMENT_EVENT, 168 SystemClock.elapsedRealtime() - startTimeMillis, 169 0, 170 0, 171 Constants.STATUS_INTERNAL_ERROR); 172 throw e; 173 } catch (Exception e) { 174 logApiCallStats( 175 service, 176 "", 177 Constants.API_NAME_NOTIFY_MEASUREMENT_EVENT, 178 SystemClock.elapsedRealtime() - startTimeMillis, 179 0, 180 0, 181 Constants.STATUS_INTERNAL_ERROR); 182 receiver.onError(e); 183 } 184 } 185 logApiCallStats( IOnDevicePersonalizationManagingService service, String sdkPackageName, int apiName, long latencyMillis, long rpcCallLatencyMillis, long rpcReturnLatencyMillis, int responseCode)186 private void logApiCallStats( 187 IOnDevicePersonalizationManagingService service, 188 String sdkPackageName, 189 int apiName, 190 long latencyMillis, 191 long rpcCallLatencyMillis, 192 long rpcReturnLatencyMillis, 193 int responseCode) { 194 try { 195 if (service != null) { 196 service.logApiCallStats(sdkPackageName, apiName, latencyMillis, 197 rpcCallLatencyMillis, rpcReturnLatencyMillis, responseCode); 198 } 199 } catch (Exception e) { 200 sLogger.e(e, TAG + ": Error logging API call stats"); 201 } 202 } 203 } 204