summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java16
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java12
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java78
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java19
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/GetSchemaResponse.java3
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/PackageIdentifier.java8
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java5
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/RemoveByUriRequest.java7
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/ReportSystemUsageRequest.java20
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java12
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java25
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/SearchResultPage.java5
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java21
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java25
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java35
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/StorageInfo.java4
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java6
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java12
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java3
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java301
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java7
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java81
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java11
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java28
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchSpecToProtoConverter.java10
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SetSchemaResponseToProtoConverter.java8
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/TypePropertyPathToProtoConverter.java5
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java11
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java12
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java10
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/util/PrefixUtil.java229
-rw-r--r--apex/appsearch/synced_jetpack_changeid.txt2
-rw-r--r--apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java5
-rw-r--r--core/tests/coretests/src/android/app/appsearch/external/app/AppSearchResultTest.java41
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java14
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java18
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java374
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverterTest.java155
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java37
39 files changed, 1158 insertions, 517 deletions
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java
index b66837d1f679..b06e21516cac 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java
@@ -37,6 +37,8 @@ import java.util.Objects;
* @param <ValueType> The type of result object for successful calls.
*/
public final class AppSearchResult<ValueType> implements Parcelable {
+ private static final String TAG = "AppSearchResult";
+
/**
* Result codes from {@link AppSearchSession} methods.
* @hide
@@ -246,14 +248,22 @@ public final class AppSearchResult<ValueType> implements Parcelable {
@NonNull
public static <ValueType> AppSearchResult<ValueType> throwableToFailedResult(
@NonNull Throwable t) {
- Log.d("AppSearchResult", "Converting throwable to failed result.", t);
+ // Log for traceability. NOT_FOUND is logged at VERBOSE because this error can occur during
+ // the regular operation of the system (b/183550974). Everything else is logged at DEBUG.
+ if (t instanceof AppSearchException
+ && ((AppSearchException) t).getResultCode() == RESULT_NOT_FOUND) {
+ Log.v(TAG, "Converting throwable to failed result: " + t);
+ } else {
+ Log.d(TAG, "Converting throwable to failed result.", t);
+ }
if (t instanceof AppSearchException) {
return ((AppSearchException) t).toAppSearchResult();
}
+ String exceptionClass = t.getClass().getSimpleName();
@AppSearchResult.ResultCode int resultCode;
- if (t instanceof IllegalStateException) {
+ if (t instanceof IllegalStateException || t instanceof NullPointerException) {
resultCode = AppSearchResult.RESULT_INTERNAL_ERROR;
} else if (t instanceof IllegalArgumentException) {
resultCode = AppSearchResult.RESULT_INVALID_ARGUMENT;
@@ -262,6 +272,6 @@ public final class AppSearchResult<ValueType> implements Parcelable {
} else {
resultCode = AppSearchResult.RESULT_UNKNOWN_ERROR;
}
- return AppSearchResult.newFailedResult(resultCode, t.getMessage());
+ return AppSearchResult.newFailedResult(resultCode, exceptionClass + ": " + t.getMessage());
}
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
index a8048dc5a4c4..2368bdb7466d 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
@@ -51,7 +51,7 @@ public final class AppSearchSchema {
/** @hide */
public AppSearchSchema(@NonNull Bundle bundle) {
- Preconditions.checkNotNull(bundle);
+ Objects.requireNonNull(bundle);
mBundle = bundle;
}
@@ -125,7 +125,7 @@ public final class AppSearchSchema {
/** Creates a new {@link AppSearchSchema.Builder}. */
public Builder(@NonNull String schemaType) {
- Preconditions.checkNotNull(schemaType);
+ Objects.requireNonNull(schemaType);
mSchemaType = schemaType;
}
@@ -133,7 +133,7 @@ public final class AppSearchSchema {
@NonNull
public AppSearchSchema.Builder addProperty(@NonNull PropertyConfig propertyConfig) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(propertyConfig);
+ Objects.requireNonNull(propertyConfig);
String name = propertyConfig.getName();
if (!mPropertyNames.add(name)) {
throw new IllegalSchemaException("Property defined more than once: " + name);
@@ -246,7 +246,7 @@ public final class AppSearchSchema {
@Nullable private Integer mHashCode;
PropertyConfig(@NonNull Bundle bundle) {
- mBundle = Preconditions.checkNotNull(bundle);
+ mBundle = Objects.requireNonNull(bundle);
}
@Override
@@ -712,7 +712,7 @@ public final class AppSearchSchema {
/** Returns the logical schema-type of the contents of this document property. */
@NonNull
public String getSchemaType() {
- return Preconditions.checkNotNull(mBundle.getString(SCHEMA_TYPE_FIELD));
+ return Objects.requireNonNull(mBundle.getString(SCHEMA_TYPE_FIELD));
}
/**
@@ -755,7 +755,7 @@ public final class AppSearchSchema {
@NonNull
public DocumentPropertyConfig.Builder setSchemaType(@NonNull String schemaType) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(schemaType);
+ Objects.requireNonNull(schemaType);
mBundle.putString(SCHEMA_TYPE_FIELD, schemaType);
return this;
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
index 8c9d950abe25..e3b3a859981d 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
@@ -31,6 +31,7 @@ import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Objects;
import java.util.Set;
/**
@@ -101,11 +102,11 @@ public class GenericDocument {
* @hide
*/
public GenericDocument(@NonNull Bundle bundle) {
- Preconditions.checkNotNull(bundle);
+ Objects.requireNonNull(bundle);
mBundle = bundle;
- mProperties = Preconditions.checkNotNull(bundle.getParcelable(PROPERTIES_FIELD));
- mUri = Preconditions.checkNotNull(mBundle.getString(URI_FIELD));
- mSchemaType = Preconditions.checkNotNull(mBundle.getString(SCHEMA_TYPE_FIELD));
+ mProperties = Objects.requireNonNull(bundle.getParcelable(PROPERTIES_FIELD));
+ mUri = Objects.requireNonNull(mBundle.getString(URI_FIELD));
+ mSchemaType = Objects.requireNonNull(mBundle.getString(SCHEMA_TYPE_FIELD));
mCreationTimestampMillis =
mBundle.getLong(CREATION_TIMESTAMP_MILLIS_FIELD, System.currentTimeMillis());
}
@@ -199,7 +200,7 @@ public class GenericDocument {
*/
@Nullable
public Object getProperty(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
Object property = mProperties.get(key);
if (property instanceof ArrayList) {
return getPropertyBytesArray(key);
@@ -218,7 +219,7 @@ public class GenericDocument {
*/
@Nullable
public String getPropertyString(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
String[] propertyArray = getPropertyStringArray(key);
if (propertyArray == null || propertyArray.length == 0) {
return null;
@@ -235,7 +236,7 @@ public class GenericDocument {
* there is no such key or the value is of a different type.
*/
public long getPropertyLong(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
long[] propertyArray = getPropertyLongArray(key);
if (propertyArray == null || propertyArray.length == 0) {
return 0;
@@ -252,7 +253,7 @@ public class GenericDocument {
* if there is no such key or the value is of a different type.
*/
public double getPropertyDouble(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
double[] propertyArray = getPropertyDoubleArray(key);
if (propertyArray == null || propertyArray.length == 0) {
return 0.0;
@@ -269,7 +270,7 @@ public class GenericDocument {
* false} if there is no such key or the value is of a different type.
*/
public boolean getPropertyBoolean(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
boolean[] propertyArray = getPropertyBooleanArray(key);
if (propertyArray == null || propertyArray.length == 0) {
return false;
@@ -287,7 +288,7 @@ public class GenericDocument {
*/
@Nullable
public byte[] getPropertyBytes(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
byte[][] propertyArray = getPropertyBytesArray(key);
if (propertyArray == null || propertyArray.length == 0) {
return null;
@@ -305,7 +306,7 @@ public class GenericDocument {
*/
@Nullable
public GenericDocument getPropertyDocument(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
GenericDocument[] propertyArray = getPropertyDocumentArray(key);
if (propertyArray == null || propertyArray.length == 0) {
return null;
@@ -342,7 +343,7 @@ public class GenericDocument {
*/
@Nullable
public String[] getPropertyStringArray(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
return getAndCastPropertyArray(key, String[].class);
}
@@ -355,7 +356,7 @@ public class GenericDocument {
*/
@Nullable
public long[] getPropertyLongArray(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
return getAndCastPropertyArray(key, long[].class);
}
@@ -368,7 +369,7 @@ public class GenericDocument {
*/
@Nullable
public double[] getPropertyDoubleArray(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
return getAndCastPropertyArray(key, double[].class);
}
@@ -381,7 +382,7 @@ public class GenericDocument {
*/
@Nullable
public boolean[] getPropertyBooleanArray(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
return getAndCastPropertyArray(key, boolean[].class);
}
@@ -396,7 +397,7 @@ public class GenericDocument {
@Nullable
@SuppressWarnings("unchecked")
public byte[][] getPropertyBytesArray(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
ArrayList<Bundle> bundles = getAndCastPropertyArray(key, ArrayList.class);
if (bundles == null || bundles.size() == 0) {
return null;
@@ -428,7 +429,7 @@ public class GenericDocument {
@SuppressLint("ArrayReturn")
@Nullable
public GenericDocument[] getPropertyDocumentArray(@NonNull String key) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
Parcelable[] bundles = getAndCastPropertyArray(key, Parcelable[].class);
if (bundles == null || bundles.length == 0) {
return null;
@@ -591,9 +592,9 @@ public class GenericDocument {
*/
@SuppressWarnings("unchecked")
public Builder(@NonNull String namespace, @NonNull String uri, @NonNull String schemaType) {
- Preconditions.checkNotNull(namespace);
- Preconditions.checkNotNull(uri);
- Preconditions.checkNotNull(schemaType);
+ Objects.requireNonNull(namespace);
+ Objects.requireNonNull(uri);
+ Objects.requireNonNull(schemaType);
mBuilderTypeInstance = (BuilderType) this;
mBundle.putString(GenericDocument.NAMESPACE_FIELD, namespace);
mBundle.putString(GenericDocument.URI_FIELD, uri);
@@ -682,8 +683,8 @@ public class GenericDocument {
@NonNull
public BuilderType setPropertyString(@NonNull String key, @NonNull String... values) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(key);
- Preconditions.checkNotNull(values);
+ Objects.requireNonNull(key);
+ Objects.requireNonNull(values);
putInPropertyBundle(key, values);
return mBuilderTypeInstance;
}
@@ -694,15 +695,14 @@ public class GenericDocument {
*
* @param key the key associated with the {@code values}.
* @param values the {@code boolean} values of the property.
- * @throws IllegalArgumentException if no values are provided or if values exceed maximum
- * repeated property length.
+ * @throws IllegalArgumentException if values exceed maximum repeated property length.
* @throws IllegalStateException if the builder has already been used.
*/
@NonNull
public BuilderType setPropertyBoolean(@NonNull String key, @NonNull boolean... values) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(key);
- Preconditions.checkNotNull(values);
+ Objects.requireNonNull(key);
+ Objects.requireNonNull(values);
putInPropertyBundle(key, values);
return mBuilderTypeInstance;
}
@@ -712,15 +712,14 @@ public class GenericDocument {
*
* @param key the key associated with the {@code values}.
* @param values the {@code long} values of the property.
- * @throws IllegalArgumentException if no values are provided or if values exceed maximum
- * repeated property length.
+ * @throws IllegalArgumentException if values exceed maximum repeated property length.
* @throws IllegalStateException if the builder has already been used.
*/
@NonNull
public BuilderType setPropertyLong(@NonNull String key, @NonNull long... values) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(key);
- Preconditions.checkNotNull(values);
+ Objects.requireNonNull(key);
+ Objects.requireNonNull(values);
putInPropertyBundle(key, values);
return mBuilderTypeInstance;
}
@@ -730,15 +729,14 @@ public class GenericDocument {
*
* @param key the key associated with the {@code values}.
* @param values the {@code double} values of the property.
- * @throws IllegalArgumentException if no values are provided or if values exceed maximum
- * repeated property length.
+ * @throws IllegalArgumentException if values exceed maximum repeated property length.
* @throws IllegalStateException if the builder has already been used.
*/
@NonNull
public BuilderType setPropertyDouble(@NonNull String key, @NonNull double... values) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(key);
- Preconditions.checkNotNull(values);
+ Objects.requireNonNull(key);
+ Objects.requireNonNull(values);
putInPropertyBundle(key, values);
return mBuilderTypeInstance;
}
@@ -755,8 +753,8 @@ public class GenericDocument {
@NonNull
public BuilderType setPropertyBytes(@NonNull String key, @NonNull byte[]... values) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(key);
- Preconditions.checkNotNull(values);
+ Objects.requireNonNull(key);
+ Objects.requireNonNull(values);
putInPropertyBundle(key, values);
return mBuilderTypeInstance;
}
@@ -776,8 +774,8 @@ public class GenericDocument {
public BuilderType setPropertyDocument(
@NonNull String key, @NonNull GenericDocument... values) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(key);
- Preconditions.checkNotNull(values);
+ Objects.requireNonNull(key);
+ Objects.requireNonNull(values);
putInPropertyBundle(key, values);
return mBuilderTypeInstance;
}
@@ -850,9 +848,7 @@ public class GenericDocument {
}
private static void validateRepeatedPropertyLength(@NonNull String key, int length) {
- if (length == 0) {
- throw new IllegalArgumentException("The input array is empty.");
- } else if (length > MAX_REPEATED_PROPERTY_LENGTH) {
+ if (length > MAX_REPEATED_PROPERTY_LENGTH) {
throw new IllegalArgumentException(
"Repeated property \""
+ key
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java
index 1719e14b01e3..4dc3225bd179 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java
@@ -28,6 +28,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -52,9 +53,9 @@ public final class GetByUriRequest {
@NonNull String namespace,
@NonNull Set<String> uris,
@NonNull Map<String, List<String>> typePropertyPathsMap) {
- mNamespace = Preconditions.checkNotNull(namespace);
- mUris = Preconditions.checkNotNull(uris);
- mTypePropertyPathsMap = Preconditions.checkNotNull(typePropertyPathsMap);
+ mNamespace = Objects.requireNonNull(namespace);
+ mUris = Objects.requireNonNull(uris);
+ mTypePropertyPathsMap = Objects.requireNonNull(typePropertyPathsMap);
}
/** Returns the namespace attached to the request. */
@@ -114,7 +115,7 @@ public final class GetByUriRequest {
/** Creates a {@link GetByUriRequest.Builder} instance. */
public Builder(@NonNull String namespace) {
- mNamespace = Preconditions.checkNotNull(namespace);
+ mNamespace = Objects.requireNonNull(namespace);
}
/**
@@ -124,7 +125,7 @@ public final class GetByUriRequest {
*/
@NonNull
public Builder addUris(@NonNull String... uris) {
- Preconditions.checkNotNull(uris);
+ Objects.requireNonNull(uris);
return addUris(Arrays.asList(uris));
}
@@ -136,7 +137,7 @@ public final class GetByUriRequest {
@NonNull
public Builder addUris(@NonNull Collection<String> uris) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(uris);
+ Objects.requireNonNull(uris);
mUris.addAll(uris);
return this;
}
@@ -161,11 +162,11 @@ public final class GetByUriRequest {
public Builder addProjection(
@NonNull String schemaType, @NonNull Collection<String> propertyPaths) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(schemaType);
- Preconditions.checkNotNull(propertyPaths);
+ Objects.requireNonNull(schemaType);
+ Objects.requireNonNull(propertyPaths);
List<String> propertyPathsList = new ArrayList<>(propertyPaths.size());
for (String propertyPath : propertyPaths) {
- Preconditions.checkNotNull(propertyPath);
+ Objects.requireNonNull(propertyPath);
propertyPathsList.add(propertyPath);
}
mProjectionTypePropertyPaths.put(schemaType, propertyPathsList);
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GetSchemaResponse.java b/apex/appsearch/framework/java/external/android/app/appsearch/GetSchemaResponse.java
index 1f56ef3588b1..691ef4ff939f 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/GetSchemaResponse.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/GetSchemaResponse.java
@@ -24,6 +24,7 @@ import android.util.ArraySet;
import com.android.internal.util.Preconditions;
import java.util.ArrayList;
+import java.util.Objects;
import java.util.Set;
/** The response class of {@link AppSearchSession#getSchema} */
@@ -34,7 +35,7 @@ public class GetSchemaResponse {
private final Bundle mBundle;
GetSchemaResponse(@NonNull Bundle bundle) {
- mBundle = Preconditions.checkNotNull(bundle);
+ mBundle = Objects.requireNonNull(bundle);
}
/**
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/PackageIdentifier.java b/apex/appsearch/framework/java/external/android/app/appsearch/PackageIdentifier.java
index bfb9323047c8..4f63baeeb41c 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/PackageIdentifier.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/PackageIdentifier.java
@@ -20,7 +20,7 @@ import android.annotation.NonNull;
import android.app.appsearch.util.BundleUtil;
import android.os.Bundle;
-import com.android.internal.util.Preconditions;
+import java.util.Objects;
/** This class represents a uniquely identifiable package. */
public class PackageIdentifier {
@@ -43,7 +43,7 @@ public class PackageIdentifier {
/** @hide */
public PackageIdentifier(@NonNull Bundle bundle) {
- mBundle = Preconditions.checkNotNull(bundle);
+ mBundle = Objects.requireNonNull(bundle);
}
/** @hide */
@@ -54,12 +54,12 @@ public class PackageIdentifier {
@NonNull
public String getPackageName() {
- return Preconditions.checkNotNull(mBundle.getString(PACKAGE_NAME_FIELD));
+ return Objects.requireNonNull(mBundle.getString(PACKAGE_NAME_FIELD));
}
@NonNull
public byte[] getSha256Certificate() {
- return Preconditions.checkNotNull(mBundle.getByteArray(SHA256_CERTIFICATE_FIELD));
+ return Objects.requireNonNull(mBundle.getByteArray(SHA256_CERTIFICATE_FIELD));
}
@Override
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
index 01473be062bc..b49e0e8ca2cf 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
@@ -26,6 +26,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
/**
* Encapsulates a request to index documents into an {@link AppSearchSession} database.
@@ -61,7 +62,7 @@ public final class PutDocumentsRequest {
*/
@NonNull
public Builder addGenericDocuments(@NonNull GenericDocument... documents) {
- Preconditions.checkNotNull(documents);
+ Objects.requireNonNull(documents);
return addGenericDocuments(Arrays.asList(documents));
}
@@ -74,7 +75,7 @@ public final class PutDocumentsRequest {
public Builder addGenericDocuments(
@NonNull Collection<? extends GenericDocument> documents) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(documents);
+ Objects.requireNonNull(documents);
mDocuments.addAll(documents);
return this;
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByUriRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByUriRequest.java
index 8da68c0b4898..4dcad68d49be 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByUriRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByUriRequest.java
@@ -24,6 +24,7 @@ import com.android.internal.util.Preconditions;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Objects;
import java.util.Set;
/**
@@ -65,7 +66,7 @@ public final class RemoveByUriRequest {
/** Creates a {@link RemoveByUriRequest.Builder} instance. */
public Builder(@NonNull String namespace) {
- mNamespace = Preconditions.checkNotNull(namespace);
+ mNamespace = Objects.requireNonNull(namespace);
}
/**
@@ -75,7 +76,7 @@ public final class RemoveByUriRequest {
*/
@NonNull
public Builder addUris(@NonNull String... uris) {
- Preconditions.checkNotNull(uris);
+ Objects.requireNonNull(uris);
return addUris(Arrays.asList(uris));
}
@@ -87,7 +88,7 @@ public final class RemoveByUriRequest {
@NonNull
public Builder addUris(@NonNull Collection<String> uris) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(uris);
+ Objects.requireNonNull(uris);
mUris.addAll(uris);
return this;
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/ReportSystemUsageRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/ReportSystemUsageRequest.java
index 2e152f89465f..8aff3b41cbc7 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/ReportSystemUsageRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/ReportSystemUsageRequest.java
@@ -20,6 +20,8 @@ import android.annotation.NonNull;
import com.android.internal.util.Preconditions;
+import java.util.Objects;
+
/**
* A request to report usage of a document owned by another app from a system UI surface.
*
@@ -42,10 +44,10 @@ public final class ReportSystemUsageRequest {
@NonNull String namespace,
@NonNull String uri,
long usageTimeMillis) {
- mPackageName = Preconditions.checkNotNull(packageName);
- mDatabase = Preconditions.checkNotNull(database);
- mNamespace = Preconditions.checkNotNull(namespace);
- mUri = Preconditions.checkNotNull(uri);
+ mPackageName = Objects.requireNonNull(packageName);
+ mDatabase = Objects.requireNonNull(database);
+ mNamespace = Objects.requireNonNull(namespace);
+ mUri = Objects.requireNonNull(uri);
mUsageTimeMillis = usageTimeMillis;
}
@@ -95,9 +97,9 @@ public final class ReportSystemUsageRequest {
/** Creates a {@link ReportSystemUsageRequest.Builder} instance. */
public Builder(
@NonNull String packageName, @NonNull String database, @NonNull String namespace) {
- mPackageName = Preconditions.checkNotNull(packageName);
- mDatabase = Preconditions.checkNotNull(database);
- mNamespace = Preconditions.checkNotNull(namespace);
+ mPackageName = Objects.requireNonNull(packageName);
+ mDatabase = Objects.requireNonNull(database);
+ mNamespace = Objects.requireNonNull(namespace);
}
/**
@@ -110,7 +112,7 @@ public final class ReportSystemUsageRequest {
@NonNull
public ReportSystemUsageRequest.Builder setUri(@NonNull String uri) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(uri);
+ Objects.requireNonNull(uri);
mUri = uri;
return this;
}
@@ -142,7 +144,7 @@ public final class ReportSystemUsageRequest {
@NonNull
public ReportSystemUsageRequest build() {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(mUri, "ReportUsageRequest is missing a URI");
+ Objects.requireNonNull(mUri, "ReportUsageRequest is missing a URI");
if (mUsageTimeMillis == null) {
mUsageTimeMillis = System.currentTimeMillis();
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java
index 646e73c24bd9..925bde92d69d 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java
@@ -20,6 +20,8 @@ import android.annotation.NonNull;
import com.android.internal.util.Preconditions;
+import java.util.Objects;
+
/**
* A request to report usage of a document.
*
@@ -33,8 +35,8 @@ public final class ReportUsageRequest {
private final long mUsageTimeMillis;
ReportUsageRequest(@NonNull String namespace, @NonNull String uri, long usageTimeMillis) {
- mNamespace = Preconditions.checkNotNull(namespace);
- mUri = Preconditions.checkNotNull(uri);
+ mNamespace = Objects.requireNonNull(namespace);
+ mUri = Objects.requireNonNull(uri);
mUsageTimeMillis = usageTimeMillis;
}
@@ -69,7 +71,7 @@ public final class ReportUsageRequest {
/** Creates a {@link ReportUsageRequest.Builder} instance. */
public Builder(@NonNull String namespace) {
- mNamespace = Preconditions.checkNotNull(namespace);
+ mNamespace = Objects.requireNonNull(namespace);
}
/**
@@ -82,7 +84,7 @@ public final class ReportUsageRequest {
@NonNull
public ReportUsageRequest.Builder setUri(@NonNull String uri) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(uri);
+ Objects.requireNonNull(uri);
mUri = uri;
return this;
}
@@ -114,7 +116,7 @@ public final class ReportUsageRequest {
@NonNull
public ReportUsageRequest build() {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(mUri, "ReportUsageRequest is missing a URI");
+ Objects.requireNonNull(mUri, "ReportUsageRequest is missing a URI");
if (mUsageTimeMillis == null) {
mUsageTimeMillis = System.currentTimeMillis();
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
index 55a228d94c10..432f838bc78c 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
@@ -59,7 +59,7 @@ public final class SearchResult {
/** @hide */
public SearchResult(@NonNull Bundle bundle) {
- mBundle = Preconditions.checkNotNull(bundle);
+ mBundle = Objects.requireNonNull(bundle);
}
/** @hide */
@@ -77,8 +77,7 @@ public final class SearchResult {
public GenericDocument getGenericDocument() {
if (mDocument == null) {
mDocument =
- new GenericDocument(
- Preconditions.checkNotNull(mBundle.getBundle(DOCUMENT_FIELD)));
+ new GenericDocument(Objects.requireNonNull(mBundle.getBundle(DOCUMENT_FIELD)));
}
return mDocument;
}
@@ -95,7 +94,7 @@ public final class SearchResult {
public List<MatchInfo> getMatches() {
if (mMatches == null) {
List<Bundle> matchBundles =
- Preconditions.checkNotNull(mBundle.getParcelableArrayList(MATCHES_FIELD));
+ Objects.requireNonNull(mBundle.getParcelableArrayList(MATCHES_FIELD));
mMatches = new ArrayList<>(matchBundles.size());
for (int i = 0; i < matchBundles.size(); i++) {
MatchInfo matchInfo = new MatchInfo(matchBundles.get(i), getGenericDocument());
@@ -112,7 +111,7 @@ public final class SearchResult {
*/
@NonNull
public String getPackageName() {
- return Preconditions.checkNotNull(mBundle.getString(PACKAGE_NAME_FIELD));
+ return Objects.requireNonNull(mBundle.getString(PACKAGE_NAME_FIELD));
}
/**
@@ -122,7 +121,7 @@ public final class SearchResult {
*/
@NonNull
public String getDatabaseName() {
- return Preconditions.checkNotNull(mBundle.getString(DATABASE_NAME_FIELD));
+ return Objects.requireNonNull(mBundle.getString(DATABASE_NAME_FIELD));
}
/**
@@ -169,8 +168,8 @@ public final class SearchResult {
* @param databaseName the database name the matched document belongs to.
*/
public Builder(@NonNull String packageName, @NonNull String databaseName) {
- mBundle.putString(PACKAGE_NAME_FIELD, Preconditions.checkNotNull(packageName));
- mBundle.putString(DATABASE_NAME_FIELD, Preconditions.checkNotNull(databaseName));
+ mBundle.putString(PACKAGE_NAME_FIELD, Objects.requireNonNull(packageName));
+ mBundle.putString(DATABASE_NAME_FIELD, Objects.requireNonNull(databaseName));
}
/**
@@ -312,9 +311,9 @@ public final class SearchResult {
@Nullable private MatchRange mWindowRange;
MatchInfo(@NonNull Bundle bundle, @Nullable GenericDocument document) {
- mBundle = Preconditions.checkNotNull(bundle);
+ mBundle = Objects.requireNonNull(bundle);
mDocument = document;
- mPropertyPath = Preconditions.checkNotNull(bundle.getString(PROPERTY_PATH_FIELD));
+ mPropertyPath = Objects.requireNonNull(bundle.getString(PROPERTY_PATH_FIELD));
}
/**
@@ -449,7 +448,7 @@ public final class SearchResult {
Preconditions.checkState(!mBuilt, "Builder has already been used");
mBundle.putString(
SearchResult.MatchInfo.PROPERTY_PATH_FIELD,
- Preconditions.checkNotNull(propertyPath));
+ Objects.requireNonNull(propertyPath));
return this;
}
@@ -461,7 +460,7 @@ public final class SearchResult {
@NonNull
public Builder setExactMatchRange(@NonNull MatchRange matchRange) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(matchRange);
+ Objects.requireNonNull(matchRange);
mBundle.putInt(MatchInfo.EXACT_MATCH_RANGE_LOWER_FIELD, matchRange.getStart());
mBundle.putInt(MatchInfo.EXACT_MATCH_RANGE_UPPER_FIELD, matchRange.getEnd());
return this;
@@ -475,7 +474,7 @@ public final class SearchResult {
@NonNull
public Builder setSnippetRange(@NonNull MatchRange matchRange) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(matchRange);
+ Objects.requireNonNull(matchRange);
mBundle.putInt(MatchInfo.SNIPPET_RANGE_LOWER_FIELD, matchRange.getStart());
mBundle.putInt(MatchInfo.SNIPPET_RANGE_UPPER_FIELD, matchRange.getEnd());
return this;
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResultPage.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResultPage.java
index dbd09d6bb91b..4853b5b03229 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResultPage.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResultPage.java
@@ -20,11 +20,10 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Bundle;
-import com.android.internal.util.Preconditions;
-
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
/**
* This class represents a page of {@link SearchResult}s
@@ -41,7 +40,7 @@ public class SearchResultPage {
@NonNull private final Bundle mBundle;
public SearchResultPage(@NonNull Bundle bundle) {
- mBundle = Preconditions.checkNotNull(bundle);
+ mBundle = Objects.requireNonNull(bundle);
mNextPageToken = mBundle.getLong(NEXT_PAGE_TOKEN_FIELD);
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
index 19d94305b3da..d466bf1359d0 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
@@ -34,6 +34,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -176,7 +177,7 @@ public final class SearchSpec {
/** @hide */
public SearchSpec(@NonNull Bundle bundle) {
- Preconditions.checkNotNull(bundle);
+ Objects.requireNonNull(bundle);
mBundle = bundle;
}
@@ -342,7 +343,7 @@ public final class SearchSpec {
*/
@NonNull
public Builder addFilterSchemas(@NonNull String... schemas) {
- Preconditions.checkNotNull(schemas);
+ Objects.requireNonNull(schemas);
Preconditions.checkState(!mBuilt, "Builder has already been used");
return addFilterSchemas(Arrays.asList(schemas));
}
@@ -355,7 +356,7 @@ public final class SearchSpec {
*/
@NonNull
public Builder addFilterSchemas(@NonNull Collection<String> schemas) {
- Preconditions.checkNotNull(schemas);
+ Objects.requireNonNull(schemas);
Preconditions.checkState(!mBuilt, "Builder has already been used");
mSchemas.addAll(schemas);
return this;
@@ -369,7 +370,7 @@ public final class SearchSpec {
*/
@NonNull
public Builder addFilterNamespaces(@NonNull String... namespaces) {
- Preconditions.checkNotNull(namespaces);
+ Objects.requireNonNull(namespaces);
Preconditions.checkState(!mBuilt, "Builder has already been used");
return addFilterNamespaces(Arrays.asList(namespaces));
}
@@ -382,7 +383,7 @@ public final class SearchSpec {
*/
@NonNull
public Builder addFilterNamespaces(@NonNull Collection<String> namespaces) {
- Preconditions.checkNotNull(namespaces);
+ Objects.requireNonNull(namespaces);
Preconditions.checkState(!mBuilt, "Builder has already been used");
mNamespaces.addAll(namespaces);
return this;
@@ -398,7 +399,7 @@ public final class SearchSpec {
*/
@NonNull
public Builder addFilterPackageNames(@NonNull String... packageNames) {
- Preconditions.checkNotNull(packageNames);
+ Objects.requireNonNull(packageNames);
Preconditions.checkState(!mBuilt, "Builder has already been used");
return addFilterPackageNames(Arrays.asList(packageNames));
}
@@ -413,7 +414,7 @@ public final class SearchSpec {
*/
@NonNull
public Builder addFilterPackageNames(@NonNull Collection<String> packageNames) {
- Preconditions.checkNotNull(packageNames);
+ Objects.requireNonNull(packageNames);
Preconditions.checkState(!mBuilt, "Builder has already been used");
mPackageNames.addAll(packageNames);
return this;
@@ -586,11 +587,11 @@ public final class SearchSpec {
public SearchSpec.Builder addProjection(
@NonNull String schema, @NonNull Collection<String> propertyPaths) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(schema);
- Preconditions.checkNotNull(propertyPaths);
+ Objects.requireNonNull(schema);
+ Objects.requireNonNull(propertyPaths);
ArrayList<String> propertyPathsArrayList = new ArrayList<>(propertyPaths.size());
for (String propertyPath : propertyPaths) {
- Preconditions.checkNotNull(propertyPath);
+ Objects.requireNonNull(propertyPath);
propertyPathsArrayList.add(propertyPath);
}
mProjectionTypePropertyMasks.putStringArrayList(schema, propertyPathsArrayList);
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
index 5672bc7fdc13..8f7a0bf61f3e 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
@@ -28,6 +28,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -94,10 +95,10 @@ public final class SetSchemaRequest {
@NonNull Map<String, Migrator> migrators,
boolean forceOverride,
int version) {
- mSchemas = Preconditions.checkNotNull(schemas);
- mSchemasNotDisplayedBySystem = Preconditions.checkNotNull(schemasNotDisplayedBySystem);
- mSchemasVisibleToPackages = Preconditions.checkNotNull(schemasVisibleToPackages);
- mMigrators = Preconditions.checkNotNull(migrators);
+ mSchemas = Objects.requireNonNull(schemas);
+ mSchemasNotDisplayedBySystem = Objects.requireNonNull(schemasNotDisplayedBySystem);
+ mSchemasVisibleToPackages = Objects.requireNonNull(schemasVisibleToPackages);
+ mMigrators = Objects.requireNonNull(migrators);
mForceOverride = forceOverride;
mVersion = version;
}
@@ -192,7 +193,7 @@ public final class SetSchemaRequest {
*/
@NonNull
public Builder addSchemas(@NonNull AppSearchSchema... schemas) {
- Preconditions.checkNotNull(schemas);
+ Objects.requireNonNull(schemas);
return addSchemas(Arrays.asList(schemas));
}
@@ -206,7 +207,7 @@ public final class SetSchemaRequest {
@NonNull
public Builder addSchemas(@NonNull Collection<AppSearchSchema> schemas) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(schemas);
+ Objects.requireNonNull(schemas);
mSchemas.addAll(schemas);
return this;
}
@@ -231,7 +232,7 @@ public final class SetSchemaRequest {
@NonNull
public Builder setSchemaTypeDisplayedBySystem(
@NonNull String schemaType, boolean displayed) {
- Preconditions.checkNotNull(schemaType);
+ Objects.requireNonNull(schemaType);
Preconditions.checkState(!mBuilt, "Builder has already been used");
if (displayed) {
@@ -270,8 +271,8 @@ public final class SetSchemaRequest {
@NonNull String schemaType,
boolean visible,
@NonNull PackageIdentifier packageIdentifier) {
- Preconditions.checkNotNull(schemaType);
- Preconditions.checkNotNull(packageIdentifier);
+ Objects.requireNonNull(schemaType);
+ Objects.requireNonNull(packageIdentifier);
Preconditions.checkState(!mBuilt, "Builder has already been used");
Set<PackageIdentifier> packageIdentifiers = mSchemasVisibleToPackages.get(schemaType);
@@ -321,8 +322,8 @@ public final class SetSchemaRequest {
@NonNull
@SuppressLint("MissingGetterMatchingBuilder") // Getter return plural objects.
public Builder setMigrator(@NonNull String schemaType, @NonNull Migrator migrator) {
- Preconditions.checkNotNull(schemaType);
- Preconditions.checkNotNull(migrator);
+ Objects.requireNonNull(schemaType);
+ Objects.requireNonNull(migrator);
mMigrators.put(schemaType, migrator);
return this;
}
@@ -350,7 +351,7 @@ public final class SetSchemaRequest {
*/
@NonNull
public Builder setMigrators(@NonNull Map<String, Migrator> migrators) {
- Preconditions.checkNotNull(migrators);
+ Objects.requireNonNull(migrators);
mMigrators.putAll(migrators);
return this;
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java
index d63e4372f61f..7be589f727ce 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java
@@ -27,6 +27,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
/** The response class of {@link AppSearchSession#setSchema} */
@@ -61,8 +62,8 @@ public class SetSchemaResponse {
@Nullable private Set<String> mIncompatibleTypes;
SetSchemaResponse(@NonNull Bundle bundle, @NonNull List<MigrationFailure> migrationFailures) {
- mBundle = Preconditions.checkNotNull(bundle);
- mMigrationFailures = Preconditions.checkNotNull(migrationFailures);
+ mBundle = Objects.requireNonNull(bundle);
+ mMigrationFailures = Objects.requireNonNull(migrationFailures);
}
SetSchemaResponse(@NonNull Bundle bundle) {
@@ -103,7 +104,7 @@ public class SetSchemaResponse {
if (mDeletedTypes == null) {
mDeletedTypes =
new ArraySet<>(
- Preconditions.checkNotNull(
+ Objects.requireNonNull(
mBundle.getStringArrayList(DELETED_TYPES_FIELD)));
}
return Collections.unmodifiableSet(mDeletedTypes);
@@ -118,7 +119,7 @@ public class SetSchemaResponse {
if (mMigratedTypes == null) {
mMigratedTypes =
new ArraySet<>(
- Preconditions.checkNotNull(
+ Objects.requireNonNull(
mBundle.getStringArrayList(MIGRATED_TYPES_FIELD)));
}
return Collections.unmodifiableSet(mMigratedTypes);
@@ -139,7 +140,7 @@ public class SetSchemaResponse {
if (mIncompatibleTypes == null) {
mIncompatibleTypes =
new ArraySet<>(
- Preconditions.checkNotNull(
+ Objects.requireNonNull(
mBundle.getStringArrayList(INCOMPATIBLE_TYPES_FIELD)));
}
return Collections.unmodifiableSet(mIncompatibleTypes);
@@ -173,7 +174,7 @@ public class SetSchemaResponse {
public Builder addMigrationFailures(
@NonNull Collection<MigrationFailure> migrationFailures) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mMigrationFailures.addAll(Preconditions.checkNotNull(migrationFailures));
+ mMigrationFailures.addAll(Objects.requireNonNull(migrationFailures));
return this;
}
@@ -181,7 +182,7 @@ public class SetSchemaResponse {
@NonNull
public Builder addMigrationFailure(@NonNull MigrationFailure migrationFailure) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mMigrationFailures.add(Preconditions.checkNotNull(migrationFailure));
+ mMigrationFailures.add(Objects.requireNonNull(migrationFailure));
return this;
}
@@ -189,7 +190,7 @@ public class SetSchemaResponse {
@NonNull
public Builder addDeletedTypes(@NonNull Collection<String> deletedTypes) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mDeletedTypes.addAll(Preconditions.checkNotNull(deletedTypes));
+ mDeletedTypes.addAll(Objects.requireNonNull(deletedTypes));
return this;
}
@@ -197,7 +198,7 @@ public class SetSchemaResponse {
@NonNull
public Builder addDeletedType(@NonNull String deletedType) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mDeletedTypes.add(Preconditions.checkNotNull(deletedType));
+ mDeletedTypes.add(Objects.requireNonNull(deletedType));
return this;
}
@@ -205,7 +206,7 @@ public class SetSchemaResponse {
@NonNull
public Builder addIncompatibleTypes(@NonNull Collection<String> incompatibleTypes) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mIncompatibleTypes.addAll(Preconditions.checkNotNull(incompatibleTypes));
+ mIncompatibleTypes.addAll(Objects.requireNonNull(incompatibleTypes));
return this;
}
@@ -213,7 +214,7 @@ public class SetSchemaResponse {
@NonNull
public Builder addIncompatibleType(@NonNull String incompatibleType) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mIncompatibleTypes.add(Preconditions.checkNotNull(incompatibleType));
+ mIncompatibleTypes.add(Objects.requireNonNull(incompatibleType));
return this;
}
@@ -221,7 +222,7 @@ public class SetSchemaResponse {
@NonNull
public Builder addMigratedTypes(@NonNull Collection<String> migratedTypes) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mMigratedTypes.addAll(Preconditions.checkNotNull(migratedTypes));
+ mMigratedTypes.addAll(Objects.requireNonNull(migratedTypes));
return this;
}
@@ -229,7 +230,7 @@ public class SetSchemaResponse {
@NonNull
public Builder addMigratedType(@NonNull String migratedType) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mMigratedTypes.add(Preconditions.checkNotNull(migratedType));
+ mMigratedTypes.add(Objects.requireNonNull(migratedType));
return this;
}
@@ -318,7 +319,7 @@ public class SetSchemaResponse {
@NonNull
public Builder setSchemaType(@NonNull String schemaType) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mSchemaType = Preconditions.checkNotNull(schemaType);
+ mSchemaType = Objects.requireNonNull(schemaType);
return this;
}
@@ -326,7 +327,7 @@ public class SetSchemaResponse {
@NonNull
public Builder setNamespace(@NonNull String namespace) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mNamespace = Preconditions.checkNotNull(namespace);
+ mNamespace = Objects.requireNonNull(namespace);
return this;
}
@@ -334,7 +335,7 @@ public class SetSchemaResponse {
@NonNull
public Builder setUri(@NonNull String uri) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- mUri = Preconditions.checkNotNull(uri);
+ mUri = Objects.requireNonNull(uri);
return this;
}
@@ -343,7 +344,7 @@ public class SetSchemaResponse {
public Builder setAppSearchResult(@NonNull AppSearchResult<Void> appSearchResult) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkState(!appSearchResult.isSuccess(), "Input a success result");
- mFailureResult = Preconditions.checkNotNull(appSearchResult);
+ mFailureResult = Objects.requireNonNull(appSearchResult);
return this;
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/StorageInfo.java b/apex/appsearch/framework/java/external/android/app/appsearch/StorageInfo.java
index dc04cf3068ce..502b9391893f 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/StorageInfo.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/StorageInfo.java
@@ -21,6 +21,8 @@ import android.os.Bundle;
import com.android.internal.util.Preconditions;
+import java.util.Objects;
+
/** The response class of {@code AppSearchSession#getStorageInfo}. */
public class StorageInfo {
@@ -31,7 +33,7 @@ public class StorageInfo {
private final Bundle mBundle;
StorageInfo(@NonNull Bundle bundle) {
- mBundle = Preconditions.checkNotNull(bundle);
+ mBundle = Objects.requireNonNull(bundle);
}
/**
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java b/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java
index 32d7e043e954..10e014bf9c9a 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java
@@ -37,7 +37,11 @@ import java.util.Set;
public final class SchemaMigrationUtil {
private SchemaMigrationUtil() {}
- /** Returns all active {@link Migrator}s that need to be triggered in this migration. */
+ /**
+ * Returns all active {@link Migrator}s that need to be triggered in this migration.
+ *
+ * <p>{@link Migrator#shouldMigrate} returns {@code true} will make the {@link Migrator} active.
+ */
@NonNull
public static Map<String, Migrator> getActiveMigrators(
@NonNull Set<AppSearchSchema> existingSchemas,
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 509877e21862..11eb5ca7909b 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -64,6 +64,8 @@ import com.android.server.appsearch.external.localstorage.stats.CallStats;
import com.android.server.appsearch.stats.LoggerInstanceManager;
import com.android.server.appsearch.stats.PlatformLogger;
+import com.google.android.icing.proto.PersistType;
+
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
@@ -364,6 +366,8 @@ public class AppSearchManagerService extends SystemService {
++operationFailureCount;
}
}
+ // Now that the batch has been written. Persist the newly written data.
+ impl.persistToDisk(PersistType.Code.LITE);
invokeCallbackOnResult(callback, resultBuilder.build());
} catch (Throwable t) {
invokeCallbackOnError(callback, t);
@@ -631,7 +635,7 @@ public class AppSearchManagerService extends SystemService {
}
}
}
- impl.persistToDisk();
+ impl.persistToDisk(PersistType.Code.FULL);
invokeCallbackOnResult(callback,
AppSearchResult.newSuccessfulResult(migrationFailureBundles));
} catch (Throwable t) {
@@ -708,6 +712,8 @@ public class AppSearchManagerService extends SystemService {
resultBuilder.setResult(uri, throwableToFailedResult(t));
}
}
+ // Now that the batch has been written. Persist the newly written data.
+ impl.persistToDisk(PersistType.Code.LITE);
invokeCallbackOnResult(callback, resultBuilder.build());
} catch (Throwable t) {
invokeCallbackOnError(callback, t);
@@ -741,6 +747,8 @@ public class AppSearchManagerService extends SystemService {
databaseName,
queryExpression,
new SearchSpec(searchSpecBundle));
+ // Now that the batch has been written. Persist the newly written data.
+ impl.persistToDisk(PersistType.Code.LITE);
invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
} catch (Throwable t) {
invokeCallbackOnError(callback, t);
@@ -785,7 +793,7 @@ public class AppSearchManagerService extends SystemService {
verifyUserUnlocked(callingUserId);
AppSearchImpl impl =
mImplInstanceManager.getAppSearchImpl(callingUserId);
- impl.persistToDisk();
+ impl.persistToDisk(PersistType.Code.FULL);
} catch (Throwable t) {
Log.e(TAG, "Unable to persist the data to disk", t);
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java b/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java
index 1ed26d670f36..c1b829428467 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java
@@ -36,6 +36,7 @@ import android.util.ArraySet;
import android.util.Log;
import com.android.internal.util.Preconditions;
+import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
import java.util.ArrayList;
import java.util.Arrays;
@@ -153,7 +154,7 @@ public class VisibilityStore {
* AppSearchImpl.
*/
static final String VISIBILITY_STORE_PREFIX =
- AppSearchImpl.createPrefix(PACKAGE_NAME, DATABASE_NAME);
+ PrefixUtil.createPrefix(PACKAGE_NAME, DATABASE_NAME);
/** Namespace of documents that contain visibility settings */
private static final String NAMESPACE = "";
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
index 5f8cbee3dee3..50ac054a05fc 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
@@ -16,10 +16,18 @@
package com.android.server.appsearch.external.localstorage;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.addPrefixToDocument;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.createPackagePrefix;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.createPrefix;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.getDatabaseName;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.getPackageName;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.getPrefix;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.removePrefix;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.removePrefixesFromDocument;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.WorkerThread;
-import android.app.appsearch.AppSearchResult;
import android.app.appsearch.AppSearchSchema;
import android.app.appsearch.GenericDocument;
import android.app.appsearch.GetByUriRequest;
@@ -39,7 +47,6 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
import com.android.server.appsearch.external.localstorage.converter.GenericDocumentToProtoConverter;
import com.android.server.appsearch.external.localstorage.converter.ResultCodeToProtoConverter;
import com.android.server.appsearch.external.localstorage.converter.SchemaToProtoConverter;
@@ -66,7 +73,6 @@ import com.google.android.icing.proto.OptimizeResultProto;
import com.google.android.icing.proto.PersistToDiskResultProto;
import com.google.android.icing.proto.PersistType;
import com.google.android.icing.proto.PropertyConfigProto;
-import com.google.android.icing.proto.PropertyProto;
import com.google.android.icing.proto.PutResultProto;
import com.google.android.icing.proto.ReportUsageResultProto;
import com.google.android.icing.proto.ResetResultProto;
@@ -89,6 +95,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -132,10 +139,6 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
public final class AppSearchImpl implements Closeable {
private static final String TAG = "AppSearchImpl";
- @VisibleForTesting static final char DATABASE_DELIMITER = '/';
-
- @VisibleForTesting static final char PACKAGE_DELIMITER = '$';
-
@VisibleForTesting static final int OPTIMIZE_THRESHOLD_DOC_COUNT = 1000;
@VisibleForTesting static final int OPTIMIZE_THRESHOLD_BYTES = 1_000_000; // 1MB
@VisibleForTesting static final int CHECK_OPTIMIZE_INTERVAL = 100;
@@ -148,11 +151,12 @@ public final class AppSearchImpl implements Closeable {
@GuardedBy("mReadWriteLock")
private final VisibilityStore mVisibilityStoreLocked;
- // This map contains schemaTypes for all package-database prefixes. All values in the map are
- // prefixed with the package-database prefix.
- // TODO(b/172360376): Check if this can be replaced with an ArrayMap
+ // This map contains schema types and SchemaTypeConfigProtos for all package-database
+ // prefixes. It maps each package-database prefix to an inner-map. The inner-map maps each
+ // prefixed schema type to its respective SchemaTypeConfigProto.
@GuardedBy("mReadWriteLock")
- private final Map<String, Set<String>> mSchemaMapLocked = new HashMap<>();
+ private final Map<String, Map<String, SchemaTypeConfigProto>> mSchemaMapLocked =
+ new ArrayMap<>();
// This map contains namespaces for all package-database prefixes. All values in the map are
// prefixed with the package-database prefix.
@@ -182,9 +186,9 @@ public final class AppSearchImpl implements Closeable {
int userId,
@NonNull String globalQuerierPackage)
throws AppSearchException {
- Preconditions.checkNotNull(icingDir);
- Preconditions.checkNotNull(context);
- Preconditions.checkNotNull(globalQuerierPackage);
+ Objects.requireNonNull(icingDir);
+ Objects.requireNonNull(context);
+ Objects.requireNonNull(globalQuerierPackage);
AppSearchImpl appSearchImpl =
new AppSearchImpl(icingDir, context, userId, globalQuerierPackage);
appSearchImpl.initializeVisibilityStore();
@@ -229,7 +233,7 @@ public final class AppSearchImpl implements Closeable {
// Populate schema map
for (SchemaTypeConfigProto schema : schemaProto.getTypesList()) {
String prefixedSchemaType = schema.getSchemaType();
- addToMap(mSchemaMapLocked, getPrefix(prefixedSchemaType), prefixedSchemaType);
+ addToMap(mSchemaMapLocked, getPrefix(prefixedSchemaType), schema);
}
// Populate namespace map
@@ -278,7 +282,7 @@ public final class AppSearchImpl implements Closeable {
return;
}
- persistToDisk();
+ persistToDisk(PersistType.Code.FULL);
mIcingSearchEngineLocked.close();
mClosedLocked = true;
} catch (AppSearchException e) {
@@ -364,7 +368,14 @@ public final class AppSearchImpl implements Closeable {
}
// Update derived data structures.
- mSchemaMapLocked.put(prefix, rewrittenSchemaResults.mRewrittenPrefixedTypes);
+ for (SchemaTypeConfigProto schemaTypeConfigProto :
+ rewrittenSchemaResults.mRewrittenPrefixedTypes.values()) {
+ addToMap(mSchemaMapLocked, prefix, schemaTypeConfigProto);
+ }
+
+ for (String schemaType : rewrittenSchemaResults.mDeletedPrefixedTypes) {
+ removeFromMap(mSchemaMapLocked, prefix, schemaType);
+ }
Set<String> prefixedSchemasNotPlatformSurfaceable =
new ArraySet<>(schemasNotPlatformSurfaceable.size());
@@ -586,7 +597,7 @@ public final class AppSearchImpl implements Closeable {
mReadWriteLock.readLock().lock();
try {
throwIfClosedLocked();
-
+ String prefix = createPrefix(packageName, databaseName);
List<TypePropertyMask> nonPrefixedPropertyMasks =
TypePropertyPathToProtoConverter.toTypePropertyMaskList(typePropertyPaths);
List<TypePropertyMask> prefixedPropertyMasks =
@@ -597,7 +608,7 @@ public final class AppSearchImpl implements Closeable {
String prefixedType =
nonPrefixedType.equals(GetByUriRequest.PROJECTION_SCHEMA_TYPE_WILDCARD)
? nonPrefixedType
- : createPrefix(packageName, databaseName) + nonPrefixedType;
+ : prefix + nonPrefixedType;
prefixedPropertyMasks.add(
typePropertyMask.toBuilder().setSchemaType(prefixedType).build());
}
@@ -607,15 +618,17 @@ public final class AppSearchImpl implements Closeable {
.build();
GetResultProto getResultProto =
- mIcingSearchEngineLocked.get(
- createPrefix(packageName, databaseName) + namespace,
- uri,
- getResultSpec);
+ mIcingSearchEngineLocked.get(prefix + namespace, uri, getResultSpec);
checkSuccess(getResultProto.getStatus());
+ // The schema type map cannot be null at this point. It could only be null if no
+ // schema had ever been set for that prefix. Given we have retrieved a document from
+ // the index, we know a schema had to have been set.
+ Map<String, SchemaTypeConfigProto> schemaTypeMap = mSchemaMapLocked.get(prefix);
DocumentProto.Builder documentBuilder = getResultProto.getDocument().toBuilder();
removePrefixesFromDocument(documentBuilder);
- return GenericDocumentToProtoConverter.toGenericDocument(documentBuilder.build());
+ return GenericDocumentToProtoConverter.toGenericDocument(
+ documentBuilder.build(), prefix, schemaTypeMap);
} finally {
mReadWriteLock.readLock().unlock();
}
@@ -726,7 +739,7 @@ public final class AppSearchImpl implements Closeable {
}
} else {
// Client didn't specify certain schemas to search over, check all schemas
- Set<String> prefixedSchemas = mSchemaMapLocked.get(prefix);
+ Set<String> prefixedSchemas = mSchemaMapLocked.get(prefix).keySet();
if (prefixedSchemas != null) {
for (String prefixedSchema : prefixedSchemas) {
if (packageName.equals(callerPackageName)
@@ -816,7 +829,7 @@ public final class AppSearchImpl implements Closeable {
searchSpecBuilder.build(), scoringSpec, resultSpecBuilder.build());
checkSuccess(searchResultProto.getStatus());
- return rewriteSearchResultProto(searchResultProto);
+ return rewriteSearchResultProto(searchResultProto, mSchemaMapLocked);
}
/**
@@ -838,7 +851,7 @@ public final class AppSearchImpl implements Closeable {
SearchResultProto searchResultProto =
mIcingSearchEngineLocked.getNextPage(nextPageToken);
checkSuccess(searchResultProto.getStatus());
- return rewriteSearchResultProto(searchResultProto);
+ return rewriteSearchResultProto(searchResultProto, mSchemaMapLocked);
} finally {
mReadWriteLock.readLock().unlock();
}
@@ -1104,22 +1117,31 @@ public final class AppSearchImpl implements Closeable {
/**
* Persists all update/delete requests to the disk.
*
- * <p>If the app crashes after a call to PersistToDisk(), Icing would be able to fully recover
- * all data written up to this point without a costly recovery process.
+ * <p>If the app crashes after a call to PersistToDisk with {@link PersistType.Code#FULL}, Icing
+ * would be able to fully recover all data written up to this point without a costly recovery
+ * process.
+ *
+ * <p>If the app crashes after a call to PersistToDisk with {@link PersistType.Code#LITE}, Icing
+ * would trigger a costly recovery process in next initialization. After that, Icing would still
+ * be able to recover all written data - excepting Usage data. Usage data is only guaranteed to
+ * be safe after a call to PersistToDisk with {@link PersistType.Code#FULL}
*
- * <p>If the app crashes before a call to PersistToDisk(), Icing would trigger a costly recovery
- * process in next initialization. After that, Icing would still be able to recover all written
- * data.
+ * <p>If the app crashes after an update/delete request has been made, but before any call to
+ * PersistToDisk, then all data in Icing will be lost.
*
+ * @param persistType the amount of data to persist. {@link PersistType.Code#LITE} will only
+ * persist the minimal amount of data to ensure all data can be recovered. {@link
+ * PersistType.Code#FULL} will persist all data necessary to prevent data loss without
+ * needing data recovery.
* @throws AppSearchException on any error that AppSearch persist data to disk.
*/
- public void persistToDisk() throws AppSearchException {
+ public void persistToDisk(@NonNull PersistType.Code persistType) throws AppSearchException {
mReadWriteLock.writeLock().lock();
try {
throwIfClosedLocked();
PersistToDiskResultProto persistToDiskResultProto =
- mIcingSearchEngineLocked.persistToDisk(PersistType.Code.FULL);
+ mIcingSearchEngineLocked.persistToDisk(persistType);
checkSuccess(persistToDiskResultProto.getStatus());
} finally {
mReadWriteLock.writeLock().unlock();
@@ -1189,8 +1211,8 @@ public final class AppSearchImpl implements Closeable {
// Any prefixed types that used to exist in the schema, but are deleted in the new one.
final Set<String> mDeletedPrefixedTypes = new ArraySet<>();
- // Prefixed types that were part of the new schema.
- final Set<String> mRewrittenPrefixedTypes = new ArraySet<>();
+ // Map of prefixed schema types to SchemaTypeConfigProtos that were part of the new schema.
+ final Map<String, SchemaTypeConfigProto> mRewrittenPrefixedTypes = new ArrayMap<>();
}
/**
@@ -1238,7 +1260,7 @@ public final class AppSearchImpl implements Closeable {
// newTypesToProto is modified below, so we need a copy first
RewrittenSchemaResults rewrittenSchemaResults = new RewrittenSchemaResults();
- rewrittenSchemaResults.mRewrittenPrefixedTypes.addAll(newTypesToProto.keySet());
+ rewrittenSchemaResults.mRewrittenPrefixedTypes.putAll(newTypesToProto);
// Combine the existing schema (which may have types from other prefixes) with this
// prefix's new schema. Modifies the existingSchemaBuilder.
@@ -1264,99 +1286,6 @@ public final class AppSearchImpl implements Closeable {
}
/**
- * Prepends {@code prefix} to all types and namespaces mentioned anywhere in {@code
- * documentBuilder}.
- *
- * @param documentBuilder The document to mutate
- * @param prefix The prefix to add
- */
- @VisibleForTesting
- static void addPrefixToDocument(
- @NonNull DocumentProto.Builder documentBuilder, @NonNull String prefix) {
- // Rewrite the type name to include/remove the prefix.
- String newSchema = prefix + documentBuilder.getSchema();
- documentBuilder.setSchema(newSchema);
-
- // Rewrite the namespace to include/remove the prefix.
- documentBuilder.setNamespace(prefix + documentBuilder.getNamespace());
-
- // Recurse into derived documents
- for (int propertyIdx = 0;
- propertyIdx < documentBuilder.getPropertiesCount();
- propertyIdx++) {
- int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
- if (documentCount > 0) {
- PropertyProto.Builder propertyBuilder =
- documentBuilder.getProperties(propertyIdx).toBuilder();
- for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
- DocumentProto.Builder derivedDocumentBuilder =
- propertyBuilder.getDocumentValues(documentIdx).toBuilder();
- addPrefixToDocument(derivedDocumentBuilder, prefix);
- propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
- }
- documentBuilder.setProperties(propertyIdx, propertyBuilder);
- }
- }
- }
-
- /**
- * Removes any prefixes from types and namespaces mentioned anywhere in {@code documentBuilder}.
- *
- * @param documentBuilder The document to mutate
- * @return Prefix name that was removed from the document.
- * @throws AppSearchException if there are unexpected database prefixing errors.
- */
- @NonNull
- @VisibleForTesting
- static String removePrefixesFromDocument(@NonNull DocumentProto.Builder documentBuilder)
- throws AppSearchException {
- // Rewrite the type name and namespace to remove the prefix.
- String schemaPrefix = getPrefix(documentBuilder.getSchema());
- String namespacePrefix = getPrefix(documentBuilder.getNamespace());
-
- if (!schemaPrefix.equals(namespacePrefix)) {
- throw new AppSearchException(
- AppSearchResult.RESULT_INTERNAL_ERROR,
- "Found unexpected"
- + " multiple prefix names in document: "
- + schemaPrefix
- + ", "
- + namespacePrefix);
- }
-
- documentBuilder.setSchema(removePrefix(documentBuilder.getSchema()));
- documentBuilder.setNamespace(removePrefix(documentBuilder.getNamespace()));
-
- // Recurse into derived documents
- for (int propertyIdx = 0;
- propertyIdx < documentBuilder.getPropertiesCount();
- propertyIdx++) {
- int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
- if (documentCount > 0) {
- PropertyProto.Builder propertyBuilder =
- documentBuilder.getProperties(propertyIdx).toBuilder();
- for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
- DocumentProto.Builder derivedDocumentBuilder =
- propertyBuilder.getDocumentValues(documentIdx).toBuilder();
- String nestedPrefix = removePrefixesFromDocument(derivedDocumentBuilder);
- if (!nestedPrefix.equals(schemaPrefix)) {
- throw new AppSearchException(
- AppSearchResult.RESULT_INTERNAL_ERROR,
- "Found unexpected multiple prefix names in document: "
- + schemaPrefix
- + ", "
- + nestedPrefix);
- }
- propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
- }
- documentBuilder.setProperties(propertyIdx, propertyBuilder);
- }
- }
-
- return schemaPrefix;
- }
-
- /**
* Rewrites the search spec filters with {@code prefixes}.
*
* <p>This method should be only called in query methods and get the READ lock to keep thread
@@ -1443,9 +1372,9 @@ public final class AppSearchImpl implements Closeable {
if (allowedPrefixedSchemas.isEmpty()) {
// If the client didn't specify any schema filters, search over all of their schemas
- Set<String> prefixedSchemas = mSchemaMapLocked.get(prefix);
- if (prefixedSchemas != null) {
- allowedPrefixedSchemas.addAll(prefixedSchemas);
+ Map<String, SchemaTypeConfigProto> prefixedSchemaMap = mSchemaMapLocked.get(prefix);
+ if (prefixedSchemaMap != null) {
+ allowedPrefixedSchemas.addAll(prefixedSchemaMap.keySet());
}
}
return allowedPrefixedSchemas;
@@ -1656,86 +1585,6 @@ public final class AppSearchImpl implements Closeable {
return mSchemaMapLocked.keySet();
}
- @NonNull
- static String createPrefix(@NonNull String packageName, @NonNull String databaseName) {
- return createPackagePrefix(packageName) + databaseName + DATABASE_DELIMITER;
- }
-
- @NonNull
- private static String createPackagePrefix(@NonNull String packageName) {
- return packageName + PACKAGE_DELIMITER;
- }
-
- /**
- * Returns the package name that's contained within the {@code prefix}.
- *
- * @param prefix Prefix string that contains the package name inside of it. The package name
- * must be in the front of the string, and separated from the rest of the string by the
- * {@link #PACKAGE_DELIMITER}.
- * @return Valid package name.
- */
- @NonNull
- private static String getPackageName(@NonNull String prefix) {
- int delimiterIndex = prefix.indexOf(PACKAGE_DELIMITER);
- if (delimiterIndex == -1) {
- // This should never happen if we construct our prefixes properly
- Log.wtf(TAG, "Malformed prefix doesn't contain package delimiter: " + prefix);
- return "";
- }
- return prefix.substring(0, delimiterIndex);
- }
-
- /**
- * Returns the database name that's contained within the {@code prefix}.
- *
- * @param prefix Prefix string that contains the database name inside of it. The database name
- * must be between the {@link #PACKAGE_DELIMITER} and {@link #DATABASE_DELIMITER}
- * @return Valid database name.
- */
- @NonNull
- private static String getDatabaseName(@NonNull String prefix) {
- int packageDelimiterIndex = prefix.indexOf(PACKAGE_DELIMITER);
- int databaseDelimiterIndex = prefix.indexOf(DATABASE_DELIMITER);
- if (packageDelimiterIndex == -1) {
- // This should never happen if we construct our prefixes properly
- Log.wtf(TAG, "Malformed prefix doesn't contain package delimiter: " + prefix);
- return "";
- }
- if (databaseDelimiterIndex == -1) {
- // This should never happen if we construct our prefixes properly
- Log.wtf(TAG, "Malformed prefix doesn't contain database delimiter: " + prefix);
- return "";
- }
- return prefix.substring(packageDelimiterIndex + 1, databaseDelimiterIndex);
- }
-
- @NonNull
- private static String removePrefix(@NonNull String prefixedString) throws AppSearchException {
- // The prefix is made up of the package, then the database. So we only need to find the
- // database cutoff.
- int delimiterIndex;
- if ((delimiterIndex = prefixedString.indexOf(DATABASE_DELIMITER)) != -1) {
- // Add 1 to include the char size of the DATABASE_DELIMITER
- return prefixedString.substring(delimiterIndex + 1);
- }
- throw new AppSearchException(
- AppSearchResult.RESULT_UNKNOWN_ERROR,
- "The prefixed value doesn't contains a valid database name.");
- }
-
- @NonNull
- private static String getPrefix(@NonNull String prefixedString) throws AppSearchException {
- int databaseDelimiterIndex = prefixedString.indexOf(DATABASE_DELIMITER);
- if (databaseDelimiterIndex == -1) {
- throw new AppSearchException(
- AppSearchResult.RESULT_UNKNOWN_ERROR,
- "The databaseName prefixed value doesn't contain a valid database name.");
- }
-
- // Add 1 to include the char size of the DATABASE_DELIMITER
- return prefixedString.substring(0, databaseDelimiterIndex + 1);
- }
-
private static void addToMap(
Map<String, Set<String>> map, String prefix, String prefixedValue) {
Set<String> values = map.get(prefix);
@@ -1746,6 +1595,26 @@ public final class AppSearchImpl implements Closeable {
values.add(prefixedValue);
}
+ private static void addToMap(
+ Map<String, Map<String, SchemaTypeConfigProto>> map,
+ String prefix,
+ SchemaTypeConfigProto schemaTypeConfigProto) {
+ Map<String, SchemaTypeConfigProto> schemaTypeMap = map.get(prefix);
+ if (schemaTypeMap == null) {
+ schemaTypeMap = new ArrayMap<>();
+ map.put(prefix, schemaTypeMap);
+ }
+ schemaTypeMap.put(schemaTypeConfigProto.getSchemaType(), schemaTypeConfigProto);
+ }
+
+ private static void removeFromMap(
+ Map<String, Map<String, SchemaTypeConfigProto>> map, String prefix, String schemaType) {
+ Map<String, SchemaTypeConfigProto> schemaTypeMap = map.get(prefix);
+ if (schemaTypeMap != null) {
+ schemaTypeMap.remove(schemaType);
+ }
+ }
+
/**
* Checks the given status code and throws an {@link AppSearchException} if code is an error.
*
@@ -1853,7 +1722,9 @@ public final class AppSearchImpl implements Closeable {
/** Remove the rewritten schema types from any result documents. */
@NonNull
@VisibleForTesting
- static SearchResultPage rewriteSearchResultProto(@NonNull SearchResultProto searchResultProto)
+ static SearchResultPage rewriteSearchResultProto(
+ @NonNull SearchResultProto searchResultProto,
+ @NonNull Map<String, Map<String, SchemaTypeConfigProto>> schemaMap)
throws AppSearchException {
// Parallel array of package names for each document search result.
List<String> packageNames = new ArrayList<>(searchResultProto.getResultsCount());
@@ -1873,7 +1744,7 @@ public final class AppSearchImpl implements Closeable {
resultsBuilder.setResults(i, resultBuilder);
}
return SearchResultToProtoConverter.toSearchResultPage(
- resultsBuilder, packageNames, databaseNames);
+ resultsBuilder, packageNames, databaseNames, schemaMap);
}
@GuardedBy("mReadWriteLock")
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
index 5680670629ae..cdd795207e0b 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
@@ -18,11 +18,12 @@ package com.android.server.appsearch.external.localstorage;
import android.annotation.NonNull;
-import com.android.internal.util.Preconditions;
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
import com.google.android.icing.proto.PutDocumentStatsProto;
+import java.util.Objects;
+
/**
* Class contains helper functions for logging.
*
@@ -42,8 +43,8 @@ public final class AppSearchLoggerHelper {
static void copyNativeStats(
@NonNull PutDocumentStatsProto fromNativeStats,
@NonNull PutDocumentStats.Builder toStatsBuilder) {
- Preconditions.checkNotNull(fromNativeStats);
- Preconditions.checkNotNull(toStatsBuilder);
+ Objects.requireNonNull(fromNativeStats);
+ Objects.requireNonNull(toStatsBuilder);
toStatsBuilder
.setNativeLatencyMillis(fromNativeStats.getLatencyMs())
.setNativeDocumentStoreLatencyMillis(fromNativeStats.getDocumentStoreLatencyMs())
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java
index d6b9da827515..5ff56abd870a 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java
@@ -17,16 +17,18 @@
package com.android.server.appsearch.external.localstorage.converter;
import android.annotation.NonNull;
+import android.app.appsearch.AppSearchSchema;
import android.app.appsearch.GenericDocument;
-import com.android.internal.util.Preconditions;
-
import com.google.android.icing.proto.DocumentProto;
import com.google.android.icing.proto.PropertyProto;
+import com.google.android.icing.proto.SchemaTypeConfigProto;
import com.google.protobuf.ByteString;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
/**
* Translates a {@link GenericDocument} into a {@link DocumentProto}.
@@ -34,13 +36,20 @@ import java.util.Collections;
* @hide
*/
public final class GenericDocumentToProtoConverter {
+ private static final String[] EMPTY_STRING_ARRAY = new String[0];
+ private static final long[] EMPTY_LONG_ARRAY = new long[0];
+ private static final double[] EMPTY_DOUBLE_ARRAY = new double[0];
+ private static final boolean[] EMPTY_BOOLEAN_ARRAY = new boolean[0];
+ private static final byte[][] EMPTY_BYTES_ARRAY = new byte[0][0];
+ private static final GenericDocument[] EMPTY_DOCUMENT_ARRAY = new GenericDocument[0];
+
private GenericDocumentToProtoConverter() {}
/** Converts a {@link GenericDocument} into a {@link DocumentProto}. */
@NonNull
@SuppressWarnings("unchecked")
public static DocumentProto toDocumentProto(@NonNull GenericDocument document) {
- Preconditions.checkNotNull(document);
+ Objects.requireNonNull(document);
DocumentProto.Builder mProtoBuilder = DocumentProto.newBuilder();
mProtoBuilder
.setUri(document.getUri())
@@ -97,16 +106,34 @@ public final class GenericDocumentToProtoConverter {
return mProtoBuilder.build();
}
- /** Converts a {@link DocumentProto} into a {@link GenericDocument}. */
+ /**
+ * Converts a {@link DocumentProto} into a {@link GenericDocument}.
+ *
+ * <p>In the case that the {@link DocumentProto} object proto has no values set, the converter
+ * searches for the matching property name in the {@link SchemaTypeConfigProto} object for the
+ * document, and infers the correct default value to set for the empty property based on the
+ * data type of the property defined by the schema type.
+ *
+ * @param proto the document to convert to a {@link GenericDocument} instance. The document
+ * proto should have its package + database prefix stripped from its fields.
+ * @param prefix the package + database prefix used searching the {@code schemaTypeMap}.
+ * @param schemaTypeMap map of prefixed schema type to {@link SchemaTypeConfigProto}, used for
+ * looking up the default empty value to set for a document property that has all empty
+ * values.
+ */
@NonNull
- public static GenericDocument toGenericDocument(@NonNull DocumentProto proto) {
- Preconditions.checkNotNull(proto);
+ public static GenericDocument toGenericDocument(
+ @NonNull DocumentProto proto,
+ @NonNull String prefix,
+ @NonNull Map<String, SchemaTypeConfigProto> schemaTypeMap) {
+ Objects.requireNonNull(proto);
GenericDocument.Builder<?> documentBuilder =
new GenericDocument.Builder<>(
proto.getNamespace(), proto.getUri(), proto.getSchema())
.setScore(proto.getScore())
.setTtlMillis(proto.getTtlMs())
.setCreationTimestampMillis(proto.getCreationTimestampMs());
+ String prefixedSchemaType = prefix + proto.getSchema();
for (int i = 0; i < proto.getPropertiesCount(); i++) {
PropertyProto property = proto.getProperties(i);
@@ -144,13 +171,51 @@ public final class GenericDocumentToProtoConverter {
} else if (property.getDocumentValuesCount() > 0) {
GenericDocument[] values = new GenericDocument[property.getDocumentValuesCount()];
for (int j = 0; j < values.length; j++) {
- values[j] = toGenericDocument(property.getDocumentValues(j));
+ values[j] =
+ toGenericDocument(property.getDocumentValues(j), prefix, schemaTypeMap);
}
documentBuilder.setPropertyDocument(name, values);
} else {
- throw new IllegalStateException("Unknown type of value: " + name);
+ // TODO(b/184966497): Optimize by caching PropertyConfigProto
+ setEmptyProperty(name, documentBuilder, schemaTypeMap.get(prefixedSchemaType));
}
}
return documentBuilder.build();
}
+
+ private static void setEmptyProperty(
+ @NonNull String propertyName,
+ @NonNull GenericDocument.Builder<?> documentBuilder,
+ @NonNull SchemaTypeConfigProto schema) {
+ @AppSearchSchema.PropertyConfig.DataType int dataType = 0;
+ for (int i = 0; i < schema.getPropertiesCount(); ++i) {
+ if (propertyName.equals(schema.getProperties(i).getPropertyName())) {
+ dataType = schema.getProperties(i).getDataType().getNumber();
+ break;
+ }
+ }
+
+ switch (dataType) {
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_STRING:
+ documentBuilder.setPropertyString(propertyName, EMPTY_STRING_ARRAY);
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_INT64:
+ documentBuilder.setPropertyLong(propertyName, EMPTY_LONG_ARRAY);
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE:
+ documentBuilder.setPropertyDouble(propertyName, EMPTY_DOUBLE_ARRAY);
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN:
+ documentBuilder.setPropertyBoolean(propertyName, EMPTY_BOOLEAN_ARRAY);
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES:
+ documentBuilder.setPropertyBytes(propertyName, EMPTY_BYTES_ARRAY);
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT:
+ documentBuilder.setPropertyDocument(propertyName, EMPTY_DOCUMENT_ARRAY);
+ break;
+ default:
+ throw new IllegalStateException("Unknown type of value: " + propertyName);
+ }
+ }
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java
index 800b073fd44f..e3fa7e08aac4 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java
@@ -20,8 +20,6 @@ import android.annotation.NonNull;
import android.app.appsearch.AppSearchSchema;
import android.util.Log;
-import com.android.internal.util.Preconditions;
-
import com.google.android.icing.proto.DocumentIndexingConfig;
import com.google.android.icing.proto.PropertyConfigProto;
import com.google.android.icing.proto.SchemaTypeConfigProto;
@@ -30,6 +28,7 @@ import com.google.android.icing.proto.StringIndexingConfig;
import com.google.android.icing.proto.TermMatchType;
import java.util.List;
+import java.util.Objects;
/**
* Translates an {@link AppSearchSchema} into a {@link SchemaTypeConfigProto}.
@@ -48,7 +47,7 @@ public final class SchemaToProtoConverter {
@NonNull
public static SchemaTypeConfigProto toSchemaTypeConfigProto(
@NonNull AppSearchSchema schema, int version) {
- Preconditions.checkNotNull(schema);
+ Objects.requireNonNull(schema);
SchemaTypeConfigProto.Builder protoBuilder =
SchemaTypeConfigProto.newBuilder()
.setSchemaType(schema.getSchemaType())
@@ -64,7 +63,7 @@ public final class SchemaToProtoConverter {
@NonNull
private static PropertyConfigProto toPropertyConfigProto(
@NonNull AppSearchSchema.PropertyConfig property) {
- Preconditions.checkNotNull(property);
+ Objects.requireNonNull(property);
PropertyConfigProto.Builder builder =
PropertyConfigProto.newBuilder().setPropertyName(property.getName());
@@ -116,7 +115,7 @@ public final class SchemaToProtoConverter {
*/
@NonNull
public static AppSearchSchema toAppSearchSchema(@NonNull SchemaTypeConfigProtoOrBuilder proto) {
- Preconditions.checkNotNull(proto);
+ Objects.requireNonNull(proto);
AppSearchSchema.Builder builder = new AppSearchSchema.Builder(proto.getSchemaType());
List<PropertyConfigProto> properties = proto.getPropertiesList();
for (int i = 0; i < properties.size(); i++) {
@@ -129,7 +128,7 @@ public final class SchemaToProtoConverter {
@NonNull
private static AppSearchSchema.PropertyConfig toPropertyConfig(
@NonNull PropertyConfigProto proto) {
- Preconditions.checkNotNull(proto);
+ Objects.requireNonNull(proto);
switch (proto.getDataType()) {
case STRING:
return toStringPropertyConfig(proto);
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
index bf7e5334d090..57c1590d2bef 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
@@ -16,6 +16,8 @@
package com.android.server.appsearch.external.localstorage.converter;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.createPrefix;
+
import android.annotation.NonNull;
import android.app.appsearch.GenericDocument;
import android.app.appsearch.SearchResult;
@@ -24,6 +26,7 @@ import android.os.Bundle;
import com.android.internal.util.Preconditions;
+import com.google.android.icing.proto.SchemaTypeConfigProto;
import com.google.android.icing.proto.SearchResultProto;
import com.google.android.icing.proto.SearchResultProtoOrBuilder;
import com.google.android.icing.proto.SnippetMatchProto;
@@ -31,6 +34,7 @@ import com.google.android.icing.proto.SnippetProto;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
* Translates a {@link SearchResultProto} into {@link SearchResult}s.
@@ -49,13 +53,17 @@ public class SearchResultToProtoConverter {
* @param databaseNames A parallel array of database names. The database name at index 'i' of
* this list shold be the database that indexed the document at index 'i' of
* proto.getResults(i).
+ * @param schemaMap A map of prefixes to an inner-map of prefixed schema type to
+ * SchemaTypeConfigProtos, used for setting a default value for results with DocumentProtos
+ * that have empty values.
* @return {@link SearchResultPage} of results.
*/
@NonNull
public static SearchResultPage toSearchResultPage(
@NonNull SearchResultProtoOrBuilder proto,
@NonNull List<String> packageNames,
- @NonNull List<String> databaseNames) {
+ @NonNull List<String> databaseNames,
+ @NonNull Map<String, Map<String, SchemaTypeConfigProto>> schemaMap) {
Preconditions.checkArgument(
proto.getResultsCount() == packageNames.size(),
"Size of results does not match the number of package names.");
@@ -63,8 +71,14 @@ public class SearchResultToProtoConverter {
bundle.putLong(SearchResultPage.NEXT_PAGE_TOKEN_FIELD, proto.getNextPageToken());
ArrayList<Bundle> resultBundles = new ArrayList<>(proto.getResultsCount());
for (int i = 0; i < proto.getResultsCount(); i++) {
+ String prefix = createPrefix(packageNames.get(i), databaseNames.get(i));
+ Map<String, SchemaTypeConfigProto> schemaTypeMap = schemaMap.get(prefix);
SearchResult result =
- toSearchResult(proto.getResults(i), packageNames.get(i), databaseNames.get(i));
+ toSearchResult(
+ proto.getResults(i),
+ packageNames.get(i),
+ databaseNames.get(i),
+ schemaTypeMap);
resultBundles.add(result.getBundle());
}
bundle.putParcelableArrayList(SearchResultPage.RESULTS_FIELD, resultBundles);
@@ -77,15 +91,21 @@ public class SearchResultToProtoConverter {
* @param proto The proto to be converted.
* @param packageName The package name associated with the document in {@code proto}.
* @param databaseName The database name associated with the document in {@code proto}.
+ * @param schemaTypeToProtoMap A map of prefixed schema types to their corresponding
+ * SchemaTypeConfigProto, used for setting a default value for results with DocumentProtos
+ * that have empty values.
* @return A {@link SearchResult} bundle.
*/
@NonNull
private static SearchResult toSearchResult(
@NonNull SearchResultProto.ResultProtoOrBuilder proto,
@NonNull String packageName,
- @NonNull String databaseName) {
+ @NonNull String databaseName,
+ @NonNull Map<String, SchemaTypeConfigProto> schemaTypeToProtoMap) {
+ String prefix = createPrefix(packageName, databaseName);
GenericDocument document =
- GenericDocumentToProtoConverter.toGenericDocument(proto.getDocument());
+ GenericDocumentToProtoConverter.toGenericDocument(
+ proto.getDocument(), prefix, schemaTypeToProtoMap);
SearchResult.Builder builder =
new SearchResult.Builder(packageName, databaseName)
.setGenericDocument(document)
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchSpecToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchSpecToProtoConverter.java
index d9e8adb52e5e..8f9e9bdc8cbc 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchSpecToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchSpecToProtoConverter.java
@@ -19,13 +19,13 @@ package com.android.server.appsearch.external.localstorage.converter;
import android.annotation.NonNull;
import android.app.appsearch.SearchSpec;
-import com.android.internal.util.Preconditions;
-
import com.google.android.icing.proto.ResultSpecProto;
import com.google.android.icing.proto.ScoringSpecProto;
import com.google.android.icing.proto.SearchSpecProto;
import com.google.android.icing.proto.TermMatchType;
+import java.util.Objects;
+
/**
* Translates a {@link SearchSpec} into icing search protos.
*
@@ -37,7 +37,7 @@ public final class SearchSpecToProtoConverter {
/** Extracts {@link SearchSpecProto} information from a {@link SearchSpec}. */
@NonNull
public static SearchSpecProto toSearchSpecProto(@NonNull SearchSpec spec) {
- Preconditions.checkNotNull(spec);
+ Objects.requireNonNull(spec);
SearchSpecProto.Builder protoBuilder =
SearchSpecProto.newBuilder()
.addAllSchemaTypeFilters(spec.getFilterSchemas())
@@ -56,7 +56,7 @@ public final class SearchSpecToProtoConverter {
/** Extracts {@link ResultSpecProto} information from a {@link SearchSpec}. */
@NonNull
public static ResultSpecProto toResultSpecProto(@NonNull SearchSpec spec) {
- Preconditions.checkNotNull(spec);
+ Objects.requireNonNull(spec);
return ResultSpecProto.newBuilder()
.setNumPerPage(spec.getResultCountPerPage())
.setSnippetSpec(
@@ -73,7 +73,7 @@ public final class SearchSpecToProtoConverter {
/** Extracts {@link ScoringSpecProto} information from a {@link SearchSpec}. */
@NonNull
public static ScoringSpecProto toScoringSpecProto(@NonNull SearchSpec spec) {
- Preconditions.checkNotNull(spec);
+ Objects.requireNonNull(spec);
ScoringSpecProto.Builder protoBuilder = ScoringSpecProto.newBuilder();
@SearchSpec.Order int orderCode = spec.getOrder();
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SetSchemaResponseToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SetSchemaResponseToProtoConverter.java
index a0f39ecd68fb..ed73593fd1a2 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SetSchemaResponseToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SetSchemaResponseToProtoConverter.java
@@ -19,10 +19,10 @@ package com.android.server.appsearch.external.localstorage.converter;
import android.annotation.NonNull;
import android.app.appsearch.SetSchemaResponse;
-import com.android.internal.util.Preconditions;
-
import com.google.android.icing.proto.SetSchemaResultProto;
+import java.util.Objects;
+
/**
* Translates a {@link SetSchemaResultProto} into {@link SetSchemaResponse}.
*
@@ -42,8 +42,8 @@ public class SetSchemaResponseToProtoConverter {
@NonNull
public static SetSchemaResponse toSetSchemaResponse(
@NonNull SetSchemaResultProto proto, @NonNull String prefix) {
- Preconditions.checkNotNull(proto);
- Preconditions.checkNotNull(prefix);
+ Objects.requireNonNull(proto);
+ Objects.requireNonNull(prefix);
SetSchemaResponse.Builder builder = new SetSchemaResponse.Builder();
for (int i = 0; i < proto.getDeletedSchemaTypesCount(); i++) {
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/TypePropertyPathToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/TypePropertyPathToProtoConverter.java
index 6f6dad207713..acf04ef08a2c 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/TypePropertyPathToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/TypePropertyPathToProtoConverter.java
@@ -18,13 +18,12 @@ package com.android.server.appsearch.external.localstorage.converter;
import android.annotation.NonNull;
-import com.android.internal.util.Preconditions;
-
import com.google.android.icing.proto.TypePropertyMask;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
/**
* Translates a <code>Map<String, List<String>></code> into <code>List<TypePropertyMask></code>.
@@ -38,7 +37,7 @@ public final class TypePropertyPathToProtoConverter {
@NonNull
public static List<TypePropertyMask> toTypePropertyMaskList(
@NonNull Map<String, List<String>> typePropertyPaths) {
- Preconditions.checkNotNull(typePropertyPaths);
+ Objects.requireNonNull(typePropertyPaths);
List<TypePropertyMask> typePropertyMasks = new ArrayList<>(typePropertyPaths.size());
for (Map.Entry<String, List<String>> e : typePropertyPaths.entrySet()) {
typePropertyMasks.add(
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java
index a724f95ad8fa..cf640c1a8d21 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java
@@ -19,10 +19,9 @@ package com.android.server.appsearch.external.localstorage.stats;
import android.annotation.IntDef;
import android.annotation.NonNull;
-import com.android.internal.util.Preconditions;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
/**
* A class for setting basic information to log for all function calls.
@@ -75,8 +74,8 @@ public class CallStats {
private final int mNumOperationsFailed;
CallStats(@NonNull Builder builder) {
- Preconditions.checkNotNull(builder);
- mGeneralStats = Preconditions.checkNotNull(builder.mGeneralStatsBuilder).build();
+ Objects.requireNonNull(builder);
+ mGeneralStats = Objects.requireNonNull(builder.mGeneralStatsBuilder).build();
mCallType = builder.mCallType;
mEstimatedBinderLatencyMillis = builder.mEstimatedBinderLatencyMillis;
mNumOperationsSucceeded = builder.mNumOperationsSucceeded;
@@ -140,8 +139,8 @@ public class CallStats {
/** Builder takes {@link GeneralStats.Builder}. */
public Builder(@NonNull String packageName, @NonNull String database) {
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(database);
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(database);
mGeneralStatsBuilder = new GeneralStats.Builder(packageName, database);
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java
index 8ce8eda3d7a7..53c1ee3f675f 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/GeneralStats.java
@@ -19,7 +19,7 @@ package com.android.server.appsearch.external.localstorage.stats;
import android.annotation.NonNull;
import android.app.appsearch.AppSearchResult;
-import com.android.internal.util.Preconditions;
+import java.util.Objects;
/**
* A class for holding general logging information.
@@ -48,9 +48,9 @@ public final class GeneralStats {
private final int mTotalLatencyMillis;
GeneralStats(@NonNull Builder builder) {
- Preconditions.checkNotNull(builder);
- mPackageName = Preconditions.checkNotNull(builder.mPackageName);
- mDatabase = Preconditions.checkNotNull(builder.mDatabase);
+ Objects.requireNonNull(builder);
+ mPackageName = Objects.requireNonNull(builder.mPackageName);
+ mDatabase = Objects.requireNonNull(builder.mDatabase);
mStatusCode = builder.mStatusCode;
mTotalLatencyMillis = builder.mTotalLatencyMillis;
}
@@ -92,8 +92,8 @@ public final class GeneralStats {
* @param database name of the database logging stats
*/
public Builder(@NonNull String packageName, @NonNull String database) {
- mPackageName = Preconditions.checkNotNull(packageName);
- mDatabase = Preconditions.checkNotNull(database);
+ mPackageName = Objects.requireNonNull(packageName);
+ mDatabase = Objects.requireNonNull(database);
}
/** Sets status code returned from {@link AppSearchResult#getResultCode()} */
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java
index c1f6fb118797..d031172d29c1 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/PutDocumentStats.java
@@ -18,7 +18,7 @@ package com.android.server.appsearch.external.localstorage.stats;
import android.annotation.NonNull;
-import com.android.internal.util.Preconditions;
+import java.util.Objects;
/**
* A class for holding detailed stats to log for each individual document put by a {@link
@@ -60,8 +60,8 @@ public final class PutDocumentStats {
private final boolean mNativeExceededMaxNumTokens;
PutDocumentStats(@NonNull Builder builder) {
- Preconditions.checkNotNull(builder);
- mGeneralStats = Preconditions.checkNotNull(builder.mGeneralStatsBuilder).build();
+ Objects.requireNonNull(builder);
+ mGeneralStats = Objects.requireNonNull(builder.mGeneralStatsBuilder).build();
mGenerateDocumentProtoLatencyMillis = builder.mGenerateDocumentProtoLatencyMillis;
mRewriteDocumentTypesLatencyMillis = builder.mRewriteDocumentTypesLatencyMillis;
mNativeLatencyMillis = builder.mNativeLatencyMillis;
@@ -142,8 +142,8 @@ public final class PutDocumentStats {
/** Builder takes {@link GeneralStats.Builder}. */
public Builder(@NonNull String packageName, @NonNull String database) {
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(database);
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(database);
mGeneralStatsBuilder = new GeneralStats.Builder(packageName, database);
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/util/PrefixUtil.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/util/PrefixUtil.java
new file mode 100644
index 000000000000..9ae9f1852849
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/util/PrefixUtil.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2021 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.server.appsearch.external.localstorage.util;
+
+import android.annotation.NonNull;
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.exceptions.AppSearchException;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import com.google.android.icing.proto.DocumentProto;
+import com.google.android.icing.proto.PropertyProto;
+
+/**
+ * Provides utility functions for working with package + database prefixes.
+ *
+ * @hide
+ */
+public class PrefixUtil {
+ private static final String TAG = "AppSearchPrefixUtil";
+
+ @VisibleForTesting public static final char DATABASE_DELIMITER = '/';
+
+ @VisibleForTesting public static final char PACKAGE_DELIMITER = '$';
+
+ private PrefixUtil() {}
+
+ /** Creates prefix string for given package name and database name. */
+ @NonNull
+ public static String createPrefix(@NonNull String packageName, @NonNull String databaseName) {
+ return packageName + PACKAGE_DELIMITER + databaseName + DATABASE_DELIMITER;
+ }
+ /** Creates prefix string for given package name. */
+ @NonNull
+ public static String createPackagePrefix(@NonNull String packageName) {
+ return packageName + PACKAGE_DELIMITER;
+ }
+
+ /**
+ * Returns the package name that's contained within the {@code prefix}.
+ *
+ * @param prefix Prefix string that contains the package name inside of it. The package name
+ * must be in the front of the string, and separated from the rest of the string by the
+ * {@link #PACKAGE_DELIMITER}.
+ * @return Valid package name.
+ */
+ @NonNull
+ public static String getPackageName(@NonNull String prefix) {
+ int delimiterIndex = prefix.indexOf(PACKAGE_DELIMITER);
+ if (delimiterIndex == -1) {
+ // This should never happen if we construct our prefixes properly
+ Log.wtf(TAG, "Malformed prefix doesn't contain package delimiter: " + prefix);
+ return "";
+ }
+ return prefix.substring(0, delimiterIndex);
+ }
+
+ /**
+ * Returns the database name that's contained within the {@code prefix}.
+ *
+ * @param prefix Prefix string that contains the database name inside of it. The database name
+ * must be between the {@link #PACKAGE_DELIMITER} and {@link #DATABASE_DELIMITER}
+ * @return Valid database name.
+ */
+ @NonNull
+ public static String getDatabaseName(@NonNull String prefix) {
+ // TODO (b/184050178) Start database delimiter index search from after package delimiter
+ int packageDelimiterIndex = prefix.indexOf(PACKAGE_DELIMITER);
+ int databaseDelimiterIndex = prefix.indexOf(DATABASE_DELIMITER);
+ if (packageDelimiterIndex == -1) {
+ // This should never happen if we construct our prefixes properly
+ Log.wtf(TAG, "Malformed prefix doesn't contain package delimiter: " + prefix);
+ return "";
+ }
+ if (databaseDelimiterIndex == -1) {
+ // This should never happen if we construct our prefixes properly
+ Log.wtf(TAG, "Malformed prefix doesn't contain database delimiter: " + prefix);
+ return "";
+ }
+ return prefix.substring(packageDelimiterIndex + 1, databaseDelimiterIndex);
+ }
+
+ /**
+ * Creates a string with the package and database prefix removed from the input string.
+ *
+ * @param prefixedString a string containing a package and database prefix.
+ * @return a string with the package and database prefix removed.
+ * @throws AppSearchException if the prefixed value does not contain a valid database name.
+ */
+ @NonNull
+ public static String removePrefix(@NonNull String prefixedString) throws AppSearchException {
+ // The prefix is made up of the package, then the database. So we only need to find the
+ // database cutoff.
+ int delimiterIndex;
+ if ((delimiterIndex = prefixedString.indexOf(DATABASE_DELIMITER)) != -1) {
+ // Add 1 to include the char size of the DATABASE_DELIMITER
+ return prefixedString.substring(delimiterIndex + 1);
+ }
+ throw new AppSearchException(
+ AppSearchResult.RESULT_UNKNOWN_ERROR,
+ "The prefixed value doesn't contains a valid database name.");
+ }
+
+ /**
+ * Creates a package and database prefix string from the input string.
+ *
+ * @param prefixedString a string containing a package and database prefix.
+ * @return a string with the package and database prefix
+ * @throws AppSearchException if the prefixed value does not contain a valid database name.
+ */
+ @NonNull
+ public static String getPrefix(@NonNull String prefixedString) throws AppSearchException {
+ int databaseDelimiterIndex = prefixedString.indexOf(DATABASE_DELIMITER);
+ if (databaseDelimiterIndex == -1) {
+ throw new AppSearchException(
+ AppSearchResult.RESULT_UNKNOWN_ERROR,
+ "The databaseName prefixed value doesn't contain a valid database name.");
+ }
+
+ // Add 1 to include the char size of the DATABASE_DELIMITER
+ return prefixedString.substring(0, databaseDelimiterIndex + 1);
+ }
+
+ /**
+ * Prepends {@code prefix} to all types and namespaces mentioned anywhere in {@code
+ * documentBuilder}.
+ *
+ * @param documentBuilder The document to mutate
+ * @param prefix The prefix to add
+ */
+ public static void addPrefixToDocument(
+ @NonNull DocumentProto.Builder documentBuilder, @NonNull String prefix) {
+ // Rewrite the type name to include/remove the prefix.
+ String newSchema = prefix + documentBuilder.getSchema();
+ documentBuilder.setSchema(newSchema);
+
+ // Rewrite the namespace to include/remove the prefix.
+ documentBuilder.setNamespace(prefix + documentBuilder.getNamespace());
+
+ // Recurse into derived documents
+ for (int propertyIdx = 0;
+ propertyIdx < documentBuilder.getPropertiesCount();
+ propertyIdx++) {
+ int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
+ if (documentCount > 0) {
+ PropertyProto.Builder propertyBuilder =
+ documentBuilder.getProperties(propertyIdx).toBuilder();
+ for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
+ DocumentProto.Builder derivedDocumentBuilder =
+ propertyBuilder.getDocumentValues(documentIdx).toBuilder();
+ addPrefixToDocument(derivedDocumentBuilder, prefix);
+ propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
+ }
+ documentBuilder.setProperties(propertyIdx, propertyBuilder);
+ }
+ }
+ }
+
+ /**
+ * Removes any prefixes from types and namespaces mentioned anywhere in {@code documentBuilder}.
+ *
+ * @param documentBuilder The document to mutate
+ * @return Prefix name that was removed from the document.
+ * @throws AppSearchException if there are unexpected database prefixing errors.
+ */
+ @NonNull
+ public static String removePrefixesFromDocument(@NonNull DocumentProto.Builder documentBuilder)
+ throws AppSearchException {
+ // Rewrite the type name and namespace to remove the prefix.
+ String schemaPrefix = getPrefix(documentBuilder.getSchema());
+ String namespacePrefix = getPrefix(documentBuilder.getNamespace());
+
+ if (!schemaPrefix.equals(namespacePrefix)) {
+ throw new AppSearchException(
+ AppSearchResult.RESULT_INTERNAL_ERROR,
+ "Found unexpected"
+ + " multiple prefix names in document: "
+ + schemaPrefix
+ + ", "
+ + namespacePrefix);
+ }
+
+ documentBuilder.setSchema(removePrefix(documentBuilder.getSchema()));
+ documentBuilder.setNamespace(removePrefix(documentBuilder.getNamespace()));
+
+ // Recurse into derived documents
+ for (int propertyIdx = 0;
+ propertyIdx < documentBuilder.getPropertiesCount();
+ propertyIdx++) {
+ int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
+ if (documentCount > 0) {
+ PropertyProto.Builder propertyBuilder =
+ documentBuilder.getProperties(propertyIdx).toBuilder();
+ for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
+ DocumentProto.Builder derivedDocumentBuilder =
+ propertyBuilder.getDocumentValues(documentIdx).toBuilder();
+ String nestedPrefix = removePrefixesFromDocument(derivedDocumentBuilder);
+ if (!nestedPrefix.equals(schemaPrefix)) {
+ throw new AppSearchException(
+ AppSearchResult.RESULT_INTERNAL_ERROR,
+ "Found unexpected multiple prefix names in document: "
+ + schemaPrefix
+ + ", "
+ + nestedPrefix);
+ }
+ propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
+ }
+ documentBuilder.setProperties(propertyIdx, propertyBuilder);
+ }
+ }
+
+ return schemaPrefix;
+ }
+}
diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt
index e46c147e36ff..f99664b4c685 100644
--- a/apex/appsearch/synced_jetpack_changeid.txt
+++ b/apex/appsearch/synced_jetpack_changeid.txt
@@ -1 +1 @@
-I925ec12f4901c7759976c344ba3428210aada8ad
+If9d1d770d2327d7d0db7d82acfc54787b5de64bc
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
index 206904372236..494945db5655 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
@@ -187,9 +187,8 @@ public interface AppSearchSessionShim extends Closeable {
* <p>Removed documents will no longer be surfaced by {@link #search} or {@link #getByUri}
* calls.
*
- * <p><b>NOTE:</b>By default, documents are removed via a soft delete operation. Once the
- * document crosses the count threshold or byte usage threshold, the documents will be removed
- * from disk.
+ * <p>Once the database crosses the document count or byte usage threshold, removed documents
+ * will be deleted from disk.
*
* @param request {@link RemoveByUriRequest} with URIs and namespace to remove from the index.
* @return a {@link ListenableFuture} which resolves to an {@link AppSearchBatchResult}. The
diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/AppSearchResultTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/AppSearchResultTest.java
new file mode 100644
index 000000000000..de0670b08ffd
--- /dev/null
+++ b/core/tests/coretests/src/android/app/appsearch/external/app/AppSearchResultTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2020 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.app.appsearch;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.expectThrows;
+
+import org.junit.Test;
+
+public class AppSearchResultTest {
+ @Test
+ public void testMapNullPointerException() {
+ NullPointerException e =
+ expectThrows(
+ NullPointerException.class,
+ () -> {
+ Object o = null;
+ o.toString();
+ });
+ AppSearchResult<?> result = AppSearchResult.throwableToFailedResult(e);
+ assertThat(result.getResultCode()).isEqualTo(AppSearchResult.RESULT_INTERNAL_ERROR);
+ // Makes sure the exception name is included in the string. Some exceptions have terse or
+ // missing strings so it's confusing to read the output without the exception name.
+ assertThat(result.getErrorMessage()).startsWith("NullPointerException");
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java b/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
index 4240581bc504..b552fd5e8718 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
@@ -32,6 +32,8 @@ import android.content.pm.PackageManager;
import androidx.test.core.app.ApplicationProvider;
+import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
+
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -203,7 +205,7 @@ public class AppSearchImplPlatformTest {
mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
// Set schema1
- String prefix = AppSearchImpl.createPrefix("package", "database");
+ String prefix = PrefixUtil.createPrefix("package", "database");
mAppSearchImpl.setSchema(
"package",
"database",
@@ -280,7 +282,7 @@ public class AppSearchImplPlatformTest {
mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
- String prefix = AppSearchImpl.createPrefix("package", "database");
+ String prefix = PrefixUtil.createPrefix("package", "database");
mAppSearchImpl.setSchema(
"package",
"database",
@@ -353,7 +355,7 @@ public class AppSearchImplPlatformTest {
@Test
public void testSetSchema_defaultPlatformVisible() throws Exception {
- String prefix = AppSearchImpl.createPrefix("package", "database");
+ String prefix = PrefixUtil.createPrefix("package", "database");
mAppSearchImpl.setSchema(
"package",
"database",
@@ -372,7 +374,7 @@ public class AppSearchImplPlatformTest {
@Test
public void testSetSchema_platformHidden() throws Exception {
- String prefix = AppSearchImpl.createPrefix("package", "database");
+ String prefix = PrefixUtil.createPrefix("package", "database");
mAppSearchImpl.setSchema(
"package",
"database",
@@ -391,7 +393,7 @@ public class AppSearchImplPlatformTest {
@Test
public void testSetSchema_defaultNotPackageAccessible() throws Exception {
- String prefix = AppSearchImpl.createPrefix("package", "database");
+ String prefix = PrefixUtil.createPrefix("package", "database");
mAppSearchImpl.setSchema(
"package",
"database",
@@ -419,7 +421,7 @@ public class AppSearchImplPlatformTest {
mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
- String prefix = AppSearchImpl.createPrefix("package", "database");
+ String prefix = PrefixUtil.createPrefix("package", "database");
mAppSearchImpl.setSchema(
"package",
"database",
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java b/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java
index 8d35ebe8e2e1..11ae76b94495 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java
@@ -28,6 +28,8 @@ import android.content.pm.PackageManager;
import androidx.test.core.app.ApplicationProvider;
+import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
+
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -78,13 +80,9 @@ public class VisibilityStoreTest {
@Test
public void testValidPackageName() {
assertThat(VisibilityStore.PACKAGE_NAME)
- .doesNotContain(
- "" + AppSearchImpl.PACKAGE_DELIMITER); // Convert the chars to CharSequences
+ .doesNotContain(String.valueOf(PrefixUtil.PACKAGE_DELIMITER));
assertThat(VisibilityStore.PACKAGE_NAME)
- .doesNotContain(
- ""
- + AppSearchImpl
- .DATABASE_DELIMITER); // Convert the chars to CharSequences
+ .doesNotContain(String.valueOf(PrefixUtil.DATABASE_DELIMITER));
}
/**
@@ -93,13 +91,9 @@ public class VisibilityStoreTest {
@Test
public void testValidDatabaseName() {
assertThat(VisibilityStore.DATABASE_NAME)
- .doesNotContain(
- "" + AppSearchImpl.PACKAGE_DELIMITER); // Convert the chars to CharSequences
+ .doesNotContain(String.valueOf(PrefixUtil.PACKAGE_DELIMITER));
assertThat(VisibilityStore.DATABASE_NAME)
- .doesNotContain(
- ""
- + AppSearchImpl
- .DATABASE_DELIMITER); // Convert the chars to CharSequences
+ .doesNotContain(String.valueOf(PrefixUtil.DATABASE_DELIMITER));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
index ba4d5856b247..380d9be5ae57 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
@@ -16,6 +16,10 @@
package com.android.server.appsearch.external.localstorage;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.addPrefixToDocument;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.createPrefix;
+import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.removePrefixesFromDocument;
+
import static com.google.common.truth.Truth.assertThat;
import static org.testng.Assert.expectThrows;
@@ -35,8 +39,10 @@ import android.util.ArraySet;
import androidx.test.core.app.ApplicationProvider;
import com.android.server.appsearch.external.localstorage.converter.GenericDocumentToProtoConverter;
+import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
import com.android.server.appsearch.proto.DocumentProto;
import com.android.server.appsearch.proto.GetOptimizeInfoResultProto;
+import com.android.server.appsearch.proto.PersistType;
import com.android.server.appsearch.proto.PropertyConfigProto;
import com.android.server.appsearch.proto.PropertyProto;
import com.android.server.appsearch.proto.SchemaProto;
@@ -47,6 +53,7 @@ import com.android.server.appsearch.proto.StringIndexingConfig;
import com.android.server.appsearch.proto.TermMatchType;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import org.junit.Before;
@@ -54,6 +61,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -96,56 +104,71 @@ public class AppSearchImplTest {
// Create a copy so we can modify it.
List<SchemaTypeConfigProto> existingTypes =
new ArrayList<>(existingSchemaBuilder.getTypesList());
-
- SchemaProto newSchema =
- SchemaProto.newBuilder()
- .addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType("Foo").build())
- .addTypes(
- SchemaTypeConfigProto.newBuilder()
- .setSchemaType("TestType")
- .addProperties(
- PropertyConfigProto.newBuilder()
- .setPropertyName("subject")
- .setDataType(
- PropertyConfigProto.DataType.Code
- .STRING)
- .setCardinality(
- PropertyConfigProto.Cardinality.Code
- .OPTIONAL)
- .setStringIndexingConfig(
- StringIndexingConfig.newBuilder()
- .setTokenizerType(
- StringIndexingConfig
- .TokenizerType
- .Code.PLAIN)
- .setTermMatchType(
- TermMatchType.Code
- .PREFIX)
- .build())
- .build())
- .addProperties(
- PropertyConfigProto.newBuilder()
- .setPropertyName("link")
- .setDataType(
- PropertyConfigProto.DataType.Code
- .DOCUMENT)
- .setCardinality(
- PropertyConfigProto.Cardinality.Code
- .OPTIONAL)
- .setSchemaType("RefType")
+ SchemaTypeConfigProto schemaTypeConfigProto1 =
+ SchemaTypeConfigProto.newBuilder().setSchemaType("Foo").build();
+ SchemaTypeConfigProto schemaTypeConfigProto2 =
+ SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("TestType")
+ .addProperties(
+ PropertyConfigProto.newBuilder()
+ .setPropertyName("subject")
+ .setDataType(PropertyConfigProto.DataType.Code.STRING)
+ .setCardinality(
+ PropertyConfigProto.Cardinality.Code.OPTIONAL)
+ .setStringIndexingConfig(
+ StringIndexingConfig.newBuilder()
+ .setTokenizerType(
+ StringIndexingConfig.TokenizerType
+ .Code.PLAIN)
+ .setTermMatchType(TermMatchType.Code.PREFIX)
.build())
.build())
+ .addProperties(
+ PropertyConfigProto.newBuilder()
+ .setPropertyName("link")
+ .setDataType(PropertyConfigProto.DataType.Code.DOCUMENT)
+ .setCardinality(
+ PropertyConfigProto.Cardinality.Code.OPTIONAL)
+ .setSchemaType("RefType")
+ .build())
+ .build();
+ SchemaTypeConfigProto schemaTypeConfigProto3 =
+ SchemaTypeConfigProto.newBuilder().setSchemaType("RefType").build();
+ SchemaProto newSchema =
+ SchemaProto.newBuilder()
+ .addTypes(schemaTypeConfigProto1)
+ .addTypes(schemaTypeConfigProto2)
+ .addTypes(schemaTypeConfigProto3)
.build();
AppSearchImpl.RewrittenSchemaResults rewrittenSchemaResults =
mAppSearchImpl.rewriteSchema(
- AppSearchImpl.createPrefix("package", "newDatabase"),
- existingSchemaBuilder,
- newSchema);
+ createPrefix("package", "newDatabase"), existingSchemaBuilder, newSchema);
// We rewrote all the new types that were added. And nothing was removed.
- assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes)
- .containsExactly("package$newDatabase/Foo", "package$newDatabase/TestType");
+ assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes.keySet())
+ .containsExactly(
+ "package$newDatabase/Foo",
+ "package$newDatabase/TestType",
+ "package$newDatabase/RefType");
+ assertThat(
+ rewrittenSchemaResults
+ .mRewrittenPrefixedTypes
+ .get("package$newDatabase/Foo")
+ .getSchemaType())
+ .isEqualTo("package$newDatabase/Foo");
+ assertThat(
+ rewrittenSchemaResults
+ .mRewrittenPrefixedTypes
+ .get("package$newDatabase/TestType")
+ .getSchemaType())
+ .isEqualTo("package$newDatabase/TestType");
+ assertThat(
+ rewrittenSchemaResults
+ .mRewrittenPrefixedTypes
+ .get("package$newDatabase/RefType")
+ .getSchemaType())
+ .isEqualTo("package$newDatabase/RefType");
assertThat(rewrittenSchemaResults.mDeletedPrefixedTypes).isEmpty();
SchemaProto expectedSchema =
@@ -190,6 +213,10 @@ public class AppSearchImplTest {
"package$newDatabase/RefType")
.build())
.build())
+ .addTypes(
+ SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("package$newDatabase/RefType")
+ .build())
.build();
existingTypes.addAll(expectedSchema.getTypesList());
@@ -216,12 +243,12 @@ public class AppSearchImplTest {
AppSearchImpl.RewrittenSchemaResults rewrittenSchemaResults =
mAppSearchImpl.rewriteSchema(
- AppSearchImpl.createPrefix("package", "existingDatabase"),
+ createPrefix("package", "existingDatabase"),
existingSchemaBuilder,
newSchema);
// Nothing was removed, but the method did rewrite the type name.
- assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes)
+ assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes.keySet())
.containsExactly("package$existingDatabase/Foo");
assertThat(rewrittenSchemaResults.mDeletedPrefixedTypes).isEmpty();
@@ -251,14 +278,15 @@ public class AppSearchImplTest {
AppSearchImpl.RewrittenSchemaResults rewrittenSchemaResults =
mAppSearchImpl.rewriteSchema(
- AppSearchImpl.createPrefix("package", "existingDatabase"),
+ createPrefix("package", "existingDatabase"),
existingSchemaBuilder,
newSchema);
// Bar type was rewritten, but Foo ended up being deleted since it wasn't included in the
// new schema.
assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes)
- .containsExactly("package$existingDatabase/Bar");
+ .containsKey("package$existingDatabase/Bar");
+ assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes.keySet().size()).isEqualTo(1);
assertThat(rewrittenSchemaResults.mDeletedPrefixedTypes)
.containsExactly("package$existingDatabase/Foo");
@@ -308,8 +336,7 @@ public class AppSearchImplTest {
.build();
DocumentProto.Builder actualDocument = documentProto.toBuilder();
- mAppSearchImpl.addPrefixToDocument(
- actualDocument, AppSearchImpl.createPrefix("package", "databaseName"));
+ addPrefixToDocument(actualDocument, createPrefix("package", "databaseName"));
assertThat(actualDocument.build()).isEqualTo(expectedDocumentProto);
}
@@ -347,8 +374,7 @@ public class AppSearchImplTest {
.build();
DocumentProto.Builder actualDocument = documentProto.toBuilder();
- assertThat(mAppSearchImpl.removePrefixesFromDocument(actualDocument))
- .isEqualTo("package$databaseName/");
+ assertThat(removePrefixesFromDocument(actualDocument)).isEqualTo("package$databaseName/");
assertThat(actualDocument.build()).isEqualTo(expectedDocumentProto);
}
@@ -365,8 +391,7 @@ public class AppSearchImplTest {
DocumentProto.Builder actualDocument = documentProto.toBuilder();
AppSearchException e =
expectThrows(
- AppSearchException.class,
- () -> mAppSearchImpl.removePrefixesFromDocument(actualDocument));
+ AppSearchException.class, () -> removePrefixesFromDocument(actualDocument));
assertThat(e).hasMessageThat().contains("Found unexpected multiple prefix names");
}
@@ -391,8 +416,7 @@ public class AppSearchImplTest {
DocumentProto.Builder actualDocument = documentProto.toBuilder();
AppSearchException e =
expectThrows(
- AppSearchException.class,
- () -> mAppSearchImpl.removePrefixesFromDocument(actualDocument));
+ AppSearchException.class, () -> removePrefixesFromDocument(actualDocument));
assertThat(e).hasMessageThat().contains("Found unexpected multiple prefix names");
}
@@ -484,7 +508,7 @@ public class AppSearchImplTest {
// Rewrite SearchSpec
mAppSearchImpl.rewriteSearchSpecForPrefixesLocked(
searchSpecProto,
- Collections.singleton(AppSearchImpl.createPrefix("package", "database")),
+ Collections.singleton(createPrefix("package", "database")),
ImmutableSet.of("package$database/type"));
assertThat(searchSpecProto.getSchemaTypeFiltersList())
.containsExactly("package$database/type");
@@ -531,8 +555,7 @@ public class AppSearchImplTest {
mAppSearchImpl.rewriteSearchSpecForPrefixesLocked(
searchSpecProto,
ImmutableSet.of(
- AppSearchImpl.createPrefix("package", "database1"),
- AppSearchImpl.createPrefix("package", "database2")),
+ createPrefix("package", "database1"), createPrefix("package", "database2")),
ImmutableSet.of(
"package$database1/typeA", "package$database1/typeB",
"package$database2/typeA", "package$database2/typeB"));
@@ -573,8 +596,7 @@ public class AppSearchImplTest {
assertThat(
mAppSearchImpl.rewriteSearchSpecForPrefixesLocked(
searchSpecProto,
- Collections.singleton(
- AppSearchImpl.createPrefix("package", "database")),
+ Collections.singleton(createPrefix("package", "database")),
/*allowedPrefixedSchemas=*/ Collections.emptySet()))
.isFalse();
}
@@ -1082,7 +1104,7 @@ public class AppSearchImplTest {
// Has database1
Set<String> expectedPrefixes = new ArraySet<>(existingPrefixes);
- expectedPrefixes.add(AppSearchImpl.createPrefix("package", "database1"));
+ expectedPrefixes.add(createPrefix("package", "database1"));
mAppSearchImpl.setSchema(
"package",
"database1",
@@ -1094,7 +1116,7 @@ public class AppSearchImplTest {
assertThat(mAppSearchImpl.getPrefixesLocked()).containsExactlyElementsIn(expectedPrefixes);
// Has both databases
- expectedPrefixes.add(AppSearchImpl.createPrefix("package", "database2"));
+ expectedPrefixes.add(createPrefix("package", "database2"));
mAppSearchImpl.setSchema(
"package",
"database2",
@@ -1110,9 +1132,9 @@ public class AppSearchImplTest {
public void testRewriteSearchResultProto() throws Exception {
final String prefix =
"com.package.foo"
- + AppSearchImpl.PACKAGE_DELIMITER
+ + PrefixUtil.PACKAGE_DELIMITER
+ "databaseName"
- + AppSearchImpl.DATABASE_DELIMITER;
+ + PrefixUtil.DATABASE_DELIMITER;
final String uri = "uri";
final String namespace = prefix + "namespace";
final String schemaType = prefix + "schema";
@@ -1128,18 +1150,22 @@ public class AppSearchImplTest {
SearchResultProto.ResultProto.newBuilder().setDocument(documentProto).build();
SearchResultProto searchResultProto =
SearchResultProto.newBuilder().addResults(resultProto).build();
+ SchemaTypeConfigProto schemaTypeConfigProto =
+ SchemaTypeConfigProto.newBuilder().setSchemaType(schemaType).build();
+ Map<String, Map<String, SchemaTypeConfigProto>> schemaMap =
+ ImmutableMap.of(prefix, ImmutableMap.of(schemaType, schemaTypeConfigProto));
DocumentProto.Builder strippedDocumentProto = documentProto.toBuilder();
- AppSearchImpl.removePrefixesFromDocument(strippedDocumentProto);
+ removePrefixesFromDocument(strippedDocumentProto);
SearchResultPage searchResultPage =
- AppSearchImpl.rewriteSearchResultProto(searchResultProto);
+ AppSearchImpl.rewriteSearchResultProto(searchResultProto, schemaMap);
for (SearchResult result : searchResultPage.getResults()) {
assertThat(result.getPackageName()).isEqualTo("com.package.foo");
assertThat(result.getDatabaseName()).isEqualTo("databaseName");
assertThat(result.getGenericDocument())
.isEqualTo(
GenericDocumentToProtoConverter.toGenericDocument(
- strippedDocumentProto.build()));
+ strippedDocumentProto.build(), prefix, schemaMap.get(prefix)));
}
}
@@ -1609,7 +1635,221 @@ public class AppSearchImplTest {
expectThrows(
IllegalStateException.class,
() -> {
- appSearchImpl.persistToDisk();
+ appSearchImpl.persistToDisk(PersistType.Code.FULL);
});
}
+
+ @Test
+ public void testPutPersistsWithLiteFlush() throws Exception {
+ // Setup the index
+ Context context = ApplicationProvider.getApplicationContext();
+ File appsearchDir = mTemporaryFolder.newFolder();
+ AppSearchImpl appSearchImpl =
+ AppSearchImpl.create(
+ appsearchDir,
+ context,
+ VisibilityStore.NO_OP_USER_ID,
+ /*globalQuerierPackage=*/ "");
+
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ appSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0);
+
+ // Add a document and persist it.
+ GenericDocument document =
+ new GenericDocument.Builder<>("namespace1", "uri1", "type").build();
+ appSearchImpl.putDocument("package", "database", document, /*logger=*/ null);
+ appSearchImpl.persistToDisk(PersistType.Code.LITE);
+
+ GenericDocument getResult =
+ appSearchImpl.getDocument(
+ "package", "database", "namespace1", "uri1", Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document);
+
+ // That document should be visible even from another instance.
+ AppSearchImpl appSearchImpl2 =
+ AppSearchImpl.create(
+ appsearchDir,
+ context,
+ VisibilityStore.NO_OP_USER_ID,
+ /*globalQuerierPackage=*/ "");
+ getResult =
+ appSearchImpl2.getDocument(
+ "package", "database", "namespace1", "uri1", Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document);
+ }
+
+ @Test
+ public void testDeletePersistsWithLiteFlush() throws Exception {
+ // Setup the index
+ Context context = ApplicationProvider.getApplicationContext();
+ File appsearchDir = mTemporaryFolder.newFolder();
+ AppSearchImpl appSearchImpl =
+ AppSearchImpl.create(
+ appsearchDir,
+ context,
+ VisibilityStore.NO_OP_USER_ID,
+ /*globalQuerierPackage=*/ "");
+
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ appSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0);
+
+ // Add two documents and persist them.
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("namespace1", "uri1", "type").build();
+ appSearchImpl.putDocument("package", "database", document1, /*logger=*/ null);
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("namespace1", "uri2", "type").build();
+ appSearchImpl.putDocument("package", "database", document2, /*logger=*/ null);
+ appSearchImpl.persistToDisk(PersistType.Code.LITE);
+
+ GenericDocument getResult =
+ appSearchImpl.getDocument(
+ "package", "database", "namespace1", "uri1", Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document1);
+ getResult =
+ appSearchImpl.getDocument(
+ "package", "database", "namespace1", "uri2", Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document2);
+
+ // Delete the first document
+ appSearchImpl.remove("package", "database", "namespace1", "uri1");
+ appSearchImpl.persistToDisk(PersistType.Code.LITE);
+ expectThrows(
+ AppSearchException.class,
+ () ->
+ appSearchImpl.getDocument(
+ "package",
+ "database",
+ "namespace1",
+ "uri1",
+ Collections.emptyMap()));
+ getResult =
+ appSearchImpl.getDocument(
+ "package", "database", "namespace1", "uri2", Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document2);
+
+ // Only the second document should be retrievable from another instance.
+ AppSearchImpl appSearchImpl2 =
+ AppSearchImpl.create(
+ appsearchDir,
+ context,
+ VisibilityStore.NO_OP_USER_ID,
+ /*globalQuerierPackage=*/ "");
+ expectThrows(
+ AppSearchException.class,
+ () ->
+ appSearchImpl2.getDocument(
+ "package",
+ "database",
+ "namespace1",
+ "uri1",
+ Collections.emptyMap()));
+ getResult =
+ appSearchImpl2.getDocument(
+ "package", "database", "namespace1", "uri2", Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document2);
+ }
+
+ @Test
+ public void testDeleteByQueryPersistsWithLiteFlush() throws Exception {
+ // Setup the index
+ Context context = ApplicationProvider.getApplicationContext();
+ File appsearchDir = mTemporaryFolder.newFolder();
+ AppSearchImpl appSearchImpl =
+ AppSearchImpl.create(
+ appsearchDir,
+ context,
+ VisibilityStore.NO_OP_USER_ID,
+ /*globalQuerierPackage=*/ "");
+
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ appSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0);
+
+ // Add two documents and persist them.
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("namespace1", "uri1", "type").build();
+ appSearchImpl.putDocument("package", "database", document1, /*logger=*/ null);
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("namespace2", "uri2", "type").build();
+ appSearchImpl.putDocument("package", "database", document2, /*logger=*/ null);
+ appSearchImpl.persistToDisk(PersistType.Code.LITE);
+
+ GenericDocument getResult =
+ appSearchImpl.getDocument(
+ "package", "database", "namespace1", "uri1", Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document1);
+ getResult =
+ appSearchImpl.getDocument(
+ "package", "database", "namespace2", "uri2", Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document2);
+
+ // Delete the first document
+ appSearchImpl.removeByQuery(
+ "package",
+ "database",
+ "",
+ new SearchSpec.Builder()
+ .addFilterNamespaces("namespace1")
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build());
+ appSearchImpl.persistToDisk(PersistType.Code.LITE);
+ expectThrows(
+ AppSearchException.class,
+ () ->
+ appSearchImpl.getDocument(
+ "package",
+ "database",
+ "namespace1",
+ "uri1",
+ Collections.emptyMap()));
+ getResult =
+ appSearchImpl.getDocument(
+ "package", "database", "namespace2", "uri2", Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document2);
+
+ // Only the second document should be retrievable from another instance.
+ AppSearchImpl appSearchImpl2 =
+ AppSearchImpl.create(
+ appsearchDir,
+ context,
+ VisibilityStore.NO_OP_USER_ID,
+ /*globalQuerierPackage=*/ "");
+ expectThrows(
+ AppSearchException.class,
+ () ->
+ appSearchImpl2.getDocument(
+ "package",
+ "database",
+ "namespace1",
+ "uri1",
+ Collections.emptyMap()));
+ getResult =
+ appSearchImpl2.getDocument(
+ "package", "database", "namespace2", "uri2", Collections.emptyMap());
+ assertThat(getResult).isEqualTo(document2);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverterTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverterTest.java
index 70e1e05174ef..63f031722ede 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverterTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverterTest.java
@@ -21,35 +21,50 @@ import static com.google.common.truth.Truth.assertThat;
import android.app.appsearch.GenericDocument;
import com.android.server.appsearch.proto.DocumentProto;
+import com.android.server.appsearch.proto.PropertyConfigProto;
import com.android.server.appsearch.proto.PropertyProto;
+import com.android.server.appsearch.proto.SchemaTypeConfigProto;
import com.android.server.appsearch.protobuf.ByteString;
+import com.google.common.collect.ImmutableMap;
+
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
public class GenericDocumentToProtoConverterTest {
private static final byte[] BYTE_ARRAY_1 = new byte[] {(byte) 1, (byte) 2, (byte) 3};
private static final byte[] BYTE_ARRAY_2 = new byte[] {(byte) 4, (byte) 5, (byte) 6, (byte) 7};
+ private static final String SCHEMA_TYPE_1 = "sDocumentPropertiesSchemaType1";
+ private static final String SCHEMA_TYPE_2 = "sDocumentPropertiesSchemaType2";
private static final GenericDocument DOCUMENT_PROPERTIES_1 =
new GenericDocument.Builder<GenericDocument.Builder<?>>(
- "namespace", "sDocumentProperties1", "sDocumentPropertiesSchemaType1")
+ "namespace", "sDocumentProperties1", SCHEMA_TYPE_1)
.setCreationTimestampMillis(12345L)
.build();
private static final GenericDocument DOCUMENT_PROPERTIES_2 =
new GenericDocument.Builder<GenericDocument.Builder<?>>(
- "namespace", "sDocumentProperties2", "sDocumentPropertiesSchemaType2")
+ "namespace", "sDocumentProperties2", SCHEMA_TYPE_2)
.setCreationTimestampMillis(6789L)
.build();
+ private static final SchemaTypeConfigProto SCHEMA_PROTO_1 =
+ SchemaTypeConfigProto.newBuilder().setSchemaType(SCHEMA_TYPE_1).build();
+ private static final SchemaTypeConfigProto SCHEMA_PROTO_2 =
+ SchemaTypeConfigProto.newBuilder().setSchemaType(SCHEMA_TYPE_2).build();
+ private static final String PREFIX = "package$databaseName/";
+ private static final Map<String, SchemaTypeConfigProto> SCHEMA_MAP =
+ ImmutableMap.of(
+ PREFIX + SCHEMA_TYPE_1, SCHEMA_PROTO_1, PREFIX + SCHEMA_TYPE_2, SCHEMA_PROTO_2);
@Test
public void testDocumentProtoConvert() {
GenericDocument document =
new GenericDocument.Builder<GenericDocument.Builder<?>>(
- "namespace", "uri1", "schemaType1")
+ "namespace", "uri1", SCHEMA_TYPE_1)
.setCreationTimestampMillis(5L)
.setScore(1)
.setTtlMillis(1L)
@@ -66,7 +81,7 @@ public class GenericDocumentToProtoConverterTest {
DocumentProto.Builder documentProtoBuilder =
DocumentProto.newBuilder()
.setUri("uri1")
- .setSchema("schemaType1")
+ .setSchema(SCHEMA_TYPE_1)
.setCreationTimestampMs(5L)
.setScore(1)
.setTtlMs(1L)
@@ -109,9 +124,133 @@ public class GenericDocumentToProtoConverterTest {
documentProtoBuilder.addProperties(propertyProtoMap.get(key));
}
DocumentProto documentProto = documentProtoBuilder.build();
- assertThat(GenericDocumentToProtoConverter.toDocumentProto(document))
- .isEqualTo(documentProto);
- assertThat(document)
- .isEqualTo(GenericDocumentToProtoConverter.toGenericDocument(documentProto));
+
+ GenericDocument convertedGenericDocument =
+ GenericDocumentToProtoConverter.toGenericDocument(
+ documentProto, PREFIX, SCHEMA_MAP);
+ DocumentProto convertedDocumentProto =
+ GenericDocumentToProtoConverter.toDocumentProto(document);
+
+ assertThat(convertedDocumentProto).isEqualTo(documentProto);
+ assertThat(convertedGenericDocument).isEqualTo(document);
+ }
+
+ @Test
+ public void testConvertDocument_whenPropertyHasEmptyList() {
+ String emptyStringPropertyName = "emptyStringProperty";
+ DocumentProto documentProto =
+ DocumentProto.newBuilder()
+ .setUri("uri1")
+ .setSchema(SCHEMA_TYPE_1)
+ .setCreationTimestampMs(5L)
+ .setNamespace("namespace")
+ .addProperties(
+ PropertyProto.newBuilder().setName(emptyStringPropertyName).build())
+ .build();
+
+ PropertyConfigProto emptyStringListProperty =
+ PropertyConfigProto.newBuilder()
+ .setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED)
+ .setDataType(PropertyConfigProto.DataType.Code.STRING)
+ .setPropertyName(emptyStringPropertyName)
+ .build();
+ SchemaTypeConfigProto schemaTypeConfigProto =
+ SchemaTypeConfigProto.newBuilder()
+ .addProperties(emptyStringListProperty)
+ .setSchemaType(SCHEMA_TYPE_1)
+ .build();
+ Map<String, SchemaTypeConfigProto> schemaMap =
+ ImmutableMap.of(PREFIX + SCHEMA_TYPE_1, schemaTypeConfigProto);
+
+ GenericDocument convertedDocument =
+ GenericDocumentToProtoConverter.toGenericDocument(documentProto, PREFIX, schemaMap);
+
+ GenericDocument expectedDocument =
+ new GenericDocument.Builder<GenericDocument.Builder<?>>(
+ "namespace", "uri1", SCHEMA_TYPE_1)
+ .setCreationTimestampMillis(5L)
+ .setPropertyString(emptyStringPropertyName)
+ .build();
+ assertThat(convertedDocument).isEqualTo(expectedDocument);
+ assertThat(expectedDocument.getPropertyStringArray(emptyStringPropertyName)).isEmpty();
+ }
+
+ @Test
+ public void testConvertDocument_whenNestedDocumentPropertyHasEmptyList() {
+ String emptyStringPropertyName = "emptyStringProperty";
+ String documentPropertyName = "documentProperty";
+ DocumentProto nestedDocumentProto =
+ DocumentProto.newBuilder()
+ .setUri("uri2")
+ .setSchema(SCHEMA_TYPE_2)
+ .setCreationTimestampMs(5L)
+ .setNamespace("namespace")
+ .addProperties(
+ PropertyProto.newBuilder().setName(emptyStringPropertyName).build())
+ .build();
+ DocumentProto documentProto =
+ DocumentProto.newBuilder()
+ .setUri("uri1")
+ .setSchema(SCHEMA_TYPE_1)
+ .setCreationTimestampMs(5L)
+ .setNamespace("namespace")
+ .addProperties(
+ PropertyProto.newBuilder()
+ .addDocumentValues(nestedDocumentProto)
+ .setName(documentPropertyName)
+ .build())
+ .build();
+
+ PropertyConfigProto documentProperty =
+ PropertyConfigProto.newBuilder()
+ .setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED)
+ .setDataType(PropertyConfigProto.DataType.Code.DOCUMENT)
+ .setPropertyName(documentPropertyName)
+ .setSchemaType(SCHEMA_TYPE_2)
+ .build();
+ SchemaTypeConfigProto schemaTypeConfigProto =
+ SchemaTypeConfigProto.newBuilder()
+ .addProperties(documentProperty)
+ .setSchemaType(SCHEMA_TYPE_1)
+ .build();
+ PropertyConfigProto emptyStringListProperty =
+ PropertyConfigProto.newBuilder()
+ .setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED)
+ .setDataType(PropertyConfigProto.DataType.Code.STRING)
+ .setPropertyName(emptyStringPropertyName)
+ .build();
+ SchemaTypeConfigProto nestedSchemaTypeConfigProto =
+ SchemaTypeConfigProto.newBuilder()
+ .addProperties(emptyStringListProperty)
+ .setSchemaType(SCHEMA_TYPE_2)
+ .build();
+ Map<String, SchemaTypeConfigProto> schemaMap =
+ ImmutableMap.of(
+ PREFIX + SCHEMA_TYPE_1,
+ schemaTypeConfigProto,
+ PREFIX + SCHEMA_TYPE_2,
+ nestedSchemaTypeConfigProto);
+
+ GenericDocument convertedDocument =
+ GenericDocumentToProtoConverter.toGenericDocument(documentProto, PREFIX, schemaMap);
+
+ GenericDocument expectedDocument =
+ new GenericDocument.Builder<GenericDocument.Builder<?>>(
+ "namespace", "uri1", SCHEMA_TYPE_1)
+ .setCreationTimestampMillis(5L)
+ .setPropertyDocument(
+ documentPropertyName,
+ new GenericDocument.Builder<GenericDocument.Builder<?>>(
+ "namespace", "uri2", SCHEMA_TYPE_2)
+ .setCreationTimestampMillis(5L)
+ .setPropertyString(emptyStringPropertyName)
+ .build())
+ .build();
+ assertThat(convertedDocument).isEqualTo(expectedDocument);
+ assertThat(
+ expectedDocument
+ .getPropertyDocument(documentPropertyName)
+ .getPropertyStringArray(emptyStringPropertyName))
+ .isEmpty();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
index d07211fe2028..26fac492ccd2 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
@@ -21,8 +21,10 @@ import static com.google.common.truth.Truth.assertThat;
import android.app.appsearch.SearchResult;
import android.app.appsearch.SearchResultPage;
+import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
import com.android.server.appsearch.proto.DocumentProto;
import com.android.server.appsearch.proto.PropertyProto;
+import com.android.server.appsearch.proto.SchemaTypeConfigProto;
import com.android.server.appsearch.proto.SearchResultProto;
import com.android.server.appsearch.proto.SnippetMatchProto;
import com.android.server.appsearch.proto.SnippetProto;
@@ -30,20 +32,29 @@ import com.android.server.appsearch.proto.SnippetProto;
import org.junit.Test;
import java.util.Collections;
+import java.util.Map;
public class SnippetTest {
+ private static final String SCHEMA_TYPE = "schema1";
+ private static final String PACKAGE_NAME = "packageName";
+ private static final String DATABASE_NAME = "databaseName";
+ private static final String PREFIX = PrefixUtil.createPrefix(PACKAGE_NAME, DATABASE_NAME);
+ private static final SchemaTypeConfigProto SCHEMA_TYPE_CONFIG_PROTO =
+ SchemaTypeConfigProto.newBuilder().setSchemaType(PREFIX + SCHEMA_TYPE).build();
+ private static final Map<String, Map<String, SchemaTypeConfigProto>> SCHEMA_MAP =
+ Collections.singletonMap(
+ PREFIX,
+ Collections.singletonMap(PREFIX + SCHEMA_TYPE, SCHEMA_TYPE_CONFIG_PROTO));
// TODO(tytytyww): Add tests for Double and Long Snippets.
@Test
public void testSingleStringSnippet() {
-
final String propertyKeyString = "content";
final String propertyValueString =
"A commonly used fake word is foo.\n"
+ " Another nonsense word that’s used a lot\n"
+ " is bar.\n";
final String uri = "uri1";
- final String schemaType = "schema1";
final String searchWord = "foo";
final String exactMatch = "foo";
final String window = "is foo";
@@ -57,7 +68,7 @@ public class SnippetTest {
DocumentProto documentProto =
DocumentProto.newBuilder()
.setUri(uri)
- .setSchema(schemaType)
+ .setSchema(SCHEMA_TYPE)
.addProperties(property)
.build();
SnippetProto snippetProto =
@@ -86,8 +97,9 @@ public class SnippetTest {
SearchResultPage searchResultPage =
SearchResultToProtoConverter.toSearchResultPage(
searchResultProto,
- Collections.singletonList("packageName"),
- Collections.singletonList("databaseName"));
+ Collections.singletonList(PACKAGE_NAME),
+ Collections.singletonList(DATABASE_NAME),
+ SCHEMA_MAP);
for (SearchResult result : searchResultPage.getResults()) {
SearchResult.MatchInfo match = result.getMatches().get(0);
assertThat(match.getPropertyPath()).isEqualTo(propertyKeyString);
@@ -112,7 +124,6 @@ public class SnippetTest {
+ " Another nonsense word that’s used a lot\n"
+ " is bar.\n";
final String uri = "uri1";
- final String schemaType = "schema1";
final String searchWord = "foo";
final String exactMatch = "foo";
final String window = "is foo";
@@ -126,7 +137,7 @@ public class SnippetTest {
DocumentProto documentProto =
DocumentProto.newBuilder()
.setUri(uri)
- .setSchema(schemaType)
+ .setSchema(SCHEMA_TYPE)
.addProperties(property)
.build();
SearchResultProto.ResultProto resultProto =
@@ -137,8 +148,9 @@ public class SnippetTest {
SearchResultPage searchResultPage =
SearchResultToProtoConverter.toSearchResultPage(
searchResultProto,
- Collections.singletonList("packageName"),
- Collections.singletonList("databaseName"));
+ Collections.singletonList(PACKAGE_NAME),
+ Collections.singletonList(DATABASE_NAME),
+ SCHEMA_MAP);
for (SearchResult result : searchResultPage.getResults()) {
assertThat(result.getMatches()).isEmpty();
}
@@ -162,7 +174,7 @@ public class SnippetTest {
DocumentProto documentProto =
DocumentProto.newBuilder()
.setUri("uri1")
- .setSchema("schema1")
+ .setSchema(SCHEMA_TYPE)
.addProperties(property1)
.addProperties(property2)
.build();
@@ -203,8 +215,9 @@ public class SnippetTest {
SearchResultPage searchResultPage =
SearchResultToProtoConverter.toSearchResultPage(
searchResultProto,
- Collections.singletonList("packageName"),
- Collections.singletonList("databaseName"));
+ Collections.singletonList(PACKAGE_NAME),
+ Collections.singletonList(DATABASE_NAME),
+ SCHEMA_MAP);
for (SearchResult result : searchResultPage.getResults()) {
SearchResult.MatchInfo match1 = result.getMatches().get(0);