Refactor VisibilityStore's docs and maps to separate objects.

This reduces the volume of code VisibilityStore has to manage.

Bug: 169883602
Test: VisibilityStoreTest
Change-Id: I422f1c5f35fd4ded49cbd102530c574092bb4a74
This commit is contained in:
Alexander Dorokhine
2021-05-12 15:10:16 -07:00
parent ff3c817ba8
commit 487406300a
5 changed files with 381 additions and 161 deletions

View File

@@ -36,6 +36,10 @@ import android.util.ArraySet;
import android.util.Log;
import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
import com.android.server.appsearch.visibilitystore.NotPlatformSurfaceableMap;
import com.android.server.appsearch.visibilitystore.PackageAccessibleDocument;
import com.android.server.appsearch.visibilitystore.PackageAccessibleMap;
import com.android.server.appsearch.visibilitystore.VisibilityDocument;
import com.google.android.icing.proto.PersistType;
@@ -74,73 +78,9 @@ public class VisibilityStore {
/** No-op user id that won't have any visibility settings. */
public static final int NO_OP_USER_ID = -1;
/** Schema type for documents that hold AppSearch's metadata, e.g. visibility settings */
private static final String VISIBILITY_TYPE = "VisibilityType";
/** Version for the visibility schema */
private static final int SCHEMA_VERSION = 0;
/**
* Property that holds the list of platform-hidden schemas, as part of the visibility settings.
*/
private static final String NOT_PLATFORM_SURFACEABLE_PROPERTY = "notPlatformSurfaceable";
/** Property that holds nested documents of package accessible schemas. */
private static final String PACKAGE_ACCESSIBLE_PROPERTY = "packageAccessible";
/** Schema type for nested documents that hold package accessible information. */
private static final String PACKAGE_ACCESSIBLE_TYPE = "PackageAccessibleType";
/** Property that holds the package name that can access a schema. */
private static final String PACKAGE_NAME_PROPERTY = "packageName";
/** Property that holds the SHA 256 certificate of the app that can access a schema. */
private static final String SHA_256_CERT_PROPERTY = "sha256Cert";
/** Property that holds the prefixed schema type that is accessible by some package. */
private static final String ACCESSIBLE_SCHEMA_PROPERTY = "accessibleSchema";
/** Schema for the VisibilityStore's documents. */
private static final AppSearchSchema VISIBILITY_SCHEMA =
new AppSearchSchema.Builder(VISIBILITY_TYPE)
.addProperty(
new AppSearchSchema.StringPropertyConfig.Builder(
NOT_PLATFORM_SURFACEABLE_PROPERTY)
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.build())
.addProperty(
new AppSearchSchema.DocumentPropertyConfig.Builder(
PACKAGE_ACCESSIBLE_PROPERTY, PACKAGE_ACCESSIBLE_TYPE)
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.build())
.build();
/**
* Schema for package accessible documents, these will be nested in a top-level visibility
* document.
*/
private static final AppSearchSchema PACKAGE_ACCESSIBLE_SCHEMA =
new AppSearchSchema.Builder(PACKAGE_ACCESSIBLE_TYPE)
.addProperty(
new AppSearchSchema.StringPropertyConfig.Builder(PACKAGE_NAME_PROPERTY)
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.build())
.addProperty(
new AppSearchSchema.BytesPropertyConfig.Builder(SHA_256_CERT_PROPERTY)
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.build())
.addProperty(
new AppSearchSchema.StringPropertyConfig.Builder(
ACCESSIBLE_SCHEMA_PROPERTY)
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.build())
.build();
/**
* These cannot have any of the special characters used by AppSearchImpl (e.g. {@code
* AppSearchImpl#PACKAGE_DELIMITER} or {@code AppSearchImpl#DATABASE_DELIMITER}.
@@ -177,24 +117,12 @@ public class VisibilityStore {
// platform-surfaceable content.
private int mGlobalQuerierUid;
/**
* Maps prefixes to the set of schemas that are platform-hidden within that prefix. All schemas
* in the map are prefixed.
*
* <p>Although the prefix key isn't used for lookup, it's helpful in ensuring that all previous
* visibility settings for a prefix are completely overridden by new visibility settings.
*/
private final Map<String, Set<String>> mNotPlatformSurfaceableMap = new ArrayMap<>();
/** Stores the schemas that are platform-hidden. All values are prefixed. */
private final NotPlatformSurfaceableMap mNotPlatformSurfaceableMap =
new NotPlatformSurfaceableMap();
/**
* Maps prefixes to a an internal map. The internal map maps prefixed schemas to the set of
* PackageIdentifiers that have access to that schema.
*
* <p>Although the prefix key isn't used for lookup, it's helpful in ensuring that all previous
* visibility settings for a prefix are completely overridden by new visibility settings.
*/
private final Map<String, Map<String, Set<PackageIdentifier>>> mPackageAccessibleMap =
new ArrayMap<>();
/** Stores the schemas that are package accessible. All values are prefixed. */
private final PackageAccessibleMap mPackageAccessibleMap = new PackageAccessibleMap();
/**
* Creates an uninitialized VisibilityStore object. Callers must also call {@link #initialize()}
@@ -228,9 +156,9 @@ public class VisibilityStore {
boolean hasVisibilityType = false;
boolean hasPackageAccessibleType = false;
for (AppSearchSchema schema : getSchemaResponse.getSchemas()) {
if (schema.getSchemaType().equals(VISIBILITY_TYPE)) {
if (schema.getSchemaType().equals(VisibilityDocument.SCHEMA_TYPE)) {
hasVisibilityType = true;
} else if (schema.getSchemaType().equals(PACKAGE_ACCESSIBLE_TYPE)) {
} else if (schema.getSchemaType().equals(PackageAccessibleDocument.SCHEMA_TYPE)) {
hasPackageAccessibleType = true;
}
@@ -244,7 +172,7 @@ public class VisibilityStore {
mAppSearchImpl.setSchema(
PACKAGE_NAME,
DATABASE_NAME,
Arrays.asList(VISIBILITY_SCHEMA, PACKAGE_ACCESSIBLE_SCHEMA),
Arrays.asList(VisibilityDocument.SCHEMA, PackageAccessibleDocument.SCHEMA),
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -261,40 +189,34 @@ public class VisibilityStore {
try {
// Note: We use the other clients' prefixed names as ids
GenericDocument document =
VisibilityDocument visibilityDocument = new VisibilityDocument(
mAppSearchImpl.getDocument(
PACKAGE_NAME,
DATABASE_NAME,
NAMESPACE,
/*id=*/ addIdPrefix(prefix),
/*typePropertyPaths=*/ Collections.emptyMap());
/*typePropertyPaths=*/ Collections.emptyMap()));
// Update platform visibility settings
String[] notPlatformSurfaceableSchemas =
document.getPropertyStringArray(NOT_PLATFORM_SURFACEABLE_PROPERTY);
visibilityDocument.getNotPlatformSurfaceableSchemas();
if (notPlatformSurfaceableSchemas != null) {
mNotPlatformSurfaceableMap.put(
prefix, new ArraySet<>(Arrays.asList(notPlatformSurfaceableSchemas)));
mNotPlatformSurfaceableMap.setNotPlatformSurfaceable(
prefix,
new ArraySet<>(notPlatformSurfaceableSchemas));
}
// Update 3p package visibility settings
Map<String, Set<PackageIdentifier>> schemaToPackageIdentifierMap = new ArrayMap<>();
GenericDocument[] packageAccessibleDocuments =
document.getPropertyDocumentArray(PACKAGE_ACCESSIBLE_PROPERTY);
visibilityDocument.getPackageAccessibleSchemas();
if (packageAccessibleDocuments != null) {
for (int i = 0; i < packageAccessibleDocuments.length; i++) {
String packageName =
packageAccessibleDocuments[i].getPropertyString(
PACKAGE_NAME_PROPERTY);
byte[] sha256Cert =
packageAccessibleDocuments[i].getPropertyBytes(
SHA_256_CERT_PROPERTY);
PackageAccessibleDocument packageAccessibleDocument =
new PackageAccessibleDocument(packageAccessibleDocuments[i]);
PackageIdentifier packageIdentifier =
new PackageIdentifier(packageName, sha256Cert);
String prefixedSchema =
packageAccessibleDocuments[i].getPropertyString(
ACCESSIBLE_SCHEMA_PROPERTY);
packageAccessibleDocument.getPackageIdentifier();
String prefixedSchema = packageAccessibleDocument.getAccessibleSchemaType();
Set<PackageIdentifier> packageIdentifiers =
schemaToPackageIdentifierMap.get(prefixedSchema);
if (packageIdentifiers == null) {
@@ -304,7 +226,7 @@ public class VisibilityStore {
schemaToPackageIdentifierMap.put(prefixedSchema, packageIdentifiers);
}
}
mPackageAccessibleMap.put(prefix, schemaToPackageIdentifierMap);
mPackageAccessibleMap.setPackageAccessible(prefix, schemaToPackageIdentifierMap);
} catch (AppSearchException e) {
if (e.getResultCode() == AppSearchResult.RESULT_NOT_FOUND) {
// TODO(b/172068212): This indicates some desync error. We were expecting a
@@ -339,38 +261,30 @@ public class VisibilityStore {
Objects.requireNonNull(schemasPackageAccessible);
// Persist the document
GenericDocument.Builder<?> visibilityDocument =
new GenericDocument.Builder<>(
NAMESPACE, /*id=*/ addIdPrefix(prefix), VISIBILITY_TYPE);
VisibilityDocument.Builder visibilityDocument =
new VisibilityDocument.Builder(NAMESPACE, /*id=*/ addIdPrefix(prefix));
if (!schemasNotPlatformSurfaceable.isEmpty()) {
visibilityDocument.setPropertyString(
NOT_PLATFORM_SURFACEABLE_PROPERTY,
visibilityDocument.setSchemasNotPlatformSurfaceable(
schemasNotPlatformSurfaceable.toArray(new String[0]));
}
Map<String, Set<PackageIdentifier>> schemaToPackageIdentifierMap = new ArrayMap<>();
List<GenericDocument> packageAccessibleDocuments = new ArrayList<>();
List<PackageAccessibleDocument> packageAccessibleDocuments = new ArrayList<>();
for (Map.Entry<String, List<PackageIdentifier>> entry :
schemasPackageAccessible.entrySet()) {
for (int i = 0; i < entry.getValue().size(); i++) {
GenericDocument packageAccessibleDocument = new GenericDocument.Builder<>(
NAMESPACE, /*id=*/ "", PACKAGE_ACCESSIBLE_TYPE)
.setPropertyString(
PACKAGE_NAME_PROPERTY,
entry.getValue().get(i).getPackageName())
.setPropertyBytes(
SHA_256_CERT_PROPERTY,
entry.getValue().get(i).getSha256Certificate())
.setPropertyString(ACCESSIBLE_SCHEMA_PROPERTY, entry.getKey())
.build();
PackageAccessibleDocument packageAccessibleDocument =
new PackageAccessibleDocument.Builder(NAMESPACE, /*id=*/ "")
.setAccessibleSchemaType(entry.getKey())
.setPackageIdentifier(entry.getValue().get(i))
.build();
packageAccessibleDocuments.add(packageAccessibleDocument);
}
schemaToPackageIdentifierMap.put(entry.getKey(), new ArraySet<>(entry.getValue()));
}
if (!packageAccessibleDocuments.isEmpty()) {
visibilityDocument.setPropertyDocument(
PACKAGE_ACCESSIBLE_PROPERTY,
packageAccessibleDocuments.toArray(new GenericDocument[0]));
visibilityDocument.setPackageAccessibleSchemas(
packageAccessibleDocuments.toArray(new PackageAccessibleDocument[0]));
}
mAppSearchImpl.putDocument(
@@ -379,8 +293,8 @@ public class VisibilityStore {
mAppSearchImpl.persistToDisk(PersistType.Code.LITE);
// Update derived data structures.
mNotPlatformSurfaceableMap.put(prefix, schemasNotPlatformSurfaceable);
mPackageAccessibleMap.put(prefix, schemaToPackageIdentifierMap);
mNotPlatformSurfaceableMap.setNotPlatformSurfaceable(prefix, schemasNotPlatformSurfaceable);
mPackageAccessibleMap.setPackageAccessible(prefix, schemaToPackageIdentifierMap);
}
/** Checks whether {@code prefixedSchema} can be searched over by the {@code callerUid}. */
@@ -389,10 +303,14 @@ public class VisibilityStore {
Objects.requireNonNull(prefix);
Objects.requireNonNull(prefixedSchema);
if (prefix.equals(VISIBILITY_STORE_PREFIX)) {
return false; // VisibilityStore schemas are for internal bookkeeping.
}
// We compare appIds here rather than direct uids because the package's uid may change based
// on the user that's running.
if (UserHandle.isSameApp(mGlobalQuerierUid, callerUid)
&& isSchemaPlatformSurfaceable(prefix, prefixedSchema)) {
&& mNotPlatformSurfaceableMap.isSchemaPlatformSurfaceable(prefix, prefixedSchema)) {
return true;
}
@@ -400,29 +318,6 @@ public class VisibilityStore {
return isSchemaPackageAccessible(prefix, prefixedSchema, callerUid);
}
/**
* Returns whether the caller has platform query privileges, and if so, that the schema is
* surfaceable on the platform.
*/
private boolean isSchemaPlatformSurfaceable(
@NonNull String prefix, @NonNull String prefixedSchema) {
if (prefix.equals(VISIBILITY_STORE_PREFIX)) {
// VisibilityStore schemas are for internal bookkeeping.
return false;
}
Set<String> notPlatformSurfaceableSchemas = mNotPlatformSurfaceableMap.get(prefix);
if (notPlatformSurfaceableSchemas == null) {
// No schemas were opted out of being platform-surfaced. So by default, it can be
// surfaced.
return true;
}
// Some schemas were opted out of being platform-surfaced. As long as this schema
// isn't one of those opt-outs, it's surfaceable.
return !notPlatformSurfaceableSchemas.contains(prefixedSchema);
}
/**
* Returns whether the schema is accessible by the {@code callerUid}. Checks that the callerUid
* has one of the allowed PackageIdentifier's package. And if so, that the package also has the
@@ -434,20 +329,8 @@ public class VisibilityStore {
*/
private boolean isSchemaPackageAccessible(
@NonNull String prefix, @NonNull String prefixedSchema, int callerUid) {
Map<String, Set<PackageIdentifier>> schemaToPackageIdentifierMap =
mPackageAccessibleMap.get(prefix);
if (schemaToPackageIdentifierMap == null) {
// No schemas under this prefix have granted package access, return early.
return false;
}
Set<PackageIdentifier> packageIdentifiers =
schemaToPackageIdentifierMap.get(prefixedSchema);
if (packageIdentifiers == null) {
// No package identifiers were granted access for this schema, return early.
return false;
}
mPackageAccessibleMap.getAccessiblePackages(prefix, prefixedSchema);
for (PackageIdentifier packageIdentifier : packageIdentifiers) {
// Check that the caller uid matches this allowlisted PackageIdentifier.
// TODO(b/169883602): Consider caching the UIDs of packages. Looking this up in the
@@ -467,7 +350,6 @@ public class VisibilityStore {
return true;
}
}
// If we can't verify the schema is package accessible, default to no access.
return false;
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) 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.visibilitystore;
import android.annotation.NonNull;
import android.util.ArrayMap;
import java.util.Map;
import java.util.Set;
/**
* Stores information about what types are hidden from platform surfaces through the
* {@link android.app.appsearch.SetSchemaRequest.Builder#setSchemaTypeDisplayedBySystem} API.
*
* This object is not thread safe.
* @hide
*/
public class NotPlatformSurfaceableMap {
/**
* Maps prefixes to the set of prefixed schemas that are platform-hidden within that prefix.
*/
private final Map<String, Set<String>> mMap = new ArrayMap<>();
/**
* Sets the prefixed schemas that are opted out of platform surfacing for the prefix.
*
* <p>Any existing mappings for this prefix are overwritten.
*/
public void setNotPlatformSurfaceable(@NonNull String prefix, @NonNull Set<String> schemas) {
mMap.put(prefix, schemas);
}
/**
* Returns whether the given prefixed schema is platform surfaceable (has not opted out) in the
* given prefix.
*/
public boolean isSchemaPlatformSurfaceable(@NonNull String prefix, @NonNull String schemaType) {
Set<String> schemaTypes = mMap.get(prefix);
if (schemaTypes == null) {
// No opt-outs for this prefix
return true;
}
// Some schemas were opted out of being platform-surfaced. As long as this schema
// isn't one of those opt-outs, it's surfaceable.
return !schemaTypes.contains(schemaType);
}
/** Discards all data in the map. */
public void clear() {
mMap.clear();
}
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright (C) 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.visibilitystore;
import android.annotation.NonNull;
import android.app.appsearch.AppSearchSchema;
import android.app.appsearch.GenericDocument;
import android.app.appsearch.PackageIdentifier;
import androidx.annotation.Nullable;
/**
* Holds configuration about a package+cert that can access a schema.
*
* @see android.app.appsearch.SetSchemaRequest.Builder#setSchemaTypeVisibilityForPackage
* @hide
*/
public class PackageAccessibleDocument extends GenericDocument {
/** Schema type for nested documents that hold package accessible information. */
public static final String SCHEMA_TYPE = "PackageAccessibleType";
/** Property that holds the package name that can access a schema. */
private static final String PACKAGE_NAME_PROPERTY = "packageName";
/** Property that holds the SHA 256 certificate of the app that can access a schema. */
private static final String SHA_256_CERT_PROPERTY = "sha256Cert";
/** Property that holds the prefixed schema type that is accessible by some package. */
private static final String ACCESSIBLE_SCHEMA_PROPERTY = "accessibleSchema";
/**
* Schema for package accessible documents, these will be nested in a top-level
* {@link VisibilityDocument}.
*
* <p>NOTE: If you update this, also update
* {@link com.android.server.appsearch.external.localstorage.VisibilityStore#SCHEMA_VERSION}
*/
public static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder(PACKAGE_NAME_PROPERTY)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.build())
.addProperty(new AppSearchSchema.BytesPropertyConfig.Builder(SHA_256_CERT_PROPERTY)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.build())
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder(
ACCESSIBLE_SCHEMA_PROPERTY)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.build())
.build();
public PackageAccessibleDocument(@NonNull GenericDocument genericDocument) {
super(genericDocument);
}
@Nullable
public String getAccessibleSchemaType() {
return getPropertyString(ACCESSIBLE_SCHEMA_PROPERTY);
}
/** Gets which package is able to access {@link #getAccessibleSchemaType} */
@NonNull
public PackageIdentifier getPackageIdentifier() {
String packageName = getPropertyString(PACKAGE_NAME_PROPERTY);
byte[] sha256Cert = getPropertyBytes(SHA_256_CERT_PROPERTY);
return new PackageIdentifier(packageName, sha256Cert);
}
/** Builder for {@link PackageAccessibleDocument} instances. */
public static class Builder extends GenericDocument.Builder<PackageAccessibleDocument.Builder> {
public Builder(@NonNull String namespace, @NonNull String id) {
super(namespace, id, SCHEMA_TYPE);
}
/** Sets which prefixed schema type is accessible by the package */
@NonNull
public Builder setAccessibleSchemaType(@NonNull String schemaType) {
return setPropertyString(ACCESSIBLE_SCHEMA_PROPERTY, schemaType);
}
/** Sets which package is able to access the {@link #setAccessibleSchemaType}. */
@NonNull
public Builder setPackageIdentifier(@NonNull PackageIdentifier packageIdentifier) {
return setPropertyString(PACKAGE_NAME_PROPERTY, packageIdentifier.getPackageName())
.setPropertyBytes(SHA_256_CERT_PROPERTY,
packageIdentifier.getSha256Certificate());
}
@Override
@NonNull
public PackageAccessibleDocument build() {
return new PackageAccessibleDocument(super.build());
}
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 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.visibilitystore;
import android.annotation.NonNull;
import android.app.appsearch.PackageIdentifier;
import android.util.ArrayMap;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
/**
* Stores information about what types are accessible to which packages through the
* {@link android.app.appsearch.SetSchemaRequest.Builder#setSchemaTypeVisibilityForPackage} API.
*
* This object is not thread safe.
* @hide
*/
public class PackageAccessibleMap {
/**
* Maps prefixes to prefixed schema types to PackageIdentifiers that have access to that schema.
*/
private final Map<String, Map<String, Set<PackageIdentifier>>> mMap = new ArrayMap<>();
/**
* Sets the prefixed schemas that have package visibility in the given prefix.
*
* <p>Any existing mappings for this prefix are overwritten.
*/
public void setPackageAccessible(
@NonNull String prefix,
@NonNull Map<String, Set<PackageIdentifier>> schemaToPackageIdentifier) {
mMap.put(prefix, schemaToPackageIdentifier);
}
/**
* Returns the set of all {@link android.app.appsearch.PackageIdentifier}s which can access the
* given schema type.
*
* <p>If no such settings exist, returns the empty set.
*/
@NonNull
public Set<PackageIdentifier> getAccessiblePackages(
@NonNull String prefix, @NonNull String schemaType) {
Map<String, Set<PackageIdentifier>> schemaTypeToVisibility = mMap.get(prefix);
if (schemaTypeToVisibility == null) {
return Collections.emptySet();
}
Set<PackageIdentifier> accessiblePackages = schemaTypeToVisibility.get(schemaType);
if (accessiblePackages == null) {
return Collections.emptySet();
}
return accessiblePackages;
}
/** Discards all data in the map. */
public void clear() {
mMap.clear();
}
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright (C) 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.visibilitystore;
import android.annotation.NonNull;
import android.app.appsearch.AppSearchSchema;
import android.app.appsearch.GenericDocument;
import androidx.annotation.Nullable;
/**
* Holds the visibility settings that apply to a package's databases.
* @hide
*/
public class VisibilityDocument extends GenericDocument {
/** Schema type for documents that hold AppSearch's metadata, e.g. visibility settings */
public static final String SCHEMA_TYPE = "VisibilityType";
/**
* Property that holds the list of platform-hidden schemas, as part of the visibility settings.
*/
private static final String NOT_PLATFORM_SURFACEABLE_PROPERTY = "notPlatformSurfaceable";
/** Property that holds nested documents of package accessible schemas. */
private static final String PACKAGE_ACCESSIBLE_PROPERTY = "packageAccessible";
/**
* Schema for the VisibilityStore's documents.
*
* <p>NOTE: If you update this, also update
* {@link com.android.server.appsearch.external.localstorage.VisibilityStore#SCHEMA_VERSION}
*/
public static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder(
NOT_PLATFORM_SURFACEABLE_PROPERTY)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.build())
.addProperty(new AppSearchSchema.DocumentPropertyConfig.Builder(
PACKAGE_ACCESSIBLE_PROPERTY, PackageAccessibleDocument.SCHEMA_TYPE)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.build())
.build();
public VisibilityDocument(@NonNull GenericDocument genericDocument) {
super(genericDocument);
}
@Nullable
public String[] getNotPlatformSurfaceableSchemas() {
return getPropertyStringArray(NOT_PLATFORM_SURFACEABLE_PROPERTY);
}
@Nullable
public GenericDocument[] getPackageAccessibleSchemas() {
return getPropertyDocumentArray(PACKAGE_ACCESSIBLE_PROPERTY);
}
/** Builder for {@link VisibilityDocument}. */
public static class Builder extends GenericDocument.Builder<VisibilityDocument.Builder> {
public Builder(@NonNull String namespace, @NonNull String id) {
super(namespace, id, SCHEMA_TYPE);
}
/** Sets which prefixed schemas have opted out of platform surfacing. */
@NonNull
public Builder setSchemasNotPlatformSurfaceable(
@NonNull String[] notPlatformSurfaceableSchemas) {
return setPropertyString(
NOT_PLATFORM_SURFACEABLE_PROPERTY, notPlatformSurfaceableSchemas);
}
/** Sets which prefixed schemas have configured package access. */
@NonNull
public Builder setPackageAccessibleSchemas(
@NonNull PackageAccessibleDocument[] packageAccessibleSchemas) {
return setPropertyDocument(PACKAGE_ACCESSIBLE_PROPERTY, packageAccessibleSchemas);
}
}
}