script-astra/Android/Sdk/sources/android-35/android/adservices/ondevicepersonalization/EventUrlProvider.java

157 lines
6.5 KiB
Java
Raw Normal View History

2025-01-20 15:15:20 +00:00
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.adservices.ondevicepersonalization;
import android.adservices.ondevicepersonalization.aidl.IDataAccessService;
import android.adservices.ondevicepersonalization.aidl.IDataAccessServiceCallback;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.WorkerThread;
import android.net.Uri;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.os.RemoteException;
import com.android.adservices.ondevicepersonalization.flags.Flags;
import com.android.ondevicepersonalization.internal.util.LoggerFactory;
import java.util.Objects;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
* Generates event tracking URLs for a request. The service can embed these URLs within the
* HTML output as needed. When the HTML is rendered within an ODP WebView, ODP will intercept
* requests to these URLs, call
* {@code IsolatedWorker#onEvent(EventInput, android.os.OutcomeReceiver)}, and log the returned
* output in the EVENTS table.
*
*/
@FlaggedApi(Flags.FLAG_ON_DEVICE_PERSONALIZATION_APIS_ENABLED)
public class EventUrlProvider {
private static final LoggerFactory.Logger sLogger = LoggerFactory.getLogger();
private static final String TAG = EventUrlProvider.class.getSimpleName();
private static final long ASYNC_TIMEOUT_MS = 1000;
@NonNull private final IDataAccessService mDataAccessService;
/** @hide */
public EventUrlProvider(@NonNull IDataAccessService binder) {
mDataAccessService = Objects.requireNonNull(binder);
}
/**
* Creates an event tracking URL that returns the provided response. Returns HTTP Status
* 200 (OK) if the response data is not empty. Returns HTTP Status 204 (No Content) if the
* response data is empty.
*
* @param eventParams The data to be passed to
* {@code IsolatedWorker#onEvent(EventInput, android.os.OutcomeReceiver)}
* when the event occurs.
* @param responseData The content to be returned to the WebView when the URL is fetched.
* @param mimeType The Mime Type of the URL response.
* @return An ODP event URL that can be inserted into a WebView.
*/
@WorkerThread
@NonNull public Uri createEventTrackingUrlWithResponse(
@NonNull PersistableBundle eventParams,
@Nullable byte[] responseData,
@Nullable String mimeType) {
final long startTimeMillis = System.currentTimeMillis();
Bundle params = new Bundle();
params.putParcelable(Constants.EXTRA_EVENT_PARAMS, eventParams);
params.putByteArray(Constants.EXTRA_RESPONSE_DATA, responseData);
params.putString(Constants.EXTRA_MIME_TYPE, mimeType);
return getUrl(params, Constants.API_NAME_EVENT_URL_CREATE_WITH_RESPONSE, startTimeMillis);
}
/**
* Creates an event tracking URL that redirects to the provided destination URL when it is
* clicked in an ODP webview.
*
* @param eventParams The data to be passed to
* {@code IsolatedWorker#onEvent(EventInput, android.os.OutcomeReceiver)}
* when the event occurs
* @param destinationUrl The URL to redirect to.
* @return An ODP event URL that can be inserted into a WebView.
*/
@WorkerThread
@NonNull public Uri createEventTrackingUrlWithRedirect(
@NonNull PersistableBundle eventParams,
@Nullable Uri destinationUrl) {
final long startTimeMillis = System.currentTimeMillis();
Bundle params = new Bundle();
params.putParcelable(Constants.EXTRA_EVENT_PARAMS, eventParams);
params.putString(Constants.EXTRA_DESTINATION_URL, destinationUrl.toString());
return getUrl(params, Constants.API_NAME_EVENT_URL_CREATE_WITH_REDIRECT, startTimeMillis);
}
@NonNull private Uri getUrl(
@NonNull Bundle params, int apiName, long startTimeMillis) {
int responseCode = Constants.STATUS_SUCCESS;
try {
BlockingQueue<CallbackResult> asyncResult = new ArrayBlockingQueue<>(1);
mDataAccessService.onRequest(
Constants.DATA_ACCESS_OP_GET_EVENT_URL,
params,
new IDataAccessServiceCallback.Stub() {
@Override
public void onSuccess(@NonNull Bundle result) {
asyncResult.add(new CallbackResult(result, 0));
}
@Override
public void onError(int errorCode) {
asyncResult.add(new CallbackResult(null, errorCode));
}
});
CallbackResult callbackResult = asyncResult.take();
Objects.requireNonNull(callbackResult);
if (callbackResult.mErrorCode != 0) {
throw new IllegalStateException("Error: " + callbackResult.mErrorCode);
}
Bundle result = Objects.requireNonNull(callbackResult.mResult);
Uri url = Objects.requireNonNull(
result.getParcelable(Constants.EXTRA_RESULT, Uri.class));
return url;
} catch (InterruptedException | RemoteException e) {
responseCode = Constants.STATUS_INTERNAL_ERROR;
throw new RuntimeException(e);
} finally {
try {
mDataAccessService.logApiCallStats(
apiName,
System.currentTimeMillis() - startTimeMillis,
responseCode);
} catch (Exception e) {
sLogger.d(e, TAG + ": failed to log metrics");
}
}
}
private static class CallbackResult {
final Bundle mResult;
final int mErrorCode;
CallbackResult(Bundle result, int errorCode) {
mResult = result;
mErrorCode = errorCode;
}
}
}