1 /* 2 * Copyright 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.appsearch.external.localstorage.visibilitystore; 18 19 import android.annotation.NonNull; 20 import android.app.appsearch.AppSearchResult; 21 import android.app.appsearch.InternalVisibilityConfig; 22 import android.app.appsearch.PackageIdentifier; 23 import android.app.appsearch.SetSchemaRequest; 24 import android.app.appsearch.exceptions.AppSearchException; 25 import android.util.ArraySet; 26 27 import com.android.internal.annotations.VisibleForTesting; 28 import com.android.server.appsearch.external.localstorage.AppSearchImpl; 29 import com.android.server.appsearch.external.localstorage.util.PrefixUtil; 30 31 import java.util.ArrayList; 32 import java.util.Collections; 33 import java.util.List; 34 import java.util.Set; 35 36 /** 37 * The helper class to store Visibility Document information of version 1 and handle the upgrade to 38 * latest version 39 * 40 * @hide 41 */ 42 public class VisibilityStoreMigrationHelperFromV1 { VisibilityStoreMigrationHelperFromV1()43 private VisibilityStoreMigrationHelperFromV1() {} 44 45 /** Enum in {@link android.app.appsearch.SetSchemaRequest} AppSearch supported role. */ 46 @VisibleForTesting static final int DEPRECATED_ROLE_HOME = 1; 47 48 /** Enum in {@link android.app.appsearch.SetSchemaRequest} AppSearch supported role. */ 49 @VisibleForTesting static final int DEPRECATED_ROLE_ASSISTANT = 2; 50 51 /** Reads all stored deprecated Visibility Document in version 0 from icing. */ getVisibilityDocumentsInVersion1( @onNull AppSearchImpl appSearchImpl)52 static List<VisibilityDocumentV1> getVisibilityDocumentsInVersion1( 53 @NonNull AppSearchImpl appSearchImpl) throws AppSearchException { 54 List<String> allPrefixedSchemaTypes = appSearchImpl.getAllPrefixedSchemaTypes(); 55 List<VisibilityDocumentV1> visibilityDocumentV1s = 56 new ArrayList<>(allPrefixedSchemaTypes.size()); 57 for (int i = 0; i < allPrefixedSchemaTypes.size(); i++) { 58 String packageName = PrefixUtil.getPackageName(allPrefixedSchemaTypes.get(i)); 59 if (packageName.equals(VisibilityStore.VISIBILITY_PACKAGE_NAME)) { 60 continue; // Our own package. Skip. 61 } 62 try { 63 // Note: We use the prefixed schema type as ids 64 visibilityDocumentV1s.add( 65 new VisibilityDocumentV1( 66 appSearchImpl.getDocument( 67 VisibilityStore.VISIBILITY_PACKAGE_NAME, 68 VisibilityStore.VISIBILITY_DATABASE_NAME, 69 VisibilityToDocumentConverter.VISIBILITY_DOCUMENT_NAMESPACE, 70 allPrefixedSchemaTypes.get(i), 71 /* typePropertyPaths= */ Collections.emptyMap()))); 72 } catch (AppSearchException e) { 73 if (e.getResultCode() == AppSearchResult.RESULT_NOT_FOUND) { 74 // TODO(b/172068212): This indicates some desync error. We were expecting a 75 // document, but didn't find one. Should probably reset AppSearch instead 76 // of ignoring it. 77 continue; 78 } 79 // Otherwise, this is some other error we should pass up. 80 throw e; 81 } 82 } 83 return visibilityDocumentV1s; 84 } 85 86 /** 87 * Converts the given list of deprecated Visibility Documents into a Map of {@code 88 * <PrefixedSchemaType, VisibilityDocument.Builder of the latest version>}. 89 * 90 * @param visibilityDocumentV1s The deprecated Visibility Document we found. 91 */ 92 @NonNull toVisibilityDocumentsV2( @onNull List<VisibilityDocumentV1> visibilityDocumentV1s)93 static List<InternalVisibilityConfig> toVisibilityDocumentsV2( 94 @NonNull List<VisibilityDocumentV1> visibilityDocumentV1s) { 95 List<InternalVisibilityConfig> latestVisibilityDocuments = 96 new ArrayList<>(visibilityDocumentV1s.size()); 97 for (int i = 0; i < visibilityDocumentV1s.size(); i++) { 98 VisibilityDocumentV1 visibilityDocumentV1 = visibilityDocumentV1s.get(i); 99 Set<Set<Integer>> visibleToPermissionSets = new ArraySet<>(); 100 Set<Integer> deprecatedVisibleToRoles = visibilityDocumentV1.getVisibleToRoles(); 101 if (deprecatedVisibleToRoles != null) { 102 for (int deprecatedVisibleToRole : deprecatedVisibleToRoles) { 103 Set<Integer> visibleToPermission = new ArraySet<>(); 104 switch (deprecatedVisibleToRole) { 105 case DEPRECATED_ROLE_HOME: 106 visibleToPermission.add(SetSchemaRequest.READ_HOME_APP_SEARCH_DATA); 107 break; 108 case DEPRECATED_ROLE_ASSISTANT: 109 visibleToPermission.add( 110 SetSchemaRequest.READ_ASSISTANT_APP_SEARCH_DATA); 111 break; 112 } 113 visibleToPermissionSets.add(visibleToPermission); 114 } 115 } 116 Set<Integer> deprecatedVisibleToPermissions = 117 visibilityDocumentV1.getVisibleToPermissions(); 118 if (deprecatedVisibleToPermissions != null) { 119 visibleToPermissionSets.add(deprecatedVisibleToPermissions); 120 } 121 122 InternalVisibilityConfig.Builder latestVisibilityDocumentBuilder = 123 new InternalVisibilityConfig.Builder(visibilityDocumentV1.getId()) 124 .setNotDisplayedBySystem(visibilityDocumentV1.isNotDisplayedBySystem()); 125 String[] packageNames = visibilityDocumentV1.getPackageNames(); 126 byte[][] sha256Certs = visibilityDocumentV1.getSha256Certs(); 127 if (packageNames.length == sha256Certs.length) { 128 for (int j = 0; j < packageNames.length; j++) { 129 latestVisibilityDocumentBuilder.addVisibleToPackage( 130 new PackageIdentifier(packageNames[j], sha256Certs[j])); 131 } 132 } 133 for (Set<Integer> visibleToPermissions : visibleToPermissionSets) { 134 latestVisibilityDocumentBuilder.addVisibleToPermissions(visibleToPermissions); 135 } 136 latestVisibilityDocuments.add(latestVisibilityDocumentBuilder.build()); 137 } 138 return latestVisibilityDocuments; 139 } 140 } 141