• 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 package android.adservices.adid;
17 
18 import static android.adservices.common.AdServicesPermissions.ACCESS_ADSERVICES_AD_ID;
19 import static android.adservices.common.AdServicesStatusUtils.SERVICE_UNAVAILABLE_ERROR_MESSAGE;
20 import static android.adservices.common.AndroidRCommonUtil.invokeCallbackOnErrorOnRvc;
21 
22 import android.adservices.common.AdServicesOutcomeReceiver;
23 import android.adservices.common.AdServicesStatusUtils;
24 import android.adservices.common.CallerMetadata;
25 import android.adservices.common.OutcomeReceiverConverter;
26 import android.adservices.common.SandboxedSdkContextUtils;
27 import android.annotation.CallbackExecutor;
28 import android.annotation.FlaggedApi;
29 import android.annotation.NonNull;
30 import android.annotation.RequiresPermission;
31 import android.app.sdksandbox.SandboxedSdkContext;
32 import android.content.Context;
33 import android.os.Build;
34 import android.os.OutcomeReceiver;
35 import android.os.RemoteException;
36 import android.os.SystemClock;
37 
38 import androidx.annotation.RequiresApi;
39 
40 import com.android.adservices.AdServicesCommon;
41 import com.android.adservices.LogUtil;
42 import com.android.adservices.ServiceBinder;
43 import com.android.adservices.flags.Flags;
44 import com.android.adservices.shared.common.exception.ServiceUnavailableException;
45 
46 import java.util.Objects;
47 import java.util.concurrent.Executor;
48 
49 /**
50  * AdId Manager provides APIs for app and ad-SDKs to access advertising ID. The advertising ID is a
51  * unique, per-device, user-resettable ID for advertising. It gives users better controls and
52  * provides developers with a simple, standard system to continue to monetize their apps via
53  * personalized ads (formerly known as interest-based ads).
54  */
55 public class AdIdManager {
56     /**
57      * Service used for registering AdIdManager in the system service registry.
58      *
59      * @hide
60      */
61     public static final String ADID_SERVICE = "adid_service";
62 
63     // When an app calls the AdId API directly, it sets the SDK name to empty string.
64     static final String EMPTY_SDK = "";
65 
66     private Context mContext;
67     private ServiceBinder<IAdIdService> mServiceBinder;
68 
69     /**
70      * Factory method for creating an instance of AdIdManager.
71      *
72      * @param context The {@link Context} to use
73      * @return A {@link AdIdManager} instance
74      */
75     @NonNull
get(@onNull Context context)76     public static AdIdManager get(@NonNull Context context) {
77         // On T+, context.getSystemService() does more than just call constructor.
78         return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
79                 ? context.getSystemService(AdIdManager.class)
80                 : new AdIdManager(context);
81     }
82 
83     /**
84      * Create AdIdManager
85      *
86      * @hide
87      */
AdIdManager(Context context)88     public AdIdManager(Context context) {
89         // In case the AdIdManager is initiated from inside a sdk_sandbox process the fields
90         // will be immediately rewritten by the initialize method below.
91         initialize(context);
92     }
93 
94     /**
95      * Initializes {@link AdIdManager} with the given {@code context}.
96      *
97      * <p>This method is called by the {@link SandboxedSdkContext} to propagate the correct context.
98      * For more information check the javadoc on the {@link
99      * android.app.sdksandbox.SdkSandboxSystemServiceRegistry}.
100      *
101      * @hide
102      * @see android.app.sdksandbox.SdkSandboxSystemServiceRegistry
103      */
initialize(Context context)104     public AdIdManager initialize(Context context) {
105         mContext = context;
106         mServiceBinder =
107                 ServiceBinder.getServiceBinder(
108                         context,
109                         AdServicesCommon.ACTION_ADID_SERVICE,
110                         IAdIdService.Stub::asInterface);
111         return this;
112     }
113 
114     @SuppressWarnings("NewApi")
getService( @allbackExecutor Executor executor, OutcomeReceiver<AdId, Exception> callback)115     private IAdIdService getService(
116             @CallbackExecutor Executor executor, OutcomeReceiver<AdId, Exception> callback) {
117         IAdIdService service = null;
118         try {
119             service = mServiceBinder.getService();
120 
121             // Throw ServiceUnavailableException and set it to the callback.
122             if (service == null) {
123                 throw new ServiceUnavailableException(SERVICE_UNAVAILABLE_ERROR_MESSAGE);
124             }
125         } catch (RuntimeException e) {
126             LogUtil.e(e, "Failed binding to AdId service");
127             executor.execute(() -> callback.onError(e));
128         }
129 
130         return service;
131     }
132 
getContext()133     private Context getContext() {
134         return mContext;
135     }
136 
137     /**
138      * Return the AdId.
139      *
140      * @param executor The executor to run callback.
141      * @param callback The callback that's called after adid are available or an error occurs.
142      */
143     @RequiresApi(Build.VERSION_CODES.S)
144     @RequiresPermission(ACCESS_ADSERVICES_AD_ID)
145     @NonNull
getAdId( @onNull @allbackExecutor Executor executor, @NonNull OutcomeReceiver<AdId, Exception> callback)146     public void getAdId(
147             @NonNull @CallbackExecutor Executor executor,
148             @NonNull OutcomeReceiver<AdId, Exception> callback) {
149         Objects.requireNonNull(executor, "executor must not be null");
150         Objects.requireNonNull(callback, "callback must not be null");
151         CallerMetadata callerMetadata =
152                 new CallerMetadata.Builder()
153                         .setBinderElapsedTimestamp(SystemClock.elapsedRealtime())
154                         .build();
155         String appPackageName = "";
156         String sdkPackageName = "";
157         // First check if context is SandboxedSdkContext or not
158         Context getAdIdRequestContext = getContext();
159         SandboxedSdkContext requestContext =
160                 SandboxedSdkContextUtils.getAsSandboxedSdkContext(getAdIdRequestContext);
161         if (requestContext != null) {
162             sdkPackageName = requestContext.getSdkPackageName();
163             appPackageName = requestContext.getClientPackageName();
164         } else { // This is the case without the Sandbox.
165             appPackageName = getAdIdRequestContext.getPackageName();
166         }
167 
168         try {
169             IAdIdService service = getService(executor, callback);
170             if (service == null) {
171                 LogUtil.w("Unable to find AdId service");
172                 return;
173             }
174 
175             service.getAdId(
176                     new GetAdIdParam.Builder()
177                             .setAppPackageName(appPackageName)
178                             .setSdkPackageName(sdkPackageName)
179                             .build(),
180                     callerMetadata,
181                     new IGetAdIdCallback.Stub() {
182                         @Override
183                         public void onResult(GetAdIdResult resultParcel) {
184                             executor.execute(
185                                     () -> {
186                                         if (resultParcel.isSuccess()) {
187                                             callback.onResult(
188                                                     new AdId(
189                                                             resultParcel.getAdId(),
190                                                             resultParcel.isLatEnabled()));
191                                         } else {
192                                             callback.onError(
193                                                     AdServicesStatusUtils.asException(
194                                                             resultParcel));
195                                         }
196                                     });
197                         }
198 
199                         @Override
200                         public void onError(int resultCode) {
201                             executor.execute(
202                                     () ->
203                                             callback.onError(
204                                                     AdServicesStatusUtils.asException(resultCode)));
205                         }
206                     });
207         } catch (RemoteException e) {
208             LogUtil.e(e, "RemoteException");
209             callback.onError(e);
210         }
211     }
212 
213     /**
214      * Return the AdId. For use on Android R or lower.
215      *
216      * @param executor The executor to run callback.
217      * @param callback The callback that's called after adid are available or an error occurs.
218      * @deprecated use {@link #getAdId(Executor, OutcomeReceiver)} instead. Android R is no longer
219      *     supported.
220      */
221     @RequiresPermission(ACCESS_ADSERVICES_AD_ID)
222     @Deprecated
223     @FlaggedApi(Flags.FLAG_ADSERVICES_OUTCOMERECEIVER_R_API_DEPRECATED)
224     @SuppressWarnings("NewApi")
225     @NonNull
getAdId( @onNull @allbackExecutor Executor executor, @NonNull AdServicesOutcomeReceiver<AdId, Exception> callback)226     public void getAdId(
227             @NonNull @CallbackExecutor Executor executor,
228             @NonNull AdServicesOutcomeReceiver<AdId, Exception> callback) {
229         if (invokeCallbackOnErrorOnRvc(callback)) {
230             return;
231         }
232 
233         getAdId(executor, OutcomeReceiverConverter.toOutcomeReceiver(callback));
234     }
235 
236     /**
237      * If the service is in an APK (as opposed to the system service), unbind it from the service to
238      * allow the APK process to die.
239      *
240      * @hide
241      */
242     // TODO: change to @VisibleForTesting
unbindFromService()243     public void unbindFromService() {
244         mServiceBinder.unbindFromService();
245     }
246 }
247