186 lines
7.1 KiB
Java
186 lines
7.1 KiB
Java
![]() |
/*
|
||
|
* Copyright (C) 2023 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.WorkerThread;
|
||
|
import android.os.Bundle;
|
||
|
import android.os.Parcelable;
|
||
|
import android.os.RemoteException;
|
||
|
|
||
|
import com.android.adservices.ondevicepersonalization.flags.Flags;
|
||
|
import com.android.ondevicepersonalization.internal.util.LoggerFactory;
|
||
|
import com.android.ondevicepersonalization.internal.util.OdpParceledListSlice;
|
||
|
|
||
|
import java.time.Instant;
|
||
|
import java.util.List;
|
||
|
import java.util.Objects;
|
||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||
|
import java.util.concurrent.BlockingQueue;
|
||
|
|
||
|
/**
|
||
|
* An interface to a read logs from REQUESTS and EVENTS
|
||
|
*
|
||
|
* Used as a Data Access Object for the REQUESTS and EVENTS table.
|
||
|
*
|
||
|
* @see IsolatedService#getLogReader(RequestToken)
|
||
|
*
|
||
|
*/
|
||
|
@FlaggedApi(Flags.FLAG_ON_DEVICE_PERSONALIZATION_APIS_ENABLED)
|
||
|
public class LogReader {
|
||
|
private static final String TAG = "LogReader";
|
||
|
private static final LoggerFactory.Logger sLogger = LoggerFactory.getLogger();
|
||
|
|
||
|
@NonNull
|
||
|
private final IDataAccessService mDataAccessService;
|
||
|
|
||
|
/** @hide */
|
||
|
public LogReader(@NonNull IDataAccessService binder) {
|
||
|
mDataAccessService = Objects.requireNonNull(binder);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Retrieves a List of RequestLogRecords written by this IsolatedService within
|
||
|
* the specified time range.
|
||
|
*/
|
||
|
@WorkerThread
|
||
|
@NonNull
|
||
|
public List<RequestLogRecord> getRequests(
|
||
|
@NonNull Instant startTime, @NonNull Instant endTime) {
|
||
|
final long apiStartTimeMillis = System.currentTimeMillis();
|
||
|
int responseCode = Constants.STATUS_SUCCESS;
|
||
|
long startTimeMillis = startTime.toEpochMilli();
|
||
|
long endTimeMillis = endTime.toEpochMilli();
|
||
|
if (endTimeMillis <= startTimeMillis) {
|
||
|
throw new IllegalArgumentException(
|
||
|
"endTimeMillis must be greater than startTimeMillis");
|
||
|
}
|
||
|
if (startTimeMillis < 0) {
|
||
|
throw new IllegalArgumentException("startTimeMillis must be greater than 0");
|
||
|
}
|
||
|
try {
|
||
|
Bundle params = new Bundle();
|
||
|
params.putLongArray(Constants.EXTRA_LOOKUP_KEYS,
|
||
|
new long[]{startTimeMillis, endTimeMillis});
|
||
|
OdpParceledListSlice<RequestLogRecord> result =
|
||
|
handleListLookupRequest(Constants.DATA_ACCESS_OP_GET_REQUESTS, params);
|
||
|
return result.getList();
|
||
|
} catch (RuntimeException e) {
|
||
|
responseCode = Constants.STATUS_INTERNAL_ERROR;
|
||
|
throw e;
|
||
|
} finally {
|
||
|
logApiCallStats(
|
||
|
Constants.API_NAME_LOG_READER_GET_REQUESTS,
|
||
|
System.currentTimeMillis() - apiStartTimeMillis,
|
||
|
responseCode);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Retrieves a List of EventLogRecord with its corresponding RequestLogRecord written by this
|
||
|
* IsolatedService within the specified time range.
|
||
|
*/
|
||
|
@WorkerThread
|
||
|
@NonNull
|
||
|
public List<EventLogRecord> getJoinedEvents(
|
||
|
@NonNull Instant startTime, @NonNull Instant endTime) {
|
||
|
final long apiStartTimeMillis = System.currentTimeMillis();
|
||
|
int responseCode = Constants.STATUS_SUCCESS;
|
||
|
long startTimeMillis = startTime.toEpochMilli();
|
||
|
long endTimeMillis = endTime.toEpochMilli();
|
||
|
if (endTimeMillis <= startTimeMillis) {
|
||
|
throw new IllegalArgumentException(
|
||
|
"endTimeMillis must be greater than startTimeMillis");
|
||
|
}
|
||
|
if (startTimeMillis < 0) {
|
||
|
throw new IllegalArgumentException("startTimeMillis must be greater than 0");
|
||
|
}
|
||
|
try {
|
||
|
Bundle params = new Bundle();
|
||
|
params.putLongArray(Constants.EXTRA_LOOKUP_KEYS,
|
||
|
new long[]{startTimeMillis, endTimeMillis});
|
||
|
OdpParceledListSlice<EventLogRecord> result =
|
||
|
handleListLookupRequest(Constants.DATA_ACCESS_OP_GET_JOINED_EVENTS, params);
|
||
|
return result.getList();
|
||
|
} catch (RuntimeException e) {
|
||
|
responseCode = Constants.STATUS_INTERNAL_ERROR;
|
||
|
throw e;
|
||
|
} finally {
|
||
|
logApiCallStats(
|
||
|
Constants.API_NAME_LOG_READER_GET_JOINED_EVENTS,
|
||
|
System.currentTimeMillis() - apiStartTimeMillis,
|
||
|
responseCode);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private Bundle handleAsyncRequest(int op, Bundle params) {
|
||
|
try {
|
||
|
BlockingQueue<Bundle> asyncResult = new ArrayBlockingQueue<>(1);
|
||
|
mDataAccessService.onRequest(
|
||
|
op,
|
||
|
params,
|
||
|
new IDataAccessServiceCallback.Stub() {
|
||
|
@Override
|
||
|
public void onSuccess(@NonNull Bundle result) {
|
||
|
if (result != null) {
|
||
|
asyncResult.add(result);
|
||
|
} else {
|
||
|
asyncResult.add(Bundle.EMPTY);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void onError(int errorCode) {
|
||
|
asyncResult.add(Bundle.EMPTY);
|
||
|
}
|
||
|
});
|
||
|
return asyncResult.take();
|
||
|
} catch (InterruptedException | RemoteException e) {
|
||
|
sLogger.e(TAG + ": Failed to retrieve result", e);
|
||
|
throw new IllegalStateException(e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private <T extends Parcelable> OdpParceledListSlice<T> handleListLookupRequest(int op,
|
||
|
Bundle params) {
|
||
|
Bundle result = handleAsyncRequest(op, params);
|
||
|
try {
|
||
|
OdpParceledListSlice<T> data = result.getParcelable(
|
||
|
Constants.EXTRA_RESULT, OdpParceledListSlice.class);
|
||
|
if (null == data) {
|
||
|
sLogger.e(TAG + ": No EXTRA_RESULT was present in bundle");
|
||
|
throw new IllegalStateException("Bundle missing EXTRA_RESULT.");
|
||
|
}
|
||
|
return data;
|
||
|
} catch (ClassCastException e) {
|
||
|
throw new IllegalStateException("Failed to retrieve parceled list");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void logApiCallStats(int apiName, long duration, int responseCode) {
|
||
|
try {
|
||
|
mDataAccessService.logApiCallStats(apiName, duration, responseCode);
|
||
|
} catch (Exception e) {
|
||
|
sLogger.d(e, TAG + ": failed to log metrics");
|
||
|
}
|
||
|
}
|
||
|
}
|