VisibilityStoreMigrationHelperFromV1.java
/*
* Copyright 2022 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 androidx.appsearch.localstorage.visibilitystore;
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
import androidx.appsearch.app.AppSearchResult;
import androidx.appsearch.app.PackageIdentifier;
import androidx.appsearch.app.SetSchemaRequest;
import androidx.appsearch.app.VisibilityDocument;
import androidx.appsearch.exceptions.AppSearchException;
import androidx.appsearch.localstorage.AppSearchImpl;
import androidx.appsearch.localstorage.util.PrefixUtil;
import androidx.collection.ArraySet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* The helper class to store Visibility Document information of version 1 and handle the upgrade to
* latest version
*
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class VisibilityStoreMigrationHelperFromV1 {
private VisibilityStoreMigrationHelperFromV1() {}
/** Enum in {@link androidx.appsearch.app.SetSchemaRequest} AppSearch supported role. */
@VisibleForTesting
static final int DEPRECATED_ROLE_HOME = 1;
/** Enum in {@link androidx.appsearch.app.SetSchemaRequest} AppSearch supported role. */
@VisibleForTesting
static final int DEPRECATED_ROLE_ASSISTANT = 2;
/** Reads all stored deprecated Visibility Document in version 0 from icing. */
static List<VisibilityDocumentV1> getVisibilityDocumentsInVersion1(
@NonNull AppSearchImpl appSearchImpl) throws AppSearchException {
List<String> allPrefixedSchemaTypes = appSearchImpl.getAllPrefixedSchemaTypes();
List<VisibilityDocumentV1> visibilityDocumentV1s =
new ArrayList<>(allPrefixedSchemaTypes.size());
for (int i = 0; i < allPrefixedSchemaTypes.size(); i++) {
String packageName = PrefixUtil.getPackageName(allPrefixedSchemaTypes.get(i));
if (packageName.equals(VisibilityStore.VISIBILITY_PACKAGE_NAME)) {
continue; // Our own package. Skip.
}
try {
// Note: We use the prefixed schema type as ids
visibilityDocumentV1s.add(new VisibilityDocumentV1(appSearchImpl.getDocument(
VisibilityStore.VISIBILITY_PACKAGE_NAME,
VisibilityStore.VISIBILITY_DATABASE_NAME,
VisibilityDocument.NAMESPACE,
allPrefixedSchemaTypes.get(i),
/*typePropertyPaths=*/ Collections.emptyMap())));
} catch (AppSearchException e) {
if (e.getResultCode() == AppSearchResult.RESULT_NOT_FOUND) {
// TODO(b/172068212): This indicates some desync error. We were expecting a
// document, but didn't find one. Should probably reset AppSearch instead
// of ignoring it.
continue;
}
// Otherwise, this is some other error we should pass up.
throw e;
}
}
return visibilityDocumentV1s;
}
/**
* Converts the given list of deprecated Visibility Documents into a Map of {@code
* <PrefixedSchemaType, VisibilityDocument.Builder of the latest version>}.
*
* @param visibilityDocumentV1s The deprecated Visibility Document we found.
*/
@NonNull
static List<VisibilityDocument> toVisibilityDocumentsV2(
@NonNull List<VisibilityDocumentV1> visibilityDocumentV1s) {
List<VisibilityDocument> latestVisibilityDocuments =
new ArrayList<>(visibilityDocumentV1s.size());
for (int i = 0; i < visibilityDocumentV1s.size(); i++) {
VisibilityDocumentV1 visibilityDocumentV1 = visibilityDocumentV1s.get(i);
Set<Set<Integer>> visibleToPermissions = new ArraySet<>();
Set<Integer> deprecatedVisibleToRoles = visibilityDocumentV1.getVisibleToRoles();
if (deprecatedVisibleToRoles != null) {
for (int deprecatedVisibleToRole : deprecatedVisibleToRoles) {
Set<Integer> visibleToPermission = new ArraySet<>();
switch (deprecatedVisibleToRole) {
case DEPRECATED_ROLE_HOME:
visibleToPermission.add(SetSchemaRequest.READ_HOME_APP_SEARCH_DATA);
break;
case DEPRECATED_ROLE_ASSISTANT:
visibleToPermission.add(SetSchemaRequest
.READ_ASSISTANT_APP_SEARCH_DATA);
break;
}
visibleToPermissions.add(visibleToPermission);
}
}
Set<Integer> deprecatedVisibleToPermissions =
visibilityDocumentV1.getVisibleToPermissions();
if (deprecatedVisibleToPermissions != null) {
visibleToPermissions.add(deprecatedVisibleToPermissions);
}
Set<PackageIdentifier> packageIdentifiers = new ArraySet<>();
String[] packageNames = visibilityDocumentV1.getPackageNames();
byte[][] sha256Certs = visibilityDocumentV1.getSha256Certs();
if (packageNames.length == sha256Certs.length) {
for (int j = 0; j < packageNames.length; j++) {
packageIdentifiers.add(new PackageIdentifier(packageNames[j], sha256Certs[j]));
}
}
VisibilityDocument.Builder latestVisibilityDocumentBuilder =
new VisibilityDocument.Builder(visibilityDocumentV1.getId())
.setNotDisplayedBySystem(visibilityDocumentV1.isNotDisplayedBySystem())
.addVisibleToPackages(packageIdentifiers);
if (!visibleToPermissions.isEmpty()) {
latestVisibilityDocumentBuilder.setVisibleToPermissions(visibleToPermissions);
}
latestVisibilityDocuments.add(latestVisibilityDocumentBuilder.build());
}
return latestVisibilityDocuments;
}
}