From 4079ea1d88b914ad9ed0b12441078e89dd77b38b Mon Sep 17 00:00:00 2001 From: Alexander Dorokhine Date: Thu, 16 Jan 2020 19:38:55 -0800 Subject: [PATCH] Add forceSetSchema and fix the setSchema API comment. Bug: 145635424 Test: atest CtsAppSearchTestCases FrameworksCoreTests:android.app.appsearch FrameworksServicesTests:com.android.server.appsearch.impl Change-Id: Ibf7f7f33226115a94efbc659c1366edd3ccb4a3c --- .../app/appsearch/AppSearchManager.java | 71 +++++++++++++------ .../app/appsearch/IAppSearchManager.aidl | 6 +- .../appsearch/AppSearchManagerService.java | 4 +- .../server/appsearch/impl/AppSearchImpl.java | 4 +- .../appsearch/impl/AppSearchImplTest.java | 4 +- 5 files changed, 61 insertions(+), 28 deletions(-) diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java index a79894fa67bc8..f594d9667e374 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java @@ -50,6 +50,47 @@ public class AppSearchManager { /** * Sets the schema being used by documents provided to the #put method. * + *

The schema provided here is compared to the stored copy of the schema previously supplied + * to {@link #setSchema}, if any, to determine how to treat existing documents. The following + * types of schema modifications are always safe and are made without deleting any existing + * documents: + *

+ * + *

The following types of schema changes are not backwards-compatible. Supplying a schema + * with such changes will result in the provided callback being called with a {@link Throwable} + * describing the incompatibility, and the previously set schema will remain active: + *

+ * + *

If you need to make non-backwards-compatible changes as described above, you may set the + * {@code force} parameter to {@code true}. In this case, all documents which are not compatible + * with the new schema will be deleted. + * *

This operation is performed asynchronously. On success, the provided callback will be * called with {@code null}. On failure, the provided callback will be called with a * {@link Throwable} describing the failure. @@ -57,36 +98,22 @@ public class AppSearchManager { *

It is a no-op to set the same schema as has been previously set; this is handled * efficiently. * - *

AppSearch automatically handles the following types of schema changes: - *

- * - *

This method will return an error when attempting to make the following types of changes: - *

- * + * @param schemas The schema configs for the types used by the calling app. + * @param force Whether to force the new schema to be applied even if there are incompatible + * changes versus the previously set schema. Documents which are incompatible with the new + * schema will be deleted. * @param executor Executor on which to invoke the callback. * @param callback Callback to receive errors resulting from setting the schema. If the * operation succeeds, the callback will be invoked with {@code null}. - * @param schemas The schema configs for the types used by the calling app. * * @hide */ // TODO(b/143789408): linkify #put after that API is created - // TODO(b/145635424): add a 'force' param to setSchema after the corresponding API is finalized - // in Icing Library - // TODO(b/145635424): Update the documentation above once the Schema mutation APIs of Icing - // Library are finalized public void setSchema( + List schemas, + boolean force, @NonNull @CallbackExecutor Executor executor, - @NonNull Consumer callback, - @NonNull AppSearchSchema... schemas) { + @NonNull Consumer callback) { // Prepare the merged schema for transmission. SchemaProto.Builder schemaProtoBuilder = SchemaProto.newBuilder(); for (AppSearchSchema schema : schemas) { @@ -99,7 +126,7 @@ public class AppSearchManager { byte[] schemaBytes = schemaProtoBuilder.build().toByteArray(); AndroidFuture future = new AndroidFuture<>(); try { - mService.setSchema(schemaBytes, future); + mService.setSchema(schemaBytes, force, future); } catch (RemoteException e) { future.completeExceptionally(e); } diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl index fc83d8ccbd4ae..5da47b22efe97 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl +++ b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl @@ -22,11 +22,13 @@ interface IAppSearchManager { /** * Sets the schema. * - * @param schemaProto serialized SchemaProto + * @param schemaProto Serialized SchemaProto. + * @param force Whether to apply the new schema even if it is incompatible. All incompatible + documents will be deleted. * @param callback {@link AndroidFuture}<{@link Void}>. Will be completed with * {@code null} upon successful completion of the setSchema call, or completed exceptionally * if setSchema fails. */ - void setSchema(in byte[] schemaProto, in AndroidFuture callback); + void setSchema(in byte[] schemaProto, boolean force, in AndroidFuture callback); void put(in byte[] documentBytes, in AndroidFuture callback); } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java index ce7e04c8ce047..1c87d01d26267 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java @@ -44,7 +44,7 @@ public class AppSearchManagerService extends SystemService { private class Stub extends IAppSearchManager.Stub { @Override - public void setSchema(byte[] schemaBytes, AndroidFuture callback) { + public void setSchema(byte[] schemaBytes, boolean force, AndroidFuture callback) { Preconditions.checkNotNull(schemaBytes); Preconditions.checkNotNull(callback); int callingUid = Binder.getCallingUidOrThrow(); @@ -53,7 +53,7 @@ public class AppSearchManagerService extends SystemService { try { SchemaProto schema = SchemaProto.parseFrom(schemaBytes); AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); - impl.setSchema(callingUid, schema); + impl.setSchema(callingUid, schema, force); callback.complete(null); } catch (Throwable t) { callback.completeExceptionally(t); diff --git a/apex/appsearch/service/java/com/android/server/appsearch/impl/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/impl/AppSearchImpl.java index 7c97b0b8cf302..e69fc8a2af639 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/impl/AppSearchImpl.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/impl/AppSearchImpl.java @@ -45,8 +45,10 @@ public final class AppSearchImpl { * * @param callingUid The uid of the app calling AppSearch. * @param origSchema The schema to set for this app. + * @param force Whether to force-apply the schema even if it is incompatible. Documents which do + * not comply with the new schema will be deleted. */ - public void setSchema(int callingUid, @NonNull SchemaProto origSchema) { + public void setSchema(int callingUid, @NonNull SchemaProto origSchema, boolean force) { // Rewrite schema type names to include the calling app's package and uid. String typePrefix = getTypePrefix(callingUid); SchemaProto.Builder schemaBuilder = origSchema.toBuilder(); diff --git a/services/tests/servicestests/src/com/android/server/appsearch/impl/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/impl/AppSearchImplTest.java index 41956794aaf21..6b0f557ad9ed3 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/impl/AppSearchImplTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/impl/AppSearchImplTest.java @@ -101,7 +101,9 @@ public class AppSearchImplTest { IllegalStateException e = expectThrows( IllegalStateException.class, () -> impl.setSchema( - /*callingUid=*/Integer.MAX_VALUE, SchemaProto.getDefaultInstance())); + /*callingUid=*/Integer.MAX_VALUE, + SchemaProto.getDefaultInstance(), + /*force=*/false)); assertThat(e).hasMessageThat().contains("Failed to look up package name"); } }