Snap for 11397440 from 318cb24be4e5cb0fb7f34e6a5cbab1d684e418e3 to mainline-ipsec-release
Change-Id: Idb672edbe7b98c506cda42bef78712ceb9c4d323
diff --git a/federatedcompute/src/com/android/federatedcompute/services/common/PhFlags.java b/federatedcompute/src/com/android/federatedcompute/services/common/PhFlags.java
index ba7cf9e..0a3cd75 100644
--- a/federatedcompute/src/com/android/federatedcompute/services/common/PhFlags.java
+++ b/federatedcompute/src/com/android/federatedcompute/services/common/PhFlags.java
@@ -49,6 +49,23 @@
static final String FCP_ENABLE_ENCRYPTION = "fcp_enable_encryption";
+ static final String MIN_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION_CONFIG_NAME =
+ "min_scheduling_interval_secs_for_federated_computation";
+
+ static final String MAX_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION_CONFIG_NAME =
+ "max_scheduling_interval_secs_for_federated_computation";
+
+ static final String DEFAULT_SCHEDULING_PERIOD_SECS_CONFIG_NAME =
+ "default_scheduling_period_secs";
+
+ static final String MAX_SCHEDULING_PERIOD_SECS_CONFIG_NAME =
+ "max_scheduling_period_secs";
+
+ static final String TRANSIENT_ERROR_RETRY_DELAY_JITTER_PERCENT_CONFIG_NAME =
+ "transient_error_retry_delay_jitter_percent";
+
+ static final String TRANSIENT_ERROR_RETRY_DELAY_SECS_CONFIG_NAME =
+ "transient_error_retry_delay_secs";
private static final PhFlags sSingleton = new PhFlags();
/** Returns the singleton instance of the PhFlags. */
@@ -114,4 +131,52 @@
/* name= */ FCP_ENABLE_ENCRYPTION,
/* defaultValue= */ ENCRYPTION_ENABLED);
}
+
+ @Override
+ public long getMinSchedulingIntervalSecsForFederatedComputation() {
+ return DeviceConfig.getLong(
+ /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ /* name= */ MIN_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION_CONFIG_NAME,
+ /* defaultValue= */ MIN_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION);
+ }
+
+ @Override
+ public long getMaxSchedulingIntervalSecsForFederatedComputation() {
+ return DeviceConfig.getLong(
+ /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ /* name= */ MAX_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION_CONFIG_NAME,
+ /* defaultValue= */ MAX_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION);
+ }
+
+ @Override
+ public long getDefaultSchedulingPeriodSecs() {
+ return DeviceConfig.getLong(
+ /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ /* name= */ DEFAULT_SCHEDULING_PERIOD_SECS_CONFIG_NAME,
+ /* defaultValue= */ DEFAULT_SCHEDULING_PERIOD_SECS);
+ }
+
+ @Override
+ public long getMaxSchedulingPeriodSecs() {
+ return DeviceConfig.getLong(
+ /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ /* name= */ MAX_SCHEDULING_PERIOD_SECS_CONFIG_NAME,
+ /* defaultValue= */ MAX_SCHEDULING_PERIOD_SECS);
+ }
+
+ @Override
+ public float getTransientErrorRetryDelayJitterPercent() {
+ return DeviceConfig.getFloat(
+ /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ /* name= */ TRANSIENT_ERROR_RETRY_DELAY_JITTER_PERCENT_CONFIG_NAME,
+ /* defaultValue= */ TRANSIENT_ERROR_RETRY_DELAY_JITTER_PERCENT);
+ }
+
+ @Override
+ public long getTransientErrorRetryDelaySecs() {
+ return DeviceConfig.getLong(
+ /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ /* name= */ TRANSIENT_ERROR_RETRY_DELAY_SECS_CONFIG_NAME,
+ /* defaultValue= */ TRANSIENT_ERROR_RETRY_DELAY_SECS);
+ }
}
diff --git a/framework/api/current.txt b/framework/api/current.txt
index 7d12fa2..0e6f776 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -204,7 +204,7 @@
@FlaggedApi("com.android.adservices.ondevicepersonalization.flags.on_device_personalization_apis_enabled") public class SurfacePackageToken {
}
- @FlaggedApi("enable_ondevicepersonalization_apis") public final class TrainingExampleRecord implements android.os.Parcelable {
+ @FlaggedApi("com.android.adservices.ondevicepersonalization.flags.on_device_personalization_apis_enabled") public final class TrainingExampleRecord implements android.os.Parcelable {
method public int describeContents();
method @Nullable public byte[] getResumptionToken();
method @Nullable public byte[] getTrainingExample();
@@ -212,7 +212,7 @@
field @NonNull public static final android.os.Parcelable.Creator<android.adservices.ondevicepersonalization.TrainingExampleRecord> CREATOR;
}
- @FlaggedApi("enable_ondevicepersonalization_apis") public static final class TrainingExampleRecord.Builder {
+ public static final class TrainingExampleRecord.Builder {
ctor public TrainingExampleRecord.Builder();
method @NonNull public android.adservices.ondevicepersonalization.TrainingExampleRecord build();
method @NonNull public android.adservices.ondevicepersonalization.TrainingExampleRecord.Builder setResumptionToken(@NonNull byte...);
diff --git a/framework/java/android/adservices/ondevicepersonalization/Constants.java b/framework/java/android/adservices/ondevicepersonalization/Constants.java
index f720716..9e9d508 100644
--- a/framework/java/android/adservices/ondevicepersonalization/Constants.java
+++ b/framework/java/android/adservices/ondevicepersonalization/Constants.java
@@ -51,13 +51,15 @@
public static final String EXTRA_LOOKUP_KEYS =
"android.ondevicepersonalization.extra.lookup_keys";
public static final String EXTRA_MIME_TYPE = "android.ondevicepersonalization.extra.mime_type";
+ public static final String EXTRA_OUTPUT_DATA =
+ "android.ondevicepersonalization.extra.output_data";
public static final String EXTRA_RESPONSE_DATA =
"android.ondevicepersonalization.extra.response_data";
+ public static final String EXTRA_RESULT = "android.ondevicepersonalization.extra.result";
+ public static final String EXTRA_SURFACE_PACKAGE_TOKEN_STRING =
+ "android.ondevicepersonalization.extra.surface_package_token_string";
public static final String EXTRA_USER_DATA = "android.ondevicepersonalization.extra.user_data";
public static final String EXTRA_VALUE = "android.ondevicepersonalization.extra.value";
- public static final String EXTRA_RESULT = "android.ondevicepersonalization.extra.result";
- public static final String KEY_ENABLE_ONDEVICEPERSONALIZATION_APIS =
- "enable_ondevicepersonalization_apis";
// Data Access Service operations.
public static final int DATA_ACCESS_OP_REMOTE_DATA_LOOKUP = 1;
diff --git a/framework/java/android/adservices/ondevicepersonalization/ExecuteOutput.java b/framework/java/android/adservices/ondevicepersonalization/ExecuteOutput.java
index fefa777..57ed941 100644
--- a/framework/java/android/adservices/ondevicepersonalization/ExecuteOutput.java
+++ b/framework/java/android/adservices/ondevicepersonalization/ExecuteOutput.java
@@ -61,6 +61,17 @@
@DataClass.PluralOf("eventLogRecord")
@NonNull private List<EventLogRecord> mEventLogRecords = Collections.emptyList();
+ /**
+ * A byte array returned by an {@link IsolatedService} to a calling app. The contents of
+ * this array is returned to the caller of
+ * {@link OnDevicePersonalizationManager#execute(ComponentName, PersistableBundle, java.util.concurrent.Executor, OutcomeReceiver)}
+ * if the (calling app package, isolated service package) pair is present in an allow list
+ * that permits data to be returned to the caller.
+ *
+ * @hide
+ */
+ @Nullable private byte[] mOutputData = null;
+
// Code below generated by codegen v1.0.23.
@@ -80,12 +91,14 @@
/* package-private */ ExecuteOutput(
@Nullable RequestLogRecord requestLogRecord,
@Nullable RenderingConfig renderingConfig,
- @NonNull List<EventLogRecord> eventLogRecords) {
+ @NonNull List<EventLogRecord> eventLogRecords,
+ @Nullable byte[] outputData) {
this.mRequestLogRecord = requestLogRecord;
this.mRenderingConfig = renderingConfig;
this.mEventLogRecords = eventLogRecords;
AnnotationValidations.validate(
NonNull.class, null, mEventLogRecords);
+ this.mOutputData = outputData;
// onConstructed(); // You can define this method to get a callback
}
@@ -122,6 +135,20 @@
return mEventLogRecords;
}
+ /**
+ * A byte array returned by an {@link IsolatedService} to a calling app. The contents of
+ * this array is returned to the caller of
+ * {@link OnDevicePersonalizationManager#execute(ComponentName, PersistableBundle, java.util.concurrent.Executor, OutcomeReceiver)}
+ * if the (calling app package, isolated service package) pair is present in an allow list
+ * that permits data to be returned to the caller.
+ *
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public @Nullable byte[] getOutputData() {
+ return mOutputData;
+ }
+
@Override
@DataClass.Generated.Member
public boolean equals(@Nullable Object o) {
@@ -137,7 +164,8 @@
return true
&& java.util.Objects.equals(mRequestLogRecord, that.mRequestLogRecord)
&& java.util.Objects.equals(mRenderingConfig, that.mRenderingConfig)
- && java.util.Objects.equals(mEventLogRecords, that.mEventLogRecords);
+ && java.util.Objects.equals(mEventLogRecords, that.mEventLogRecords)
+ && java.util.Arrays.equals(mOutputData, that.mOutputData);
}
@Override
@@ -150,6 +178,7 @@
_hash = 31 * _hash + java.util.Objects.hashCode(mRequestLogRecord);
_hash = 31 * _hash + java.util.Objects.hashCode(mRenderingConfig);
_hash = 31 * _hash + java.util.Objects.hashCode(mEventLogRecords);
+ _hash = 31 * _hash + java.util.Arrays.hashCode(mOutputData);
return _hash;
}
@@ -163,6 +192,7 @@
private @Nullable RequestLogRecord mRequestLogRecord;
private @Nullable RenderingConfig mRenderingConfig;
private @NonNull List<EventLogRecord> mEventLogRecords;
+ private @Nullable byte[] mOutputData;
private long mBuilderFieldsSet = 0L;
@@ -218,10 +248,27 @@
return this;
}
+ /**
+ * A byte array returned by an {@link IsolatedService} to a calling app. The contents of
+ * this array is returned to the caller of
+ * {@link OnDevicePersonalizationManager#execute(ComponentName, PersistableBundle, java.util.concurrent.Executor, OutcomeReceiver)}
+ * if the (calling app package, isolated service package) pair is present in an allow list
+ * that permits data to be returned to the caller.
+ *
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setOutputData(@NonNull byte... value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x8;
+ mOutputData = value;
+ return this;
+ }
+
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull ExecuteOutput build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x8; // Mark builder used
+ mBuilderFieldsSet |= 0x10; // Mark builder used
if ((mBuilderFieldsSet & 0x1) == 0) {
mRequestLogRecord = null;
@@ -232,15 +279,19 @@
if ((mBuilderFieldsSet & 0x4) == 0) {
mEventLogRecords = Collections.emptyList();
}
+ if ((mBuilderFieldsSet & 0x8) == 0) {
+ mOutputData = null;
+ }
ExecuteOutput o = new ExecuteOutput(
mRequestLogRecord,
mRenderingConfig,
- mEventLogRecords);
+ mEventLogRecords,
+ mOutputData);
return o;
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x8) != 0) {
+ if ((mBuilderFieldsSet & 0x10) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
@@ -248,10 +299,10 @@
}
@DataClass.Generated(
- time = 1705959458240L,
+ time = 1706683855882L,
codegenVersion = "1.0.23",
sourceFile = "packages/modules/OnDevicePersonalization/framework/java/android/adservices/ondevicepersonalization/ExecuteOutput.java",
- inputSignatures = "private @android.annotation.Nullable android.adservices.ondevicepersonalization.RequestLogRecord mRequestLogRecord\nprivate @android.annotation.Nullable android.adservices.ondevicepersonalization.RenderingConfig mRenderingConfig\nprivate @com.android.ondevicepersonalization.internal.util.DataClass.PluralOf(\"eventLogRecord\") @android.annotation.NonNull java.util.List<android.adservices.ondevicepersonalization.EventLogRecord> mEventLogRecords\nclass ExecuteOutput extends java.lang.Object implements []\n@com.android.ondevicepersonalization.internal.util.DataClass(genBuilder=true, genEqualsHashCode=true)")
+ inputSignatures = "private @android.annotation.Nullable android.adservices.ondevicepersonalization.RequestLogRecord mRequestLogRecord\nprivate @android.annotation.Nullable android.adservices.ondevicepersonalization.RenderingConfig mRenderingConfig\nprivate @com.android.ondevicepersonalization.internal.util.DataClass.PluralOf(\"eventLogRecord\") @android.annotation.NonNull java.util.List<android.adservices.ondevicepersonalization.EventLogRecord> mEventLogRecords\nprivate @android.annotation.Nullable byte[] mOutputData\nclass ExecuteOutput extends java.lang.Object implements []\n@com.android.ondevicepersonalization.internal.util.DataClass(genBuilder=true, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
diff --git a/framework/java/android/adservices/ondevicepersonalization/ExecuteOutputParcel.java b/framework/java/android/adservices/ondevicepersonalization/ExecuteOutputParcel.java
index 73c160c..54ba5eb 100644
--- a/framework/java/android/adservices/ondevicepersonalization/ExecuteOutputParcel.java
+++ b/framework/java/android/adservices/ondevicepersonalization/ExecuteOutputParcel.java
@@ -52,14 +52,25 @@
* If the event does not contain a {@link RequestLogRecord} emitted by this package, the
* EventLogRecord is not written.
*
- * @hide
*/
@DataClass.PluralOf("eventLogRecord")
@NonNull private List<EventLogRecord> mEventLogRecords = Collections.emptyList();
+ /**
+ * A byte array returned by an {@link IsolatedService} to a calling app. The contents of
+ * this array is returned to the caller of
+ * {@link OnDevicePersonalizationManager#execute(ComponentName, PersistableBundle, java.util.concurrent.Executor, OutcomeReceiver)}
+ * if the (calling app package, isolated service package) pair is present in an allow list
+ * that permits data to be returned to the caller.
+ *
+ * @hide
+ */
+ @Nullable private byte[] mOutputData = null;
+
/** @hide */
public ExecuteOutputParcel(@NonNull ExecuteOutput value) {
- this(value.getRequestLogRecord(), value.getRenderingConfig(), value.getEventLogRecords());
+ this(value.getRequestLogRecord(), value.getRenderingConfig(), value.getEventLogRecords(),
+ value.getOutputData());
}
@@ -93,17 +104,25 @@
* {@link EventLogRecord#getRequestLogRecord()}.
* If the event does not contain a {@link RequestLogRecord} emitted by this package, the
* EventLogRecord is not written.
+ * @param outputData
+ * A byte array returned by an {@link IsolatedService} to a calling app. The contents of
+ * this array is returned to the caller of
+ * {@link OnDevicePersonalizationManager#execute(ComponentName, PersistableBundle, java.util.concurrent.Executor, OutcomeReceiver)}
+ * if the (calling app package, isolated service package) pair is present in an allow list
+ * that permits data to be returned to the caller.
*/
@DataClass.Generated.Member
public ExecuteOutputParcel(
@Nullable RequestLogRecord requestLogRecord,
@Nullable RenderingConfig renderingConfig,
- @NonNull List<EventLogRecord> eventLogRecords) {
+ @NonNull List<EventLogRecord> eventLogRecords,
+ @Nullable byte[] outputData) {
this.mRequestLogRecord = requestLogRecord;
this.mRenderingConfig = renderingConfig;
this.mEventLogRecords = eventLogRecords;
AnnotationValidations.validate(
NonNull.class, null, mEventLogRecords);
+ this.mOutputData = outputData;
// onConstructed(); // You can define this method to get a callback
}
@@ -133,14 +152,26 @@
* {@link EventLogRecord#getRequestLogRecord()}.
* If the event does not contain a {@link RequestLogRecord} emitted by this package, the
* EventLogRecord is not written.
- *
- * @hide
*/
@DataClass.Generated.Member
public @NonNull List<EventLogRecord> getEventLogRecords() {
return mEventLogRecords;
}
+ /**
+ * A byte array returned by an {@link IsolatedService} to a calling app. The contents of
+ * this array is returned to the caller of
+ * {@link OnDevicePersonalizationManager#execute(ComponentName, PersistableBundle, java.util.concurrent.Executor, OutcomeReceiver)}
+ * if the (calling app package, isolated service package) pair is present in an allow list
+ * that permits data to be returned to the caller.
+ *
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public @Nullable byte[] getOutputData() {
+ return mOutputData;
+ }
+
@Override
@DataClass.Generated.Member
public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
@@ -154,6 +185,7 @@
if (mRequestLogRecord != null) dest.writeTypedObject(mRequestLogRecord, flags);
if (mRenderingConfig != null) dest.writeTypedObject(mRenderingConfig, flags);
dest.writeParcelableList(mEventLogRecords, flags);
+ dest.writeByteArray(mOutputData);
}
@Override
@@ -172,12 +204,14 @@
RenderingConfig renderingConfig = (flg & 0x2) == 0 ? null : (RenderingConfig) in.readTypedObject(RenderingConfig.CREATOR);
List<EventLogRecord> eventLogRecords = new java.util.ArrayList<>();
in.readParcelableList(eventLogRecords, EventLogRecord.class.getClassLoader());
+ byte[] outputData = in.createByteArray();
this.mRequestLogRecord = requestLogRecord;
this.mRenderingConfig = renderingConfig;
this.mEventLogRecords = eventLogRecords;
AnnotationValidations.validate(
NonNull.class, null, mEventLogRecords);
+ this.mOutputData = outputData;
// onConstructed(); // You can define this method to get a callback
}
@@ -197,10 +231,10 @@
};
@DataClass.Generated(
- time = 1704832029278L,
+ time = 1706684633171L,
codegenVersion = "1.0.23",
sourceFile = "packages/modules/OnDevicePersonalization/framework/java/android/adservices/ondevicepersonalization/ExecuteOutputParcel.java",
- inputSignatures = "private @android.annotation.Nullable android.adservices.ondevicepersonalization.RequestLogRecord mRequestLogRecord\nprivate @android.annotation.Nullable android.adservices.ondevicepersonalization.RenderingConfig mRenderingConfig\nprivate @com.android.ondevicepersonalization.internal.util.DataClass.PluralOf(\"eventLogRecord\") @android.annotation.NonNull java.util.List<android.adservices.ondevicepersonalization.EventLogRecord> mEventLogRecords\nclass ExecuteOutputParcel extends java.lang.Object implements [android.os.Parcelable]\n@com.android.ondevicepersonalization.internal.util.DataClass(genAidl=false, genBuilder=false)")
+ inputSignatures = "private @android.annotation.Nullable android.adservices.ondevicepersonalization.RequestLogRecord mRequestLogRecord\nprivate @android.annotation.Nullable android.adservices.ondevicepersonalization.RenderingConfig mRenderingConfig\nprivate @com.android.ondevicepersonalization.internal.util.DataClass.PluralOf(\"eventLogRecord\") @android.annotation.NonNull java.util.List<android.adservices.ondevicepersonalization.EventLogRecord> mEventLogRecords\nprivate @android.annotation.Nullable byte[] mOutputData\nclass ExecuteOutputParcel extends java.lang.Object implements [android.os.Parcelable]\n@com.android.ondevicepersonalization.internal.util.DataClass(genAidl=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/framework/java/android/adservices/ondevicepersonalization/OnDevicePersonalizationManager.java b/framework/java/android/adservices/ondevicepersonalization/OnDevicePersonalizationManager.java
index 966fcfe..d5935e1 100644
--- a/framework/java/android/adservices/ondevicepersonalization/OnDevicePersonalizationManager.java
+++ b/framework/java/android/adservices/ondevicepersonalization/OnDevicePersonalizationManager.java
@@ -16,19 +16,24 @@
package android.adservices.ondevicepersonalization;
+import static android.adservices.ondevicepersonalization.OnDevicePersonalizationPermissions.REGISTER_MEASUREMENT_EVENT;
+
import android.adservices.ondevicepersonalization.aidl.IExecuteCallback;
import android.adservices.ondevicepersonalization.aidl.IOnDevicePersonalizationManagingService;
+import android.adservices.ondevicepersonalization.aidl.IRegisterWebTriggerCallback;
import android.adservices.ondevicepersonalization.aidl.IRequestSurfacePackageCallback;
import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.OutcomeReceiver;
import android.os.PersistableBundle;
-import android.os.RemoteException;
import android.os.SystemClock;
import android.view.SurfaceControlViewHost;
@@ -138,14 +143,16 @@
IExecuteCallback callbackWrapper = new IExecuteCallback.Stub() {
@Override
public void onSuccess(
- String tokenString) {
+ Bundle callbackResult) {
executor.execute(() -> {
try {
- SurfacePackageToken token;
- if (tokenString == null || tokenString.isBlank()) {
- token = null;
- } else {
- token = new SurfacePackageToken(tokenString);
+ SurfacePackageToken token = null;
+ if (callbackResult != null) {
+ String tokenString = callbackResult.getString(
+ Constants.EXTRA_SURFACE_PACKAGE_TOKEN_STRING);
+ if (tokenString != null && !tokenString.isBlank()) {
+ token = new SurfacePackageToken(tokenString);
+ }
}
receiver.onResult(token);
} catch (Exception e) {
@@ -167,8 +174,10 @@
new CallerMetadata.Builder().setStartTimeMillis(startTimeMillis).build(),
callbackWrapper);
- } catch (RemoteException e) {
- receiver.onError(new IllegalStateException(e));
+ } catch (IllegalArgumentException | NullPointerException e) {
+ throw e;
+ } catch (Exception e) {
+ receiver.onError(e);
}
}
@@ -241,8 +250,66 @@
new CallerMetadata.Builder().setStartTimeMillis(startTimeMillis).build(),
callbackWrapper);
- } catch (RemoteException e) {
- receiver.onError(new IllegalStateException(e));
+ } catch (IllegalArgumentException | NullPointerException e) {
+ throw e;
+ } catch (Exception e) {
+ receiver.onError(e);
+ }
+ }
+
+ /**
+ * Registers a web trigger.
+ *
+ * @param destinationUrl the URL of the web page where the triggering event occurred.
+ * @param registrationUrl the URL which returned the triggering data.
+ * @param triggerHeader the payload returned by the registrationUrl in the Odp trigger header.
+ * @param appPackageName the browser app which showed the page where the triggering event
+ * occurred.
+ * @param executor the {@link Executor} on which to invoke the callback
+ * @param receiver This either returns {@code null} on success, or an exception on failure.
+ *
+ * @hide
+ */
+ @RequiresPermission(REGISTER_MEASUREMENT_EVENT)
+ public void registerWebTrigger(
+ @NonNull Uri destinationUrl,
+ @NonNull Uri registrationUrl,
+ @NonNull String triggerHeader,
+ @NonNull String appPackageName,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OutcomeReceiver<Void, Exception> receiver) {
+ Objects.requireNonNull(destinationUrl);
+ Objects.requireNonNull(registrationUrl);
+ Objects.requireNonNull(triggerHeader);
+ Objects.requireNonNull(appPackageName);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(receiver);
+ long startTimeMillis = SystemClock.elapsedRealtime();
+
+ try {
+ final IOnDevicePersonalizationManagingService service =
+ mServiceBinder.getService(executor);
+ service.registerWebTrigger(
+ destinationUrl,
+ registrationUrl,
+ triggerHeader,
+ appPackageName,
+ new CallerMetadata.Builder().setStartTimeMillis(startTimeMillis).build(),
+ new IRegisterWebTriggerCallback.Stub() {
+ @Override
+ public void onSuccess() {
+ executor.execute(() -> receiver.onResult(null));
+ }
+ @Override
+ public void onError(int errorCode) {
+ executor.execute(() -> receiver.onError(createException(errorCode)));
+ }
+ }
+ );
+ } catch (IllegalArgumentException | NullPointerException e) {
+ throw e;
+ } catch (Exception e) {
+ receiver.onError(e);
}
}
diff --git a/framework/java/android/adservices/ondevicepersonalization/SurfacePackageToken.java b/framework/java/android/adservices/ondevicepersonalization/SurfacePackageToken.java
index bb3876e..d412de9 100644
--- a/framework/java/android/adservices/ondevicepersonalization/SurfacePackageToken.java
+++ b/framework/java/android/adservices/ondevicepersonalization/SurfacePackageToken.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import com.android.adservices.ondevicepersonalization.flags.Flags;
+import com.android.internal.annotations.VisibleForTesting;
/**
* An opaque reference to content that can be displayed in a {@link android.view.SurfaceView}. This
@@ -34,7 +35,9 @@
mTokenString = tokenString;
}
- @NonNull String getTokenString() {
+ /** @hide */
+ @VisibleForTesting
+ @NonNull public String getTokenString() {
return mTokenString;
}
}
diff --git a/framework/java/android/adservices/ondevicepersonalization/TrainingExampleRecord.java b/framework/java/android/adservices/ondevicepersonalization/TrainingExampleRecord.java
index 65268c2..470a0c2 100644
--- a/framework/java/android/adservices/ondevicepersonalization/TrainingExampleRecord.java
+++ b/framework/java/android/adservices/ondevicepersonalization/TrainingExampleRecord.java
@@ -16,18 +16,17 @@
package android.adservices.ondevicepersonalization;
-import static android.adservices.ondevicepersonalization.Constants.KEY_ENABLE_ONDEVICEPERSONALIZATION_APIS;
-
import android.annotation.FlaggedApi;
import android.annotation.Nullable;
import android.os.Parcelable;
+import com.android.adservices.ondevicepersonalization.flags.Flags;
import com.android.ondevicepersonalization.internal.util.DataClass;
/**
* One record of {@link TrainingExamplesOutput}.
*/
-@FlaggedApi(KEY_ENABLE_ONDEVICEPERSONALIZATION_APIS)
+@FlaggedApi(Flags.FLAG_ON_DEVICE_PERSONALIZATION_APIS_ENABLED)
@DataClass(genBuilder = true, genAidl = false)
public final class TrainingExampleRecord implements Parcelable {
/**
@@ -35,14 +34,16 @@
* href="https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/example/example.proto">
* tensorflow.Example</a> proto. The maximum allowed example size is 50KB.
*/
- @Nullable private byte[] mTrainingExample;
+ @Nullable private byte[] mTrainingExample = null;
/**
* The resumption token byte arrays corresponding to training examples. The last processed
* example's corresponding resumption token will be passed to {@link
* IsolatedWorker#onTrainingExamples} to support resumption.
*/
- @Nullable private byte[] mResumptionToken;
+ @Nullable private byte[] mResumptionToken = null;
+
+
// Code below generated by codegen v1.0.23.
//
@@ -134,7 +135,6 @@
/**
* A builder for {@link TrainingExampleRecord}
*/
- @FlaggedApi(KEY_ENABLE_ONDEVICEPERSONALIZATION_APIS)
@SuppressWarnings("WeakerAccess")
@DataClass.Generated.Member
public static final class Builder {
@@ -144,7 +144,8 @@
private long mBuilderFieldsSet = 0L;
- public Builder(){}
+ public Builder() {
+ }
/**
* Training example byte arrays. The format is a binary serialized <a
@@ -177,6 +178,12 @@
checkNotUsed();
mBuilderFieldsSet |= 0x4; // Mark builder used
+ if ((mBuilderFieldsSet & 0x1) == 0) {
+ mTrainingExample = null;
+ }
+ if ((mBuilderFieldsSet & 0x2) == 0) {
+ mResumptionToken = null;
+ }
TrainingExampleRecord o = new TrainingExampleRecord(
mTrainingExample,
mResumptionToken);
@@ -192,7 +199,7 @@
}
@DataClass.Generated(
- time = 1705090577195L,
+ time = 1706729212797L,
codegenVersion = "1.0.23",
sourceFile = "packages/modules/OnDevicePersonalization/framework/java/android/adservices/ondevicepersonalization/TrainingExampleRecord.java",
inputSignatures = "private @android.annotation.Nullable byte[] mTrainingExample\nprivate @android.annotation.Nullable byte[] mResumptionToken\nclass TrainingExampleRecord extends java.lang.Object implements [android.os.Parcelable]\n@com.android.ondevicepersonalization.internal.util.DataClass(genBuilder=true, genAidl=false)")
diff --git a/framework/java/android/adservices/ondevicepersonalization/aidl/IExecuteCallback.aidl b/framework/java/android/adservices/ondevicepersonalization/aidl/IExecuteCallback.aidl
index ccfc91d..1132c03 100644
--- a/framework/java/android/adservices/ondevicepersonalization/aidl/IExecuteCallback.aidl
+++ b/framework/java/android/adservices/ondevicepersonalization/aidl/IExecuteCallback.aidl
@@ -16,8 +16,10 @@
package android.adservices.ondevicepersonalization.aidl;
+import android.os.Bundle;
+
/** @hide */
oneway interface IExecuteCallback {
- void onSuccess(in String result);
+ void onSuccess(in Bundle result);
void onError(int errorCode);
}
diff --git a/src/com/android/ondevicepersonalization/services/Flags.java b/src/com/android/ondevicepersonalization/services/Flags.java
index 70d6294..9e7f6c4 100644
--- a/src/com/android/ondevicepersonalization/services/Flags.java
+++ b/src/com/android/ondevicepersonalization/services/Flags.java
@@ -58,6 +58,48 @@
*/
boolean DEFAULT_SHARED_ISOLATED_PROCESS_FEATURE_ENABLED = false;
+ String DEFAULT_CALLER_APP_ALLOW_LIST =
+ "android.ondevicepersonalization,"
+ + "android.ondevicepersonalization.test.scenario,"
+ + "com.android.federatedcompute.services,"
+ + "com.android.libraries.pcc.chronicle.test,"
+ + "com.android.ondevicepersonalization,"
+ + "com.android.ondevicepersonalization.cts.e2e,"
+ + "com.android.ondevicepersonalization.federatedcomputetests,"
+ + "com.android.ondevicepersonalization.libraries.plugin,"
+ + "com.android.ondevicepersonalization.manualtests,"
+ + "com.android.ondevicepersonalization.plugintests,"
+ + "com.android.ondevicepersonalization.services,"
+ + "com.android.ondevicepersonalization.servicetests,"
+ + "com.android.ondevicepersonalization.systemserviceapitests,"
+ + "com.android.ondevicepersonalization.systemserviceimpltests,"
+ + "com.android.ondevicepersonalization.testing.sampleservice,"
+ + "com.example.odpclient,"
+ + "com.example.odpsamplenetwork,"
+ + "com.example.odptargetingapp1,"
+ + "com.example.odptargetingapp2";
+
+ String DEFAULT_ISOLATED_SERVICE_ALLOW_LIST =
+ "android.ondevicepersonalization,"
+ + "android.ondevicepersonalization.test.scenario,"
+ + "com.android.federatedcompute.services,"
+ + "com.android.libraries.pcc.chronicle.test,"
+ + "com.android.ondevicepersonalization,"
+ + "com.android.ondevicepersonalization.cts.e2e,"
+ + "com.android.ondevicepersonalization.federatedcomputetests,"
+ + "com.android.ondevicepersonalization.libraries.plugin,"
+ + "com.android.ondevicepersonalization.manualtests,"
+ + "com.android.ondevicepersonalization.plugintests,"
+ + "com.android.ondevicepersonalization.services,"
+ + "com.android.ondevicepersonalization.servicetests,"
+ + "com.android.ondevicepersonalization.systemserviceapitests,"
+ + "com.android.ondevicepersonalization.systemserviceimpltests,"
+ + "com.android.ondevicepersonalization.testing.sampleservice,"
+ + "com.example.odpclient,"
+ + "com.example.odpsamplenetwork,"
+ + "com.example.odptargetingapp1,"
+ + "com.example.odptargetingapp2";
+
default boolean getGlobalKillSwitch() {
return GLOBAL_KILL_SWITCH;
}
@@ -81,4 +123,12 @@
default boolean isSharedIsolatedProcessFeatureEnabled() {
return DEFAULT_SHARED_ISOLATED_PROCESS_FEATURE_ENABLED;
}
+
+ default String getCallerAppAllowList() {
+ return DEFAULT_CALLER_APP_ALLOW_LIST;
+ }
+
+ default String getIsolatedServiceAllowList() {
+ return DEFAULT_ISOLATED_SERVICE_ALLOW_LIST;
+ }
}
diff --git a/src/com/android/ondevicepersonalization/services/PhFlags.java b/src/com/android/ondevicepersonalization/services/PhFlags.java
index 33d6c5b..8a975c0 100644
--- a/src/com/android/ondevicepersonalization/services/PhFlags.java
+++ b/src/com/android/ondevicepersonalization/services/PhFlags.java
@@ -42,6 +42,10 @@
static final String KEY_SHARED_ISOLATED_PROCESS_FEATURE_ENABLED =
"shared_isolated_process_feature_enabled";
+ static final String KEY_CALLER_APP_ALLOW_LIST = "caller_app_allow_list";
+
+ static final String KEY_ISOLATED_SERVICE_ALLOW_LIST = "isolated_service_allow_list";
+
// OnDevicePersonalization Namespace String from DeviceConfig class
static final String NAMESPACE_ON_DEVICE_PERSONALIZATION = "on_device_personalization";
private static final PhFlags sSingleton = new PhFlags();
@@ -110,4 +114,20 @@
/* name= */ KEY_SHARED_ISOLATED_PROCESS_FEATURE_ENABLED,
/* defaultValue */ DEFAULT_SHARED_ISOLATED_PROCESS_FEATURE_ENABLED);
}
+
+ @Override
+ public String getCallerAppAllowList() {
+ return DeviceConfig.getString(
+ /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ /* name */ KEY_CALLER_APP_ALLOW_LIST,
+ /* defaultValue */ DEFAULT_CALLER_APP_ALLOW_LIST);
+ }
+
+ @Override
+ public String getIsolatedServiceAllowList() {
+ return DeviceConfig.getString(
+ /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ /* name */ KEY_ISOLATED_SERVICE_ALLOW_LIST,
+ /* defaultValue */ DEFAULT_ISOLATED_SERVICE_ALLOW_LIST);
+ }
}
diff --git a/src/com/android/ondevicepersonalization/services/request/AppRequestFlow.java b/src/com/android/ondevicepersonalization/services/request/AppRequestFlow.java
index 1b8cd29..e0d48de 100644
--- a/src/com/android/ondevicepersonalization/services/request/AppRequestFlow.java
+++ b/src/com/android/ondevicepersonalization/services/request/AppRequestFlow.java
@@ -49,6 +49,7 @@
import com.android.ondevicepersonalization.services.util.CryptUtils;
import com.android.ondevicepersonalization.services.util.LogUtils;
import com.android.ondevicepersonalization.services.util.MonotonicClock;
+import com.android.ondevicepersonalization.services.util.PrivacyUtils;
import com.android.ondevicepersonalization.services.util.StatsUtils;
import com.google.common.util.concurrent.FluentFuture;
@@ -106,6 +107,11 @@
UserPrivacyStatus privacyStatus = UserPrivacyStatus.getInstance();
return privacyStatus.isPersonalizationStatusEnabled();
}
+
+ boolean isOutputDataAllowed(
+ String servicePackageName, String appPackageName, Context context) {
+ return PrivacyUtils.isOutputDataAllowed(servicePackageName, appPackageName, context);
+ }
}
@NonNull
@@ -172,7 +178,8 @@
ListenableFuture<IsolatedServiceInfo> loadFuture =
mInjector.getProcessRunner().loadIsolatedService(
TASK_NAME, mService);
- ListenableFuture<ExecuteOutputParcel> resultFuture = FluentFuture.from(loadFuture)
+ ListenableFuture<ExecuteOutputParcel> executeResultFuture =
+ FluentFuture.from(loadFuture)
.transformAsync(
result -> executeAppRequest(result),
mInjector.getExecutor()
@@ -185,14 +192,15 @@
mInjector.getExecutor()
);
- ListenableFuture<Long> queryIdFuture = FluentFuture.from(resultFuture)
+ ListenableFuture<Long> queryIdFuture = FluentFuture.from(executeResultFuture)
.transformAsync(input -> logQuery(input), mInjector.getExecutor());
- ListenableFuture<String> resultTokenFuture =
+ ListenableFuture<Bundle> outputResultFuture =
FluentFuture.from(
- Futures.whenAllSucceed(resultFuture, queryIdFuture)
+ Futures.whenAllSucceed(executeResultFuture, queryIdFuture)
.callAsync(
- () -> createToken(resultFuture, queryIdFuture),
+ () -> createResultBundle(
+ executeResultFuture, queryIdFuture),
mInjector.getExecutor()))
.withTimeout(
mInjector.getFlags().getIsolatedServiceDeadlineSeconds(),
@@ -201,11 +209,11 @@
);
Futures.addCallback(
- resultTokenFuture,
- new FutureCallback<String>() {
+ outputResultFuture,
+ new FutureCallback<Bundle>() {
@Override
- public void onSuccess(String token) {
- sendSuccessResult(token);
+ public void onSuccess(Bundle bundle) {
+ sendSuccessResult(bundle);
}
@Override
@@ -216,7 +224,7 @@
},
mInjector.getExecutor());
- var unused = Futures.whenAllComplete(loadFuture, resultTokenFuture)
+ var unused = Futures.whenAllComplete(loadFuture, outputResultFuture)
.callAsync(() -> mInjector.getProcessRunner().unloadIsolatedService(
loadFuture.get()),
mInjector.getExecutor());
@@ -278,11 +286,11 @@
result.getEventLogRecords());
}
- private ListenableFuture<String> createToken(
+ private ListenableFuture<Bundle> createResultBundle(
ListenableFuture<ExecuteOutputParcel> resultFuture,
ListenableFuture<Long> queryIdFuture) {
try {
- sLogger.d(TAG + ": createToken() started.");
+ sLogger.d(TAG + ": createResultBundle() started.");
ExecuteOutputParcel result = Futures.getDone(resultFuture);
long queryId = Futures.getDone(queryIdFuture);
RenderingConfig renderingConfig = result.getRenderingConfig();
@@ -296,17 +304,22 @@
mService.getPackageName(), queryId);
token = CryptUtils.encrypt(wrapper);
}
-
- return Futures.immediateFuture(token);
+ Bundle bundle = new Bundle();
+ bundle.putString(Constants.EXTRA_SURFACE_PACKAGE_TOKEN_STRING, token);
+ if (mInjector.isOutputDataAllowed(
+ mService.getPackageName(), mCallingPackageName, mContext)) {
+ bundle.putByteArray(Constants.EXTRA_OUTPUT_DATA, result.getOutputData());
+ }
+ return Futures.immediateFuture(bundle);
} catch (Exception e) {
return Futures.immediateFailedFuture(e);
}
}
- private void sendSuccessResult(String resultToken) {
+ private void sendSuccessResult(Bundle result) {
int responseCode = Constants.STATUS_SUCCESS;
try {
- mCallback.onSuccess(resultToken);
+ mCallback.onSuccess(result);
} catch (RemoteException e) {
responseCode = Constants.STATUS_INTERNAL_ERROR;
sLogger.w(TAG + ": Callback error", e);
diff --git a/src/com/android/ondevicepersonalization/services/util/AllowListUtils.java b/src/com/android/ondevicepersonalization/services/util/AllowListUtils.java
new file mode 100644
index 0000000..ae8a077
--- /dev/null
+++ b/src/com/android/ondevicepersonalization/services/util/AllowListUtils.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 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 com.android.ondevicepersonalization.services.util;
+
+import android.annotation.NonNull;
+
+import java.util.Arrays;
+
+/** A utility class to check a single entity against an allow list */
+public class AllowListUtils {
+ private static final String ALLOW_ALL = "*";
+ private static final String SPLITTER = ",";
+
+ /** check if an entity is in the allow list */
+ public static boolean isAllowListed(final String entityName,
+ @NonNull final String allowList) {
+ if (ALLOW_ALL.equals(allowList)) {
+ return true;
+ }
+
+ if (entityName == null || entityName.trim().isEmpty()) {
+ return false;
+ }
+
+ return Arrays.stream(allowList.split(SPLITTER))
+ .map(String::trim)
+ .anyMatch(entityInAllowList -> entityInAllowList.equals(entityName));
+ }
+}
diff --git a/src/com/android/ondevicepersonalization/services/util/PrivacyUtils.java b/src/com/android/ondevicepersonalization/services/util/PrivacyUtils.java
new file mode 100644
index 0000000..91dc430
--- /dev/null
+++ b/src/com/android/ondevicepersonalization/services/util/PrivacyUtils.java
@@ -0,0 +1,34 @@
+/*
+ * 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 com.android.ondevicepersonalization.services.util;
+
+import android.annotation.NonNull;
+import android.content.Context;
+
+/** Privacy utils. */
+public class PrivacyUtils {
+ /** Returns true if the service is allowed to return data to the app. */
+ public static boolean isOutputDataAllowed(
+ @NonNull String servicePackageName,
+ @NonNull String appPackageName,
+ @NonNull Context context) {
+ // TODO(b/323106058): Implement.
+ return false;
+ }
+
+ private PrivacyUtils() {}
+}
diff --git a/tests/federatedcomputetests/src/com/android/federatedcompute/services/common/PhFlagsTest.java b/tests/federatedcomputetests/src/com/android/federatedcompute/services/common/PhFlagsTest.java
index 3415879..553506e 100644
--- a/tests/federatedcomputetests/src/com/android/federatedcompute/services/common/PhFlagsTest.java
+++ b/tests/federatedcomputetests/src/com/android/federatedcompute/services/common/PhFlagsTest.java
@@ -17,16 +17,28 @@
package com.android.federatedcompute.services.common;
import static com.android.federatedcompute.services.common.Flags.AUTHENTICATION_ENABLED;
+import static com.android.federatedcompute.services.common.Flags.DEFAULT_SCHEDULING_PERIOD_SECS;
import static com.android.federatedcompute.services.common.Flags.ENCRYPTION_ENABLED;
import static com.android.federatedcompute.services.common.Flags.FEDERATED_COMPUTE_GLOBAL_KILL_SWITCH;
import static com.android.federatedcompute.services.common.Flags.HTTP_REQUEST_RETRY_LIMIT;
+import static com.android.federatedcompute.services.common.Flags.MAX_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION;
+import static com.android.federatedcompute.services.common.Flags.MAX_SCHEDULING_PERIOD_SECS;
+import static com.android.federatedcompute.services.common.Flags.MIN_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION;
+import static com.android.federatedcompute.services.common.Flags.TRANSIENT_ERROR_RETRY_DELAY_JITTER_PERCENT;
+import static com.android.federatedcompute.services.common.Flags.TRANSIENT_ERROR_RETRY_DELAY_SECS;
import static com.android.federatedcompute.services.common.Flags.USE_BACKGROUND_ENCRYPTION_KEY_FETCH;
+import static com.android.federatedcompute.services.common.PhFlags.DEFAULT_SCHEDULING_PERIOD_SECS_CONFIG_NAME;
import static com.android.federatedcompute.services.common.PhFlags.ENABLE_BACKGROUND_ENCRYPTION_KEY_FETCH;
import static com.android.federatedcompute.services.common.PhFlags.FCP_ENABLE_AUTHENTICATION;
import static com.android.federatedcompute.services.common.PhFlags.FCP_ENABLE_ENCRYPTION;
import static com.android.federatedcompute.services.common.PhFlags.FEDERATED_COMPUTATION_ENCRYPTION_KEY_DOWNLOAD_URL;
import static com.android.federatedcompute.services.common.PhFlags.HTTP_REQUEST_RETRY_LIMIT_CONFIG_NAME;
import static com.android.federatedcompute.services.common.PhFlags.KEY_FEDERATED_COMPUTE_KILL_SWITCH;
+import static com.android.federatedcompute.services.common.PhFlags.MAX_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION_CONFIG_NAME;
+import static com.android.federatedcompute.services.common.PhFlags.MAX_SCHEDULING_PERIOD_SECS_CONFIG_NAME;
+import static com.android.federatedcompute.services.common.PhFlags.MIN_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION_CONFIG_NAME;
+import static com.android.federatedcompute.services.common.PhFlags.TRANSIENT_ERROR_RETRY_DELAY_JITTER_PERCENT_CONFIG_NAME;
+import static com.android.federatedcompute.services.common.PhFlags.TRANSIENT_ERROR_RETRY_DELAY_SECS_CONFIG_NAME;
import static com.google.common.truth.Truth.assertThat;
@@ -71,6 +83,31 @@
FCP_ENABLE_ENCRYPTION,
Boolean.toString(ENCRYPTION_ENABLED),
/* makeDefault= */ false);
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ MIN_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION_CONFIG_NAME,
+ Long.toString(MIN_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION),
+ /* makeDefault= */ false);
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ MAX_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION_CONFIG_NAME,
+ Long.toString(MAX_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION),
+ /* makeDefault= */ false);
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ DEFAULT_SCHEDULING_PERIOD_SECS_CONFIG_NAME,
+ Long.toString(DEFAULT_SCHEDULING_PERIOD_SECS),
+ /* makeDefault= */ false);
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ MAX_SCHEDULING_PERIOD_SECS_CONFIG_NAME,
+ Long.toString(MAX_SCHEDULING_PERIOD_SECS),
+ /* makeDefault= */ false);
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ TRANSIENT_ERROR_RETRY_DELAY_JITTER_PERCENT_CONFIG_NAME,
+ Float.toString(TRANSIENT_ERROR_RETRY_DELAY_JITTER_PERCENT),
+ /* makeDefault= */ false);
}
@Test
@@ -201,4 +238,150 @@
Flags phFlags = FlagsFactory.getFlags();
assertThat(phFlags.isAuthenticationEnabled()).isEqualTo(overrideEnableAuth);
}
+
+ @Test
+ public void testGetMinSchedulingIntervalSecsForFederatedComputation() {
+ // Without Overriding
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ MIN_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION_CONFIG_NAME,
+ Long.toString(MIN_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION),
+ /* makeDefault= */ false);
+ assertThat(FlagsFactory.getFlags().getMinSchedulingIntervalSecsForFederatedComputation())
+ .isEqualTo(MIN_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION);
+
+ // Now overriding the value from PH.
+ long overrideMinSchedulingInterval =
+ MIN_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION + 60;
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ MIN_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION_CONFIG_NAME,
+ Long.toString(overrideMinSchedulingInterval),
+ /* makeDefault= */ false);
+
+ Flags phFlags = FlagsFactory.getFlags();
+ assertThat(phFlags.getMinSchedulingIntervalSecsForFederatedComputation())
+ .isEqualTo(overrideMinSchedulingInterval);
+ }
+
+ @Test
+ public void testGetMaxSchedulingIntervalSecsForFederatedComputation() {
+ // Without Overriding
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ MAX_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION_CONFIG_NAME,
+ Long.toString(MAX_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION),
+ /* makeDefault= */ false);
+ assertThat(FlagsFactory.getFlags().getMaxSchedulingIntervalSecsForFederatedComputation())
+ .isEqualTo(MAX_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION);
+
+ // Now overriding the value from PH.
+ long overrideMaxSchedulingInterval =
+ MAX_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION + 60;
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ MAX_SCHEDULING_INTERVAL_SECS_FOR_FEDERATED_COMPUTATION_CONFIG_NAME,
+ Long.toString(overrideMaxSchedulingInterval),
+ /* makeDefault= */ false);
+
+ Flags phFlags = FlagsFactory.getFlags();
+ assertThat(phFlags.getMaxSchedulingIntervalSecsForFederatedComputation())
+ .isEqualTo(overrideMaxSchedulingInterval);
+ }
+
+ @Test
+ public void testGetDefaultSchedulingPeriodSecs() {
+ // Without Overriding
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ DEFAULT_SCHEDULING_PERIOD_SECS_CONFIG_NAME,
+ Long.toString(DEFAULT_SCHEDULING_PERIOD_SECS),
+ /* makeDefault= */ false);
+ assertThat(FlagsFactory.getFlags().getDefaultSchedulingPeriodSecs())
+ .isEqualTo(DEFAULT_SCHEDULING_PERIOD_SECS);
+
+ // Now overriding the value from PH.
+ long overrideDefaultSchedulingPeriodSecs = DEFAULT_SCHEDULING_PERIOD_SECS + 60;
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ DEFAULT_SCHEDULING_PERIOD_SECS_CONFIG_NAME,
+ Long.toString(overrideDefaultSchedulingPeriodSecs),
+ /* makeDefault= */ false);
+
+ Flags phFlags = FlagsFactory.getFlags();
+ assertThat(phFlags.getDefaultSchedulingPeriodSecs())
+ .isEqualTo(overrideDefaultSchedulingPeriodSecs);
+ }
+
+ @Test
+ public void testGetMaxSchedulingPeriodSecs() {
+ // Without Overriding
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ MAX_SCHEDULING_PERIOD_SECS_CONFIG_NAME,
+ Long.toString(MAX_SCHEDULING_PERIOD_SECS),
+ /* makeDefault= */ false);
+ assertThat(FlagsFactory.getFlags().getMaxSchedulingPeriodSecs())
+ .isEqualTo(MAX_SCHEDULING_PERIOD_SECS);
+
+ // Now overriding the value from PH.
+ long overrideMaxSchedulingPeriodSecs = MAX_SCHEDULING_PERIOD_SECS + 60;
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ MAX_SCHEDULING_PERIOD_SECS_CONFIG_NAME,
+ Long.toString(overrideMaxSchedulingPeriodSecs),
+ /* makeDefault= */ false);
+
+ Flags phFlags = FlagsFactory.getFlags();
+ assertThat(phFlags.getMaxSchedulingPeriodSecs()).isEqualTo(overrideMaxSchedulingPeriodSecs);
+ }
+
+ @Test
+ public void testGetTransientErrorRetryDelayJitterPercent() {
+ // Without Overriding
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ TRANSIENT_ERROR_RETRY_DELAY_JITTER_PERCENT_CONFIG_NAME,
+ Float.toString(TRANSIENT_ERROR_RETRY_DELAY_JITTER_PERCENT),
+ /* makeDefault= */ false);
+ assertThat(FlagsFactory.getFlags().getTransientErrorRetryDelayJitterPercent())
+ .isEqualTo(TRANSIENT_ERROR_RETRY_DELAY_JITTER_PERCENT);
+
+ // Now overriding the value from PH.
+ float overrideTransientErrorRetryDelayJitterPercent =
+ TRANSIENT_ERROR_RETRY_DELAY_JITTER_PERCENT + 0.1f;
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ TRANSIENT_ERROR_RETRY_DELAY_JITTER_PERCENT_CONFIG_NAME,
+ Float.toString(overrideTransientErrorRetryDelayJitterPercent),
+ /* makeDefault= */ false);
+
+ Flags phFlags = FlagsFactory.getFlags();
+ assertThat(phFlags.getTransientErrorRetryDelayJitterPercent())
+ .isEqualTo(overrideTransientErrorRetryDelayJitterPercent);
+ }
+
+ @Test
+ public void testGetTransientErrorRetryDelaySecs() {
+ // Without Overriding
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ TRANSIENT_ERROR_RETRY_DELAY_SECS_CONFIG_NAME,
+ Long.toString(TRANSIENT_ERROR_RETRY_DELAY_SECS),
+ /* makeDefault= */ false);
+ assertThat(FlagsFactory.getFlags().getTransientErrorRetryDelaySecs())
+ .isEqualTo(TRANSIENT_ERROR_RETRY_DELAY_SECS);
+
+ // Now overriding the value from PH.
+ long overrideTransientErrorRetryDelaySecs = TRANSIENT_ERROR_RETRY_DELAY_SECS + 15;
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ TRANSIENT_ERROR_RETRY_DELAY_SECS_CONFIG_NAME,
+ Long.toString(overrideTransientErrorRetryDelaySecs),
+ /* makeDefault= */ false);
+
+ Flags phFlags = FlagsFactory.getFlags();
+ assertThat(phFlags.getTransientErrorRetryDelaySecs())
+ .isEqualTo(overrideTransientErrorRetryDelaySecs);
+ }
}
diff --git a/tests/frameworktests/src/android/adservices/ondevicepersonalization/OnDevicePersonalizationManagerTest.java b/tests/frameworktests/src/android/adservices/ondevicepersonalization/OnDevicePersonalizationManagerTest.java
index bf9db50..a55562c 100644
--- a/tests/frameworktests/src/android/adservices/ondevicepersonalization/OnDevicePersonalizationManagerTest.java
+++ b/tests/frameworktests/src/android/adservices/ondevicepersonalization/OnDevicePersonalizationManagerTest.java
@@ -16,7 +16,10 @@
package android.adservices.ondevicepersonalization;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import android.adservices.ondevicepersonalization.aidl.IExecuteCallback;
@@ -26,6 +29,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.net.Uri;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.OutcomeReceiver;
import android.os.PersistableBundle;
@@ -47,36 +51,176 @@
@RunWith(AndroidJUnit4.class)
public final class OnDevicePersonalizationManagerTest {
private static final String TAG = "OnDevicePersonalizationManagerTest";
+ private static final String KEY_OP = "op";
private Context mContext = ApplicationProvider.getApplicationContext();
private TestServiceBinder mTestBinder = new TestServiceBinder(
IOnDevicePersonalizationManagingService.Stub.asInterface(new TestService()));
private OnDevicePersonalizationManager mManager =
new OnDevicePersonalizationManager(mContext, mTestBinder);
- private boolean mCallbackSuccess = false;
- private boolean mCallbackError = false;
- private CountDownLatch mLatch = new CountDownLatch(1);
@Test
public void testExecuteSuccess() throws Exception {
+ PersistableBundle params = new PersistableBundle();
+ params.putString(KEY_OP, "ok");
+ var receiver = new ResultReceiver<SurfacePackageToken>();
mManager.execute(
ComponentName.createRelative("com.example.service", ".Example"),
- PersistableBundle.EMPTY,
+ params,
Executors.newSingleThreadExecutor(),
- new OutcomeReceiver<SurfacePackageToken, Exception>() {
- @Override
- public void onResult(SurfacePackageToken token) {
- mCallbackSuccess = true;
- mLatch.countDown();
- }
- @Override
- public void onError(Exception e) {
- mCallbackError = true;
- mLatch.countDown();
- }
- });
- mLatch.await();
- assertTrue(mCallbackSuccess);
- assertFalse(mCallbackError);
+ receiver);
+ receiver.mLatch.await();
+ assertTrue(receiver.mCallbackSuccess);
+ assertFalse(receiver.mCallbackError);
+ assertNotNull(receiver.mResult);
+ assertEquals(receiver.mResult.getTokenString(), "aaaa");
+ }
+
+ @Test
+ public void testExecuteError() throws Exception {
+ PersistableBundle params = new PersistableBundle();
+ params.putString(KEY_OP, "error");
+ var receiver = new ResultReceiver<SurfacePackageToken>();
+ mManager.execute(
+ ComponentName.createRelative("com.example.service", ".Example"),
+ params,
+ Executors.newSingleThreadExecutor(),
+ receiver);
+ receiver.mLatch.await();
+ assertFalse(receiver.mCallbackSuccess);
+ assertTrue(receiver.mCallbackError);
+ }
+
+ @Test
+ public void testExecutePropagatesIae() throws Exception {
+ PersistableBundle params = new PersistableBundle();
+ params.putString(KEY_OP, "iae");
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> mManager.execute(
+ ComponentName.createRelative("com.example.service", ".Example"),
+ params,
+ Executors.newSingleThreadExecutor(),
+ new ResultReceiver<SurfacePackageToken>()));
+ }
+
+ @Test
+ public void testExecutePropagatesNpe() throws Exception {
+ PersistableBundle params = new PersistableBundle();
+ params.putString(KEY_OP, "npe");
+ assertThrows(
+ NullPointerException.class,
+ () -> mManager.execute(
+ ComponentName.createRelative("com.example.service", ".Example"),
+ params,
+ Executors.newSingleThreadExecutor(),
+ new ResultReceiver<SurfacePackageToken>()));
+ }
+
+ @Test
+ public void testExecuteCatchesOtherExceptions() throws Exception {
+ PersistableBundle params = new PersistableBundle();
+ params.putString(KEY_OP, "ise");
+ var receiver = new ResultReceiver<SurfacePackageToken>();
+ mManager.execute(
+ ComponentName.createRelative("com.example.service", ".Example"),
+ params,
+ Executors.newSingleThreadExecutor(),
+ receiver);
+ receiver.mLatch.await();
+ assertFalse(receiver.mCallbackSuccess);
+ assertTrue(receiver.mCallbackError);
+ assertTrue(receiver.mException instanceof IllegalStateException);
+ }
+
+ @Test
+ public void testRegisterWebTriggerSuccess() throws Exception {
+ var receiver = new ResultReceiver<Void>();
+ mManager.registerWebTrigger(
+ Uri.parse("http://example.com"),
+ Uri.parse("http://regurl"),
+ "ok",
+ "com.example.browser",
+ Executors.newSingleThreadExecutor(),
+ receiver);
+ receiver.mLatch.await();
+ assertTrue(receiver.mCallbackSuccess);
+ assertFalse(receiver.mCallbackError);
+ }
+
+ @Test
+ public void testRegisterWebTriggerError() throws Exception {
+ var receiver = new ResultReceiver<Void>();
+ mManager.registerWebTrigger(
+ Uri.parse("http://example.com"),
+ Uri.parse("http://regurl"),
+ "error",
+ "com.example.browser",
+ Executors.newSingleThreadExecutor(),
+ receiver);
+ receiver.mLatch.await();
+ assertFalse(receiver.mCallbackSuccess);
+ assertTrue(receiver.mCallbackError);
+ }
+
+ @Test
+ public void testRegisterWebTriggerPropagatesIae() throws Exception {
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> mManager.registerWebTrigger(
+ Uri.parse("http://example.com"),
+ Uri.parse("http://regurl"),
+ "iae",
+ "com.example.browser",
+ Executors.newSingleThreadExecutor(),
+ new ResultReceiver<Void>()));
+ }
+
+ @Test
+ public void testRegisterWebTriggerPropagatesNpe() throws Exception {
+ assertThrows(
+ NullPointerException.class,
+ () -> mManager.registerWebTrigger(
+ Uri.parse("http://example.com"),
+ Uri.parse("http://regurl"),
+ "npe",
+ "com.example.browser",
+ Executors.newSingleThreadExecutor(),
+ new ResultReceiver<Void>()));
+ }
+
+ @Test
+ public void testRegisterWebTriggerCatchesExceptions() throws Exception {
+ var receiver = new ResultReceiver<Void>();
+ mManager.registerWebTrigger(
+ Uri.parse("http://example.com"),
+ Uri.parse("http://regurl"),
+ "ise",
+ "com.example.browser",
+ Executors.newSingleThreadExecutor(),
+ receiver);
+ receiver.mLatch.await();
+ assertFalse(receiver.mCallbackSuccess);
+ assertTrue(receiver.mCallbackError);
+ assertTrue(receiver.mException instanceof IllegalStateException);
+ }
+
+ class ResultReceiver<T> implements OutcomeReceiver<T, Exception> {
+ boolean mCallbackSuccess = false;
+ boolean mCallbackError = false;
+ T mResult = null;
+ Exception mException = null;
+ CountDownLatch mLatch = new CountDownLatch(1);
+ @Override public void onResult(T value) {
+ mCallbackSuccess = true;
+ mResult = value;
+ mLatch.countDown();
+ }
+ @Override
+ public void onError(Exception e) {
+ mCallbackError = true;
+ mException = e;
+ mLatch.countDown();
+ }
}
class TestService extends IOnDevicePersonalizationManagingService.Stub {
@@ -93,7 +237,22 @@
CallerMetadata metadata,
IExecuteCallback callback) {
try {
- callback.onSuccess("aaaa");
+ String op = params.getString(KEY_OP);
+ if (op.equals("ok")) {
+ Bundle bundle = new Bundle();
+ bundle.putString(Constants.EXTRA_SURFACE_PACKAGE_TOKEN_STRING, "aaaa");
+ callback.onSuccess(bundle);
+ } else if (op.equals("error")) {
+ callback.onError(Constants.STATUS_INTERNAL_ERROR);
+ } else if (op.equals("iae")) {
+ throw new IllegalArgumentException();
+ } else if (op.equals("npe")) {
+ throw new NullPointerException();
+ } else if (op.equals("ise")) {
+ throw new IllegalStateException();
+ } else {
+ throw new UnsupportedOperationException();
+ }
} catch (RemoteException e) {
Log.e(TAG, "callback error", e);
}
@@ -119,7 +278,21 @@
String appPackageName,
CallerMetadata metadata,
IRegisterWebTriggerCallback callback) {
- throw new UnsupportedOperationException();
+ try {
+ if (triggerHeader.equals("error")) {
+ callback.onError(Constants.STATUS_INTERNAL_ERROR);
+ } else if (triggerHeader.equals("iae")) {
+ throw new IllegalArgumentException();
+ } else if (triggerHeader.equals("npe")) {
+ throw new NullPointerException();
+ } else if (triggerHeader.equals("ise")) {
+ throw new IllegalStateException();
+ } else {
+ callback.onSuccess();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "callback error", e);
+ }
}
}
diff --git a/tests/perftests/scenarios/src/android/federatedcompute/test/scenario/federatedcompute/TestHelper.java b/tests/perftests/scenarios/src/android/federatedcompute/test/scenario/federatedcompute/TestHelper.java
index bcf7c6a..ce32472 100644
--- a/tests/perftests/scenarios/src/android/federatedcompute/test/scenario/federatedcompute/TestHelper.java
+++ b/tests/perftests/scenarios/src/android/federatedcompute/test/scenario/federatedcompute/TestHelper.java
@@ -107,6 +107,10 @@
executeShellCommand("am kill com.google.android.ondevicepersonalization.services:"
+ "com.android.ondevicepersonalization."
+ "libraries.plugin.internal.PluginExecutorService");
+ executeShellCommand("am kill com.google.android.ondevicepersonalization.services:"
+ + "plugin_disable_art_image_:"
+ + "com.android.ondevicepersonalization."
+ + "libraries.plugin.internal.PluginExecutorService");
executeShellCommand("am kill com.google.android.federatedcompute");
executeShellCommand("am kill com.google.android.federatedcompute:"
+ "com.android.federatedcompute.services.training.IsolatedTrainingService");
diff --git a/tests/perftests/scenarios/src/android/ondevicepersonalization/test/scenario/ondevicepersonalization/DownloadHelper.java b/tests/perftests/scenarios/src/android/ondevicepersonalization/test/scenario/ondevicepersonalization/DownloadHelper.java
index 3437c6a..76be68d 100644
--- a/tests/perftests/scenarios/src/android/ondevicepersonalization/test/scenario/ondevicepersonalization/DownloadHelper.java
+++ b/tests/perftests/scenarios/src/android/ondevicepersonalization/test/scenario/ondevicepersonalization/DownloadHelper.java
@@ -76,6 +76,10 @@
executeShellCommand("am kill com.google.android.ondevicepersonalization.services:"
+ "com.android.ondevicepersonalization."
+ "libraries.plugin.internal.PluginExecutorService");
+ executeShellCommand("am kill com.google.android.ondevicepersonalization.services:"
+ + "plugin_disable_art_image_:"
+ + "com.android.ondevicepersonalization."
+ + "libraries.plugin.internal.PluginExecutorService");
SystemClock.sleep(2000);
}
public static void pressHome() {
diff --git a/tests/perftests/scenarios/src/android/ondevicepersonalization/test/scenario/ondevicepersonalization/TestAppHelper.java b/tests/perftests/scenarios/src/android/ondevicepersonalization/test/scenario/ondevicepersonalization/TestAppHelper.java
index 0b62b3e..3799498 100644
--- a/tests/perftests/scenarios/src/android/ondevicepersonalization/test/scenario/ondevicepersonalization/TestAppHelper.java
+++ b/tests/perftests/scenarios/src/android/ondevicepersonalization/test/scenario/ondevicepersonalization/TestAppHelper.java
@@ -94,6 +94,10 @@
executeShellCommand("am kill com.google.android.ondevicepersonalization.services:"
+ "com.android.ondevicepersonalization."
+ "libraries.plugin.internal.PluginExecutorService");
+ executeShellCommand("am kill com.google.android.ondevicepersonalization.services:"
+ + "plugin_disable_art_image_:"
+ + "com.android.ondevicepersonalization."
+ + "libraries.plugin.internal.PluginExecutorService");
SystemClock.sleep(2000);
}
diff --git a/tests/servicetests/src/com/android/ondevicepersonalization/services/OnDevicePersonalizationManagingServiceTest.java b/tests/servicetests/src/com/android/ondevicepersonalization/services/OnDevicePersonalizationManagingServiceTest.java
index 2124f6c..594a06e 100644
--- a/tests/servicetests/src/com/android/ondevicepersonalization/services/OnDevicePersonalizationManagingServiceTest.java
+++ b/tests/servicetests/src/com/android/ondevicepersonalization/services/OnDevicePersonalizationManagingServiceTest.java
@@ -22,6 +22,7 @@
import static org.junit.Assert.assertTrue;
import android.adservices.ondevicepersonalization.CallerMetadata;
+import android.adservices.ondevicepersonalization.Constants;
import android.adservices.ondevicepersonalization.aidl.IExecuteCallback;
import android.adservices.ondevicepersonalization.aidl.IRegisterWebTriggerCallback;
import android.adservices.ondevicepersonalization.aidl.IRequestSurfacePackageCallback;
@@ -30,6 +31,7 @@
import android.content.Intent;
import android.net.Uri;
import android.os.Binder;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.PersistableBundle;
import android.view.SurfaceControlViewHost;
@@ -537,8 +539,10 @@
private CountDownLatch mLatch = new CountDownLatch(1);
@Override
- public void onSuccess(String token) {
- mToken = token;
+ public void onSuccess(Bundle bundle) {
+ if (bundle != null) {
+ mToken = bundle.getString(Constants.EXTRA_SURFACE_PACKAGE_TOKEN_STRING);
+ }
mLatch.countDown();
}
diff --git a/tests/servicetests/src/com/android/ondevicepersonalization/services/PhFlagsTest.java b/tests/servicetests/src/com/android/ondevicepersonalization/services/PhFlagsTest.java
index f5c94b4..956324b 100644
--- a/tests/servicetests/src/com/android/ondevicepersonalization/services/PhFlagsTest.java
+++ b/tests/servicetests/src/com/android/ondevicepersonalization/services/PhFlagsTest.java
@@ -16,13 +16,17 @@
package com.android.ondevicepersonalization.services;
+import static com.android.ondevicepersonalization.services.Flags.DEFAULT_CALLER_APP_ALLOW_LIST;
+import static com.android.ondevicepersonalization.services.Flags.DEFAULT_ISOLATED_SERVICE_ALLOW_LIST;
import static com.android.ondevicepersonalization.services.Flags.DEFAULT_SHARED_ISOLATED_PROCESS_FEATURE_ENABLED;
import static com.android.ondevicepersonalization.services.Flags.DEFAULT_TRUSTED_PARTNER_APPS_LIST;
import static com.android.ondevicepersonalization.services.Flags.ENABLE_PERSONALIZATION_STATUS_OVERRIDE;
import static com.android.ondevicepersonalization.services.Flags.GLOBAL_KILL_SWITCH;
import static com.android.ondevicepersonalization.services.Flags.PERSONALIZATION_STATUS_OVERRIDE_VALUE;
+import static com.android.ondevicepersonalization.services.PhFlags.KEY_CALLER_APP_ALLOW_LIST;
import static com.android.ondevicepersonalization.services.PhFlags.KEY_ENABLE_PERSONALIZATION_STATUS_OVERRIDE;
import static com.android.ondevicepersonalization.services.PhFlags.KEY_GLOBAL_KILL_SWITCH;
+import static com.android.ondevicepersonalization.services.PhFlags.KEY_ISOLATED_SERVICE_ALLOW_LIST;
import static com.android.ondevicepersonalization.services.PhFlags.KEY_PERSONALIZATION_STATUS_OVERRIDE_VALUE;
import static com.android.ondevicepersonalization.services.PhFlags.KEY_SHARED_ISOLATED_PROCESS_FEATURE_ENABLED;
import static com.android.ondevicepersonalization.services.PhFlags.KEY_TRUSTED_PARTNER_APPS_LIST;
@@ -161,4 +165,52 @@
assertThat(FlagsFactory.getFlags().isSharedIsolatedProcessFeatureEnabled())
.isEqualTo(testIsolatedProcessFeatureEnabled);
}
+
+ @Test
+ public void testGetCallerAppAllowList() {
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ KEY_CALLER_APP_ALLOW_LIST,
+ DEFAULT_CALLER_APP_ALLOW_LIST,
+ /* makeDefault */ false);
+
+ assertThat(FlagsFactory.getFlags().getCallerAppAllowList())
+ .isEqualTo(DEFAULT_CALLER_APP_ALLOW_LIST);
+
+ final String testCallerAppAllowList =
+ "com.example.odpclient";
+
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ KEY_CALLER_APP_ALLOW_LIST,
+ testCallerAppAllowList,
+ /* makeDefault */ false);
+
+ assertThat(FlagsFactory.getFlags().getCallerAppAllowList())
+ .isEqualTo(testCallerAppAllowList);
+ }
+
+ @Test
+ public void testGetIsolatedServiceAllowList() {
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ KEY_ISOLATED_SERVICE_ALLOW_LIST,
+ DEFAULT_ISOLATED_SERVICE_ALLOW_LIST,
+ /* makeDefault */ false);
+
+ assertThat(FlagsFactory.getFlags().getIsolatedServiceAllowList())
+ .isEqualTo(DEFAULT_ISOLATED_SERVICE_ALLOW_LIST);
+
+ final String testIsolatedServiceAllowList =
+ "com.example.odpsamplenetwork";
+
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_ON_DEVICE_PERSONALIZATION,
+ KEY_ISOLATED_SERVICE_ALLOW_LIST,
+ testIsolatedServiceAllowList,
+ /* makeDefault */ false);
+
+ assertThat(FlagsFactory.getFlags().getIsolatedServiceAllowList())
+ .isEqualTo(testIsolatedServiceAllowList);
+ }
}
diff --git a/tests/servicetests/src/com/android/ondevicepersonalization/services/download/OnDevicePersonalizationDataProcessingAsyncCallableTests.java b/tests/servicetests/src/com/android/ondevicepersonalization/services/download/OnDevicePersonalizationDataProcessingAsyncCallableTests.java
index 885e1e7..6a4cf5d 100644
--- a/tests/servicetests/src/com/android/ondevicepersonalization/services/download/OnDevicePersonalizationDataProcessingAsyncCallableTests.java
+++ b/tests/servicetests/src/com/android/ondevicepersonalization/services/download/OnDevicePersonalizationDataProcessingAsyncCallableTests.java
@@ -117,7 +117,7 @@
OnDevicePersonalizationDataProcessingAsyncCallable callable =
new OnDevicePersonalizationDataProcessingAsyncCallable(mPackageName, mContext);
- callable.call().get(2000, TimeUnit.MILLISECONDS);
+ callable.call().get(5000, TimeUnit.MILLISECONDS);
Cursor cursor = dao.readAllVendorData();
List<VendorData> vendorDataList = new ArrayList<>();
while (cursor.moveToNext()) {
@@ -168,7 +168,7 @@
OnDevicePersonalizationDataProcessingAsyncCallable callable =
new OnDevicePersonalizationDataProcessingAsyncCallable(mPackageName, mContext);
- callable.call().get(2000, TimeUnit.MILLISECONDS);
+ callable.call().get(5000, TimeUnit.MILLISECONDS);
Cursor cursor = dao.readAllVendorData();
List<VendorData> vendorDataList = new ArrayList<>();
while (cursor.moveToNext()) {
diff --git a/tests/servicetests/src/com/android/ondevicepersonalization/services/request/AppRequestFlowTest.java b/tests/servicetests/src/com/android/ondevicepersonalization/services/request/AppRequestFlowTest.java
index 72e43ce..497782a 100644
--- a/tests/servicetests/src/com/android/ondevicepersonalization/services/request/AppRequestFlowTest.java
+++ b/tests/servicetests/src/com/android/ondevicepersonalization/services/request/AppRequestFlowTest.java
@@ -16,7 +16,9 @@
package com.android.ondevicepersonalization.services.request;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.adservices.ondevicepersonalization.Constants;
@@ -24,6 +26,7 @@
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
+import android.os.Bundle;
import android.os.PersistableBundle;
import androidx.test.core.app.ApplicationProvider;
@@ -64,6 +67,7 @@
private boolean mCallbackSuccess;
private boolean mCallbackError;
private int mCallbackErrorCode;
+ private Bundle mCallbackResult;
@Before
public void setup() throws Exception {
@@ -93,15 +97,49 @@
}
@Test
- public void testRunAppRequestFlow() throws Exception {
+ public void testRunAppRequestFlowOutputDataBlocked() throws Exception {
AppRequestFlow appRequestFlow = new AppRequestFlow(
"abc",
new ComponentName(mContext.getPackageName(), "com.test.TestPersonalizationService"),
PersistableBundle.EMPTY,
- new TestCallback(), mContext, 100L, new TestInjector());
+ new TestCallback(), mContext, 100L,
+ new TestInjector() {
+ @Override public boolean isOutputDataAllowed(
+ String servicePkg, String appPkg, Context context) {
+ return false;
+ }
+ });
appRequestFlow.run();
mLatch.await();
assertTrue(mCallbackSuccess);
+ assertNull(mCallbackResult.getByteArray(Constants.EXTRA_OUTPUT_DATA));
+ assertEquals(2,
+ mDbHelper.getReadableDatabase().query(QueriesContract.QueriesEntry.TABLE_NAME, null,
+ null, null, null, null, null).getCount());
+ assertEquals(1,
+ mDbHelper.getReadableDatabase().query(EventsContract.EventsEntry.TABLE_NAME, null,
+ null, null, null, null, null).getCount());
+ }
+
+ @Test
+ public void testRunAppRequestFlowOutputDataAllowed() throws Exception {
+ AppRequestFlow appRequestFlow = new AppRequestFlow(
+ "abc",
+ new ComponentName(mContext.getPackageName(), "com.test.TestPersonalizationService"),
+ PersistableBundle.EMPTY,
+ new TestCallback(), mContext, 100L,
+ new TestInjector() {
+ @Override public boolean isOutputDataAllowed(
+ String servicePkg, String appPkg, Context context) {
+ return true;
+ }
+ });
+ appRequestFlow.run();
+ mLatch.await();
+ assertTrue(mCallbackSuccess);
+ assertArrayEquals(
+ mCallbackResult.getByteArray(Constants.EXTRA_OUTPUT_DATA),
+ new byte[] {1, 2, 3});
assertEquals(2,
mDbHelper.getReadableDatabase().query(QueriesContract.QueriesEntry.TABLE_NAME, null,
null, null, null, null, null).getCount());
@@ -130,8 +168,9 @@
class TestCallback extends IExecuteCallback.Stub {
@Override
- public void onSuccess(String token) {
+ public void onSuccess(Bundle bundle) {
mCallbackSuccess = true;
+ mCallbackResult = bundle;
mLatch.countDown();
}
diff --git a/tests/servicetests/src/com/android/ondevicepersonalization/services/util/AllowListUtilsTest.java b/tests/servicetests/src/com/android/ondevicepersonalization/services/util/AllowListUtilsTest.java
new file mode 100644
index 0000000..20436a5
--- /dev/null
+++ b/tests/servicetests/src/com/android/ondevicepersonalization/services/util/AllowListUtilsTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2024 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 com.android.ondevicepersonalization.services.util;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class AllowListUtilsTest {
+ @Test
+ public void testIsAllowListed() {
+ assertTrue(AllowListUtils.isAllowListed(null, "*"));
+ assertTrue(AllowListUtils.isAllowListed("", "*"));
+ assertTrue(AllowListUtils.isAllowListed("com.android.app", "*"));
+ assertFalse(AllowListUtils.isAllowListed(null, ""));
+ assertFalse(AllowListUtils.isAllowListed(" ", ""));
+ assertFalse(AllowListUtils.isAllowListed("com.android.app ", ""));
+ assertFalse(AllowListUtils.isAllowListed("com.android.app", "android.app"));
+ assertFalse(AllowListUtils.isAllowListed("com.android.app", "com.play.app"));
+ assertFalse(AllowListUtils.isAllowListed("com.android.app",
+ "com.android.app.extension"));
+ assertFalse(AllowListUtils.isAllowListed("com.android.app ", "com.android.app"));
+ assertTrue(AllowListUtils.isAllowListed("com.android.app", "com.android.app"));
+ assertTrue(AllowListUtils.isAllowListed("com.android.app",
+ "com.play.app,com.android.app"));
+ assertFalse(AllowListUtils.isAllowListed("com.android.app",
+ "com.android.app1,com.android.app2"));
+ assertTrue(AllowListUtils.isAllowListed("com.android.app",
+ " com.android.app , com.play.app "));
+ }
+}
diff --git a/tests/servicetests/src/com/test/TestPersonalizationHandler.java b/tests/servicetests/src/com/test/TestPersonalizationHandler.java
index 5c595aa..203ec30 100644
--- a/tests/servicetests/src/com/test/TestPersonalizationHandler.java
+++ b/tests/servicetests/src/com/test/TestPersonalizationHandler.java
@@ -97,6 +97,7 @@
.setType(1)
.setRowIndex(1)
.build())
+ .setOutputData(new byte[] {1, 2, 3})
.build();
consumer.accept(result);
}