1 /* 2 * Copyright 2021 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 package com.android.server.appsearch.external.localstorage.visibilitystore; 17 18 import static android.app.appsearch.AppSearchResult.RESULT_NOT_FOUND; 19 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.app.appsearch.AppSearchResult; 23 import android.app.appsearch.AppSearchSchema; 24 import android.app.appsearch.GenericDocument; 25 import android.app.appsearch.GetSchemaResponse; 26 import android.app.appsearch.InternalSetSchemaResponse; 27 import android.app.appsearch.InternalVisibilityConfig; 28 import android.app.appsearch.VisibilityPermissionConfig; 29 import android.app.appsearch.checker.initialization.qual.UnderInitialization; 30 import android.app.appsearch.checker.initialization.qual.UnknownInitialization; 31 import android.app.appsearch.checker.nullness.qual.RequiresNonNull; 32 import android.app.appsearch.exceptions.AppSearchException; 33 import android.app.appsearch.util.LogUtil; 34 import android.util.ArrayMap; 35 import android.util.Log; 36 37 import com.android.server.appsearch.external.localstorage.AppSearchImpl; 38 import com.android.server.appsearch.external.localstorage.util.PrefixUtil; 39 40 import com.google.android.icing.proto.PersistType; 41 42 import java.util.Arrays; 43 import java.util.Collections; 44 import java.util.List; 45 import java.util.Map; 46 import java.util.Objects; 47 import java.util.Set; 48 49 /** 50 * Stores all visibility settings for all databases that AppSearchImpl knows about. Persists the 51 * visibility settings and reloads them on initialization. 52 * 53 * <p>The VisibilityStore creates a {@link InternalVisibilityConfig} for each schema. This config 54 * holds the visibility settings that apply to that schema. The VisibilityStore also creates a 55 * schema and documents for these {@link InternalVisibilityConfig} and has its own package and 56 * database so that its data doesn't interfere with any clients' data. It persists the document and 57 * schema through AppSearchImpl. 58 * 59 * <p>These visibility settings won't be used in AppSearch Jetpack, we only store them for clients 60 * to look up. 61 * 62 * @hide 63 */ 64 public class VisibilityStore { 65 private static final String TAG = "AppSearchVisibilityStor"; 66 67 /** 68 * These cannot have any of the special characters used by AppSearchImpl (e.g. {@code 69 * AppSearchImpl#PACKAGE_DELIMITER} or {@code AppSearchImpl#DATABASE_DELIMITER}. 70 */ 71 public static final String VISIBILITY_PACKAGE_NAME = "VS#Pkg"; 72 73 public static final String VISIBILITY_DATABASE_NAME = "VS#Db"; 74 public static final String ANDROID_V_OVERLAY_DATABASE_NAME = "VS#AndroidVDb"; 75 76 /** 77 * Map of PrefixedSchemaType to InternalVisibilityConfig stores visibility information for each 78 * schema type. 79 */ 80 private final Map<String, InternalVisibilityConfig> mVisibilityConfigMap = new ArrayMap<>(); 81 82 private final AppSearchImpl mAppSearchImpl; 83 VisibilityStore(@onNull AppSearchImpl appSearchImpl)84 public VisibilityStore(@NonNull AppSearchImpl appSearchImpl) throws AppSearchException { 85 mAppSearchImpl = Objects.requireNonNull(appSearchImpl); 86 87 GetSchemaResponse getSchemaResponse = 88 mAppSearchImpl.getSchema( 89 VISIBILITY_PACKAGE_NAME, 90 VISIBILITY_DATABASE_NAME, 91 new CallerAccess(/* callingPackageName= */ VISIBILITY_PACKAGE_NAME)); 92 List<VisibilityDocumentV1> visibilityDocumentsV1s = null; 93 switch (getSchemaResponse.getVersion()) { 94 case VisibilityToDocumentConverter.SCHEMA_VERSION_DOC_PER_PACKAGE: 95 // TODO (b/202194495) add VisibilityDocument in version 0 back instead of using 96 // GenericDocument. 97 List<GenericDocument> visibilityDocumentsV0s = 98 VisibilityStoreMigrationHelperFromV0.getVisibilityDocumentsInVersion0( 99 getSchemaResponse, mAppSearchImpl); 100 visibilityDocumentsV1s = 101 VisibilityStoreMigrationHelperFromV0.toVisibilityDocumentV1( 102 visibilityDocumentsV0s); 103 // fall through 104 case VisibilityToDocumentConverter.SCHEMA_VERSION_DOC_PER_SCHEMA: 105 if (visibilityDocumentsV1s == null) { 106 // We need to read VisibilityDocument in Version 1 from AppSearch instead of 107 // taking from the above step. 108 visibilityDocumentsV1s = 109 VisibilityStoreMigrationHelperFromV1.getVisibilityDocumentsInVersion1( 110 mAppSearchImpl); 111 } 112 setLatestSchemaAndDocuments( 113 VisibilityStoreMigrationHelperFromV1.toVisibilityDocumentsV2( 114 visibilityDocumentsV1s)); 115 break; 116 case VisibilityToDocumentConverter.SCHEMA_VERSION_LATEST: 117 verifyOrSetLatestVisibilitySchema(getSchemaResponse); 118 // Check the version for visibility overlay database. 119 migrateVisibilityOverlayDatabase(); 120 // Now we have the latest schema, load visibility config map. 121 loadVisibilityConfigMap(); 122 break; 123 default: 124 // We must did something wrong. 125 throw new AppSearchException( 126 AppSearchResult.RESULT_INTERNAL_ERROR, 127 "Found unsupported visibility version: " + getSchemaResponse.getVersion()); 128 } 129 } 130 131 /** 132 * Sets visibility settings for the given {@link InternalVisibilityConfig}s. Any previous {@link 133 * InternalVisibilityConfig}s with same prefixed schema type will be overwritten. 134 * 135 * @param prefixedVisibilityConfigs List of prefixed {@link InternalVisibilityConfig}s which 136 * contains schema type's visibility information. 137 * @throws AppSearchException on AppSearchImpl error. 138 */ setVisibility(@onNull List<InternalVisibilityConfig> prefixedVisibilityConfigs)139 public void setVisibility(@NonNull List<InternalVisibilityConfig> prefixedVisibilityConfigs) 140 throws AppSearchException { 141 Objects.requireNonNull(prefixedVisibilityConfigs); 142 // Save new setting. 143 for (int i = 0; i < prefixedVisibilityConfigs.size(); i++) { 144 // put VisibilityConfig to AppSearchImpl and mVisibilityConfigMap. If there is a 145 // VisibilityConfig with same prefixed schema exists, it will be replaced by new 146 // VisibilityConfig in both AppSearch and memory look up map. 147 InternalVisibilityConfig prefixedVisibilityConfig = prefixedVisibilityConfigs.get(i); 148 InternalVisibilityConfig oldVisibilityConfig = 149 mVisibilityConfigMap.get(prefixedVisibilityConfig.getSchemaType()); 150 mAppSearchImpl.putDocument( 151 VISIBILITY_PACKAGE_NAME, 152 VISIBILITY_DATABASE_NAME, 153 VisibilityToDocumentConverter.createVisibilityDocument( 154 prefixedVisibilityConfig), 155 /* sendChangeNotifications= */ false, 156 /* logger= */ null); 157 158 // Put the android V visibility overlay document to AppSearchImpl. 159 GenericDocument androidVOverlay = 160 VisibilityToDocumentConverter.createAndroidVOverlay(prefixedVisibilityConfig); 161 if (androidVOverlay != null) { 162 mAppSearchImpl.putDocument( 163 VISIBILITY_PACKAGE_NAME, 164 ANDROID_V_OVERLAY_DATABASE_NAME, 165 androidVOverlay, 166 /* sendChangeNotifications= */ false, 167 /* logger= */ null); 168 } else if (isConfigContainsAndroidVOverlay(oldVisibilityConfig)) { 169 // We need to make sure to remove the VisibilityOverlay on disk as the current 170 // VisibilityConfig does not have a VisibilityOverlay. 171 // For performance improvement, we should only make the remove call if the old 172 // VisibilityConfig contains the overlay settings. 173 try { 174 mAppSearchImpl.remove( 175 VISIBILITY_PACKAGE_NAME, 176 ANDROID_V_OVERLAY_DATABASE_NAME, 177 VisibilityToDocumentConverter.ANDROID_V_OVERLAY_NAMESPACE, 178 prefixedVisibilityConfig.getSchemaType(), 179 /* removeStatsBuilder= */ null); 180 } catch (AppSearchException e) { 181 // If it already doesn't exist, that is fine 182 if (e.getResultCode() != RESULT_NOT_FOUND) { 183 throw e; 184 } 185 } 186 } 187 188 // Put the VisibilityConfig to memory look up map. 189 mVisibilityConfigMap.put( 190 prefixedVisibilityConfig.getSchemaType(), prefixedVisibilityConfig); 191 } 192 // Now that the visibility document has been written. Persist the newly written data. 193 mAppSearchImpl.persistToDisk(PersistType.Code.LITE); 194 } 195 196 /** 197 * Remove the visibility setting for the given prefixed schema type from both AppSearch and 198 * memory look up map. 199 */ removeVisibility(@onNull Set<String> prefixedSchemaTypes)200 public void removeVisibility(@NonNull Set<String> prefixedSchemaTypes) 201 throws AppSearchException { 202 for (String prefixedSchemaType : prefixedSchemaTypes) { 203 if (mVisibilityConfigMap.remove(prefixedSchemaType) != null) { 204 // The deleted schema is not all-default setting, we need to remove its 205 // VisibilityDocument from Icing. 206 try { 207 mAppSearchImpl.remove( 208 VISIBILITY_PACKAGE_NAME, 209 VISIBILITY_DATABASE_NAME, 210 VisibilityToDocumentConverter.VISIBILITY_DOCUMENT_NAMESPACE, 211 prefixedSchemaType, 212 /* removeStatsBuilder= */ null); 213 } catch (AppSearchException e) { 214 if (e.getResultCode() == RESULT_NOT_FOUND) { 215 // We are trying to remove this visibility setting, so it's weird but seems 216 // to be fine if we cannot find it. 217 Log.e( 218 TAG, 219 "Cannot find visibility document for " 220 + prefixedSchemaType 221 + " to remove."); 222 } else { 223 throw e; 224 } 225 } 226 227 try { 228 mAppSearchImpl.remove( 229 VISIBILITY_PACKAGE_NAME, 230 ANDROID_V_OVERLAY_DATABASE_NAME, 231 VisibilityToDocumentConverter.ANDROID_V_OVERLAY_NAMESPACE, 232 prefixedSchemaType, 233 /* removeStatsBuilder= */ null); 234 } catch (AppSearchException e) { 235 if (e.getResultCode() == RESULT_NOT_FOUND) { 236 // It's possible no overlay was set, so this this is fine. 237 if (LogUtil.DEBUG) { 238 Log.d( 239 TAG, 240 "Cannot find Android V overlay document for " 241 + prefixedSchemaType 242 + " to remove."); 243 } 244 } else { 245 throw e; 246 } 247 } 248 } 249 } 250 } 251 252 /** Gets the {@link InternalVisibilityConfig} for the given prefixed schema type. */ 253 @Nullable getVisibility(@onNull String prefixedSchemaType)254 public InternalVisibilityConfig getVisibility(@NonNull String prefixedSchemaType) { 255 return mVisibilityConfigMap.get(prefixedSchemaType); 256 } 257 258 /** 259 * Loads all stored latest {@link InternalVisibilityConfig} from Icing, and put them into {@link 260 * #mVisibilityConfigMap}. 261 */ 262 @RequiresNonNull("mAppSearchImpl") loadVisibilityConfigMap(@nderInitialization VisibilityStore this)263 private void loadVisibilityConfigMap(@UnderInitialization VisibilityStore this) 264 throws AppSearchException { 265 // Populate visibility settings set 266 List<String> cachedSchemaTypes = mAppSearchImpl.getAllPrefixedSchemaTypes(); 267 for (int i = 0; i < cachedSchemaTypes.size(); i++) { 268 String prefixedSchemaType = cachedSchemaTypes.get(i); 269 String packageName = PrefixUtil.getPackageName(prefixedSchemaType); 270 if (packageName.equals(VISIBILITY_PACKAGE_NAME)) { 271 continue; // Our own package. Skip. 272 } 273 274 GenericDocument visibilityDocument; 275 GenericDocument visibilityAndroidVOverlay = null; 276 try { 277 // Note: We use the other clients' prefixed schema type as ids 278 visibilityDocument = 279 mAppSearchImpl.getDocument( 280 VISIBILITY_PACKAGE_NAME, 281 VISIBILITY_DATABASE_NAME, 282 VisibilityToDocumentConverter.VISIBILITY_DOCUMENT_NAMESPACE, 283 /* id= */ prefixedSchemaType, 284 /* typePropertyPaths= */ Collections.emptyMap()); 285 } catch (AppSearchException e) { 286 if (e.getResultCode() == RESULT_NOT_FOUND) { 287 // The schema has all default setting and we won't have a VisibilityDocument for 288 // it. 289 continue; 290 } 291 // Otherwise, this is some other error we should pass up. 292 throw e; 293 } 294 295 try { 296 visibilityAndroidVOverlay = 297 mAppSearchImpl.getDocument( 298 VISIBILITY_PACKAGE_NAME, 299 ANDROID_V_OVERLAY_DATABASE_NAME, 300 VisibilityToDocumentConverter.ANDROID_V_OVERLAY_NAMESPACE, 301 /* id= */ prefixedSchemaType, 302 /* typePropertyPaths= */ Collections.emptyMap()); 303 } catch (AppSearchException e) { 304 if (e.getResultCode() != RESULT_NOT_FOUND) { 305 // This is some other error we should pass up. 306 throw e; 307 } 308 // Otherwise we continue inserting into visibility document map as the overlay 309 // map can be null 310 } 311 312 mVisibilityConfigMap.put( 313 prefixedSchemaType, 314 VisibilityToDocumentConverter.createInternalVisibilityConfig( 315 visibilityDocument, visibilityAndroidVOverlay)); 316 } 317 } 318 319 /** Set the latest version of {@link InternalVisibilityConfig} and its schema to AppSearch. */ 320 @RequiresNonNull("mAppSearchImpl") setLatestSchemaAndDocuments( @nderInitialization VisibilityStore this, @NonNull List<InternalVisibilityConfig> migratedDocuments)321 private void setLatestSchemaAndDocuments( 322 @UnderInitialization VisibilityStore this, 323 @NonNull List<InternalVisibilityConfig> migratedDocuments) 324 throws AppSearchException { 325 // The latest schema type doesn't exist yet. Add it. Set forceOverride true to 326 // delete old schema. 327 InternalSetSchemaResponse internalSetSchemaResponse = 328 mAppSearchImpl.setSchema( 329 VISIBILITY_PACKAGE_NAME, 330 VISIBILITY_DATABASE_NAME, 331 Arrays.asList( 332 VisibilityToDocumentConverter.VISIBILITY_DOCUMENT_SCHEMA, 333 VisibilityPermissionConfig.SCHEMA), 334 /* visibilityConfigs= */ Collections.emptyList(), 335 /* forceOverride= */ true, 336 /* version= */ VisibilityToDocumentConverter.SCHEMA_VERSION_LATEST, 337 /* setSchemaStatsBuilder= */ null); 338 if (!internalSetSchemaResponse.isSuccess()) { 339 // Impossible case, we just set forceOverride to be true, we should never 340 // fail in incompatible changes. 341 throw new AppSearchException( 342 AppSearchResult.RESULT_INTERNAL_ERROR, 343 internalSetSchemaResponse.getErrorMessage()); 344 } 345 InternalSetSchemaResponse internalSetAndroidVOverlaySchemaResponse = 346 mAppSearchImpl.setSchema( 347 VISIBILITY_PACKAGE_NAME, 348 ANDROID_V_OVERLAY_DATABASE_NAME, 349 Collections.singletonList( 350 VisibilityToDocumentConverter.ANDROID_V_OVERLAY_SCHEMA), 351 /* visibilityConfigs= */ Collections.emptyList(), 352 /* forceOverride= */ true, 353 /* version= */ VisibilityToDocumentConverter 354 .ANDROID_V_OVERLAY_SCHEMA_VERSION_LATEST, 355 /* setSchemaStatsBuilder= */ null); 356 if (!internalSetAndroidVOverlaySchemaResponse.isSuccess()) { 357 // Impossible case, we just set forceOverride to be true, we should never 358 // fail in incompatible changes. 359 throw new AppSearchException( 360 AppSearchResult.RESULT_INTERNAL_ERROR, 361 internalSetAndroidVOverlaySchemaResponse.getErrorMessage()); 362 } 363 for (int i = 0; i < migratedDocuments.size(); i++) { 364 InternalVisibilityConfig migratedConfig = migratedDocuments.get(i); 365 mVisibilityConfigMap.put(migratedConfig.getSchemaType(), migratedConfig); 366 mAppSearchImpl.putDocument( 367 VISIBILITY_PACKAGE_NAME, 368 VISIBILITY_DATABASE_NAME, 369 VisibilityToDocumentConverter.createVisibilityDocument(migratedConfig), 370 /* sendChangeNotifications= */ false, 371 /* logger= */ null); 372 } 373 } 374 375 /** 376 * Check and migrate visibility schemas in {@link #ANDROID_V_OVERLAY_DATABASE_NAME} to {@link 377 * VisibilityToDocumentConverter#ANDROID_V_OVERLAY_SCHEMA_VERSION_LATEST}. 378 */ 379 @RequiresNonNull("mAppSearchImpl") migrateVisibilityOverlayDatabase(@nderInitialization VisibilityStore this)380 private void migrateVisibilityOverlayDatabase(@UnderInitialization VisibilityStore this) 381 throws AppSearchException { 382 GetSchemaResponse getSchemaResponse = 383 mAppSearchImpl.getSchema( 384 VISIBILITY_PACKAGE_NAME, 385 ANDROID_V_OVERLAY_DATABASE_NAME, 386 new CallerAccess(/* callingPackageName= */ VISIBILITY_PACKAGE_NAME)); 387 switch (getSchemaResponse.getVersion()) { 388 case VisibilityToDocumentConverter.OVERLAY_SCHEMA_VERSION_PUBLIC_ACL_VISIBLE_TO_CONFIG: 389 // Force override to next version. This version hasn't released to any public 390 // version. There shouldn't have any public device in this state, so we don't 391 // actually need to migrate any document. 392 InternalSetSchemaResponse internalSetSchemaResponse = 393 mAppSearchImpl.setSchema( 394 VISIBILITY_PACKAGE_NAME, 395 ANDROID_V_OVERLAY_DATABASE_NAME, 396 Collections.singletonList( 397 VisibilityToDocumentConverter.ANDROID_V_OVERLAY_SCHEMA), 398 /* visibilityConfigs= */ Collections.emptyList(), 399 /* forceOverride= */ true, // force update to nest version. 400 VisibilityToDocumentConverter 401 .ANDROID_V_OVERLAY_SCHEMA_VERSION_LATEST, 402 /* setSchemaStatsBuilder= */ null); 403 if (!internalSetSchemaResponse.isSuccess()) { 404 // Impossible case, we just set forceOverride to be true, we should never 405 // fail in incompatible changes. 406 throw new AppSearchException( 407 AppSearchResult.RESULT_INTERNAL_ERROR, 408 internalSetSchemaResponse.getErrorMessage()); 409 } 410 break; 411 case VisibilityToDocumentConverter.OVERLAY_SCHEMA_VERSION_ALL_IN_PROTO: 412 verifyOrSetLatestVisibilityOverlaySchema(getSchemaResponse); 413 break; 414 default: 415 // We must did something wrong. 416 throw new AppSearchException( 417 AppSearchResult.RESULT_INTERNAL_ERROR, 418 "Found unsupported visibility version: " + getSchemaResponse.getVersion()); 419 } 420 } 421 422 /** 423 * Verify the existing visibility schema, set the latest visibilility schema if it's missing. 424 */ 425 @RequiresNonNull("mAppSearchImpl") verifyOrSetLatestVisibilitySchema( @nderInitialization VisibilityStore this, @NonNull GetSchemaResponse getSchemaResponse)426 private void verifyOrSetLatestVisibilitySchema( 427 @UnderInitialization VisibilityStore this, @NonNull GetSchemaResponse getSchemaResponse) 428 throws AppSearchException { 429 // We cannot change the schema version past 2 as detecting version "3" would hit the 430 // default block and throw an AppSearchException. This is why we added 431 // VisibilityOverlay. 432 433 // Check Visibility schema first. 434 Set<AppSearchSchema> existingVisibilitySchema = getSchemaResponse.getSchemas(); 435 // Force to override visibility schema if it contains DEPRECATED_PUBLIC_ACL_OVERLAY_SCHEMA. 436 // The DEPRECATED_PUBLIC_ACL_OVERLAY_SCHEMA was added to VISIBILITY_DATABASE_NAME and 437 // removed to ANDROID_V_OVERLAY_DATABASE_NAME. We need to force update the schema to 438 // migrate devices that have already store public acl schema. 439 // TODO(b/321326441) remove this method when we no longer to migrate devices in this state. 440 if (existingVisibilitySchema.contains( 441 VisibilityToDocumentConverter.VISIBILITY_DOCUMENT_SCHEMA) 442 && existingVisibilitySchema.contains(VisibilityPermissionConfig.SCHEMA) 443 && existingVisibilitySchema.contains( 444 VisibilityToDocumentConverter.DEPRECATED_PUBLIC_ACL_OVERLAY_SCHEMA)) { 445 InternalSetSchemaResponse internalSetSchemaResponse = 446 mAppSearchImpl.setSchema( 447 VISIBILITY_PACKAGE_NAME, 448 VISIBILITY_DATABASE_NAME, 449 Arrays.asList( 450 VisibilityToDocumentConverter.VISIBILITY_DOCUMENT_SCHEMA, 451 VisibilityPermissionConfig.SCHEMA), 452 /* visibilityConfigs= */ Collections.emptyList(), 453 /* forceOverride= */ true, 454 /* version= */ VisibilityToDocumentConverter.SCHEMA_VERSION_LATEST, 455 /* setSchemaStatsBuilder= */ null); 456 if (!internalSetSchemaResponse.isSuccess()) { 457 throw new AppSearchException( 458 AppSearchResult.RESULT_INTERNAL_ERROR, 459 "Fail to force override deprecated visibility schema with public acl."); 460 } 461 } else if (!(existingVisibilitySchema.contains( 462 VisibilityToDocumentConverter.VISIBILITY_DOCUMENT_SCHEMA) 463 && existingVisibilitySchema.contains(VisibilityPermissionConfig.SCHEMA))) { 464 // We must have a broken schema. Reset it to the latest version. 465 // Do NOT set forceOverride to be true here, see comment below. 466 InternalSetSchemaResponse internalSetSchemaResponse = 467 mAppSearchImpl.setSchema( 468 VISIBILITY_PACKAGE_NAME, 469 VISIBILITY_DATABASE_NAME, 470 Arrays.asList( 471 VisibilityToDocumentConverter.VISIBILITY_DOCUMENT_SCHEMA, 472 VisibilityPermissionConfig.SCHEMA), 473 /* visibilityConfigs= */ Collections.emptyList(), 474 /* forceOverride= */ false, 475 /* version= */ VisibilityToDocumentConverter.SCHEMA_VERSION_LATEST, 476 /* setSchemaStatsBuilder= */ null); 477 if (!internalSetSchemaResponse.isSuccess()) { 478 // If you hit problem here it means you made a incompatible change in 479 // Visibility Schema without update the version number. You should bump 480 // the version number and create a VisibilityStoreMigrationHelper which 481 // can analyse the different between the old version and the new version 482 // to migration user's visibility settings. 483 throw new AppSearchException( 484 AppSearchResult.RESULT_INTERNAL_ERROR, 485 "Fail to set the latest visibility schema to AppSearch. " 486 + "You may need to update the visibility schema version " 487 + "number."); 488 } 489 } 490 } 491 492 /** 493 * Verify the existing visibility overlay schema, set the latest overlay schema if it's missing. 494 */ 495 @RequiresNonNull("mAppSearchImpl") verifyOrSetLatestVisibilityOverlaySchema( @nknownInitialization VisibilityStore this, @NonNull GetSchemaResponse getAndroidVOverlaySchemaResponse)496 private void verifyOrSetLatestVisibilityOverlaySchema( 497 @UnknownInitialization VisibilityStore this, 498 @NonNull GetSchemaResponse getAndroidVOverlaySchemaResponse) 499 throws AppSearchException { 500 // Check Android V overlay schema. 501 Set<AppSearchSchema> existingAndroidVOverlaySchema = 502 getAndroidVOverlaySchemaResponse.getSchemas(); 503 if (!existingAndroidVOverlaySchema.contains( 504 VisibilityToDocumentConverter.ANDROID_V_OVERLAY_SCHEMA)) { 505 // We must have a broken schema. Reset it to the latest version. 506 // Do NOT set forceOverride to be true here, see comment below. 507 InternalSetSchemaResponse internalSetSchemaResponse = 508 mAppSearchImpl.setSchema( 509 VISIBILITY_PACKAGE_NAME, 510 ANDROID_V_OVERLAY_DATABASE_NAME, 511 Collections.singletonList( 512 VisibilityToDocumentConverter.ANDROID_V_OVERLAY_SCHEMA), 513 /* visibilityConfigs= */ Collections.emptyList(), 514 /* forceOverride= */ false, 515 VisibilityToDocumentConverter.ANDROID_V_OVERLAY_SCHEMA_VERSION_LATEST, 516 /* setSchemaStatsBuilder= */ null); 517 if (!internalSetSchemaResponse.isSuccess()) { 518 // If you hit problem here it means you made a incompatible change in 519 // Visibility Schema. You should create new overlay schema 520 throw new AppSearchException( 521 AppSearchResult.RESULT_INTERNAL_ERROR, 522 "Fail to set the overlay visibility schema to AppSearch. " 523 + "You may need to create new overlay schema."); 524 } 525 } 526 } 527 528 /** 529 * Whether the given {@link InternalVisibilityConfig} contains Android V overlay settings. 530 * 531 * <p>Android V overlay {@link VisibilityToDocumentConverter#ANDROID_V_OVERLAY_SCHEMA} contains 532 * public acl and visible to config. 533 */ isConfigContainsAndroidVOverlay( @ullable InternalVisibilityConfig config)534 private static boolean isConfigContainsAndroidVOverlay( 535 @Nullable InternalVisibilityConfig config) { 536 return config != null 537 && (config.getVisibilityConfig().getPubliclyVisibleTargetPackage() != null 538 || !config.getVisibleToConfigs().isEmpty()); 539 } 540 } 541