From 8e5ad5d46e30c66541ba73c261e0f4aa5a3e1180 Mon Sep 17 00:00:00 2001 From: Alexander Dorokhine Date: Wed, 20 Jan 2021 16:06:16 -0800 Subject: [PATCH] Sync framework from jetpack. Included changes: * 31866d: Migrate VisibilityStore to a no-op. Bug: 169883602 Test: Presubmit Change-Id: I9a4abbf64d29a248a0d04e883961f1a6da556802 --- .../server/appsearch/ImplInstanceManager.java | 2 +- .../localstorage => }/VisibilityStore.java | 0 .../external/localstorage/AppSearchImpl.java | 17 +- apex/appsearch/synced_jetpack_changeid.txt | 2 +- .../localstorage/AppSearchImplTest.java | 403 +----------------- .../localstorage/MockPackageManager.java | 82 ---- .../localstorage/VisibilityStoreTest.java | 318 -------------- 7 files changed, 29 insertions(+), 795 deletions(-) rename apex/appsearch/service/java/com/android/server/appsearch/{external/localstorage => }/VisibilityStore.java (100%) delete mode 100644 services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/MockPackageManager.java delete mode 100644 services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/VisibilityStoreTest.java diff --git a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java index cd90f8568d6e9..85423d28a5e18 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java @@ -69,7 +69,7 @@ public final class ImplInstanceManager { private static AppSearchImpl createImpl(@NonNull Context context, @UserIdInt int userId) throws AppSearchException { File appSearchDir = getAppSearchDir(context, userId); - return AppSearchImpl.create(appSearchDir, context, /*globalQuerierPackage=*/""); + return AppSearchImpl.create(appSearchDir, context, userId, /*globalQuerierPackage=*/""); } private static File getAppSearchDir(@NonNull Context context, @UserIdInt int userId) { diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/VisibilityStore.java b/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java similarity index 100% rename from apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/VisibilityStore.java rename to apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java 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 1665b1cf6d631..b1d0ab422e58f 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 @@ -160,18 +160,25 @@ public final class AppSearchImpl { */ @NonNull public static AppSearchImpl create( - @NonNull File icingDir, @NonNull Context context, @NonNull String globalQuerierPackage) + @NonNull File icingDir, + @NonNull Context context, + int userId, + @NonNull String globalQuerierPackage) throws AppSearchException { Preconditions.checkNotNull(icingDir); Preconditions.checkNotNull(context); Preconditions.checkNotNull(globalQuerierPackage); - AppSearchImpl appSearchImpl = new AppSearchImpl(icingDir, context, globalQuerierPackage); + AppSearchImpl appSearchImpl = + new AppSearchImpl(icingDir, context, userId, globalQuerierPackage); appSearchImpl.initializeVisibilityStore(); return appSearchImpl; } private AppSearchImpl( - @NonNull File icingDir, @NonNull Context context, @NonNull String globalQuerierPackage) + @NonNull File icingDir, + @NonNull Context context, + int userId, + @NonNull String globalQuerierPackage) throws AppSearchException { mReadWriteLock.writeLock().lock(); @@ -184,7 +191,8 @@ public final class AppSearchImpl { .build(); mIcingSearchEngineLocked = new IcingSearchEngine(options); - mVisibilityStoreLocked = new VisibilityStore(this, context, globalQuerierPackage); + mVisibilityStoreLocked = + new VisibilityStore(this, context, globalQuerierPackage); InitializeResultProto initializeResultProto = mIcingSearchEngineLocked.initialize(); SchemaProto schemaProto; @@ -1350,6 +1358,7 @@ public final class AppSearchImpl { } @GuardedBy("mReadWriteLock") + @NonNull @VisibleForTesting VisibilityStore getVisibilityStoreLocked() { return mVisibilityStoreLocked; diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt index 5ab34509c7026..51aeb89a33fd1 100644 --- a/apex/appsearch/synced_jetpack_changeid.txt +++ b/apex/appsearch/synced_jetpack_changeid.txt @@ -1 +1 @@ -Iff96eae150c7cdd281c9ecb5d93f4ef697e89f1a +I03df55376689c1557c651d5b9671c40da1c35955 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 b2a860d07d597..c6fb37dcad0cd 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 @@ -22,14 +22,12 @@ import static org.testng.Assert.expectThrows; import android.app.appsearch.AppSearchSchema; import android.app.appsearch.GenericDocument; -import android.app.appsearch.PackageIdentifier; import android.app.appsearch.SearchResult; import android.app.appsearch.SearchResultPage; import android.app.appsearch.SearchSpec; import android.app.appsearch.exceptions.AppSearchException; import android.content.Context; -import android.content.ContextWrapper; -import android.content.pm.PackageManager; +import android.util.ArraySet; import androidx.test.core.app.ApplicationProvider; @@ -46,7 +44,6 @@ 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; @@ -57,33 +54,23 @@ import org.junit.rules.TemporaryFolder; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; public class AppSearchImplTest { @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder(); - private MockPackageManager mMockPackageManager = new MockPackageManager(); - private Context mContext; private AppSearchImpl mAppSearchImpl; - private int mGlobalQuerierUid; @Before public void setUp() throws Exception { Context context = ApplicationProvider.getApplicationContext(); - mContext = - new ContextWrapper(context) { - @Override - public PackageManager getPackageManager() { - return mMockPackageManager.getMockPackageManager(); - } - }; - // Give ourselves global query permissions mAppSearchImpl = AppSearchImpl.create( mTemporaryFolder.newFolder(), - mContext, - /*globalQuerierPackage=*/ mContext.getPackageName()); - mGlobalQuerierUid = - mContext.getPackageManager().getPackageUid(mContext.getPackageName(), /*flags=*/ 0); + context, + /*userId=*/-1, + /*globalQuerierPackage + =*/ context.getPackageName()); } // TODO(b/175430168) add test to verify reset is working properly. @@ -702,125 +689,10 @@ public class AppSearchImplTest { new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build(); SearchResultPage searchResultPage = mAppSearchImpl.globalQuery( - "", searchSpec, mContext.getPackageName(), /*callerUid=*/ 0); + "", searchSpec, /*callerPackageName=*/ "", /*callerUid=*/ 0); assertThat(searchResultPage.getResults()).isEmpty(); } - /** - * TODO(b/169883602): This should be an integration test at the cts-level. This is a short-term - * test until we have official support for multiple-apps indexing at once. - */ - @Test - public void testGlobalQueryWithMultiplePackages_noPackageFilters() throws Exception { - // Insert package1 schema - List schema1 = - ImmutableList.of(new AppSearchSchema.Builder("schema1").build()); - mAppSearchImpl.setSchema( - "package1", - "database1", - schema1, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), - /*forceOverride=*/ false); - - // Insert package2 schema - List schema2 = - ImmutableList.of(new AppSearchSchema.Builder("schema2").build()); - mAppSearchImpl.setSchema( - "package2", - "database2", - schema2, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), - /*forceOverride=*/ false); - - // Insert package1 document - GenericDocument document1 = - new GenericDocument.Builder<>("uri", "schema1").setNamespace("namespace").build(); - mAppSearchImpl.putDocument("package1", "database1", document1); - - // Insert package2 document - GenericDocument document2 = - new GenericDocument.Builder<>("uri", "schema2").setNamespace("namespace").build(); - mAppSearchImpl.putDocument("package2", "database2", document2); - - // No query filters specified, global query can retrieve all documents. - SearchSpec searchSpec = - new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build(); - SearchResultPage searchResultPage = - mAppSearchImpl.globalQuery( - "", searchSpec, mContext.getPackageName(), mGlobalQuerierUid); - assertThat(searchResultPage.getResults()).hasSize(2); - - // Document2 will be first since it got indexed later and has a "better", aka more recent - // score. - assertThat(searchResultPage.getResults().get(0).getDocument()).isEqualTo(document2); - assertThat(searchResultPage.getResults().get(1).getDocument()).isEqualTo(document1); - } - - /** - * TODO(b/169883602): This should be an integration test at the cts-level. This is a short-term - * test until we have official support for multiple-apps indexing at once. - */ - @Test - public void testGlobalQueryWithMultiplePackages_withPackageFilters() throws Exception { - // Insert package1 schema - List schema1 = - ImmutableList.of(new AppSearchSchema.Builder("schema1").build()); - mAppSearchImpl.setSchema( - "package1", - "database1", - schema1, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), - /*forceOverride=*/ false); - - // Insert package2 schema - List schema2 = - ImmutableList.of(new AppSearchSchema.Builder("schema2").build()); - mAppSearchImpl.setSchema( - "package2", - "database2", - schema2, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), - /*forceOverride=*/ false); - - // Insert package1 document - GenericDocument document1 = - new GenericDocument.Builder<>("uri", "schema1").setNamespace("namespace").build(); - mAppSearchImpl.putDocument("package1", "database1", document1); - - // Insert package2 document - GenericDocument document2 = - new GenericDocument.Builder<>("uri", "schema2").setNamespace("namespace").build(); - mAppSearchImpl.putDocument("package2", "database2", document2); - - // "package1" filter specified - SearchSpec searchSpec = - new SearchSpec.Builder() - .setTermMatch(TermMatchType.Code.PREFIX_VALUE) - .addFilterPackageNames("package1") - .build(); - SearchResultPage searchResultPage = - mAppSearchImpl.globalQuery( - "", searchSpec, mContext.getPackageName(), mGlobalQuerierUid); - assertThat(searchResultPage.getResults()).hasSize(1); - assertThat(searchResultPage.getResults().get(0).getDocument()).isEqualTo(document1); - - // "package2" filter specified - searchSpec = - new SearchSpec.Builder() - .setTermMatch(TermMatchType.Code.PREFIX_VALUE) - .addFilterPackageNames("package2") - .build(); - searchResultPage = - mAppSearchImpl.globalQuery( - "", searchSpec, mContext.getPackageName(), mGlobalQuerierUid); - assertThat(searchResultPage.getResults()).hasSize(1); - assertThat(searchResultPage.getResults().get(0).getDocument()).isEqualTo(document2); - } - @Test public void testRemoveEmptyDatabase_noExceptionThrown() throws Exception { SearchSpec searchSpec = @@ -873,82 +745,6 @@ public class AppSearchImplTest { .containsExactlyElementsIn(expectedTypes); } - @Test - public void testSetSchema_existingSchemaRetainsVisibilitySetting() throws Exception { - // Values for a "foo" client - String packageNameFoo = "packageFoo"; - byte[] sha256CertFoo = new byte[] {10}; - int uidFoo = 1; - - // Make sure foo package will pass package manager checks. - mMockPackageManager.mockGetPackageUid(packageNameFoo, uidFoo); - mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo); - - // Set schema1 - String prefix = AppSearchImpl.createPrefix("package", "database"); - mAppSearchImpl.setSchema( - "package", - "database", - Collections.singletonList(new AppSearchSchema.Builder("schema1").build()), - /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"), - /*schemasPackageAccessible=*/ ImmutableMap.of( - "schema1", - ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))), - /*forceOverride=*/ false); - - // "schema1" is platform hidden now and package visible to package1 - assertThat( - mAppSearchImpl - .getVisibilityStoreLocked() - .isSchemaSearchableByCaller( - prefix, prefix + "schema1", mGlobalQuerierUid)) - .isFalse(); - assertThat( - mAppSearchImpl - .getVisibilityStoreLocked() - .isSchemaSearchableByCaller(prefix, prefix + "schema1", uidFoo)) - .isTrue(); - - // Add a new schema, and include the already-existing "schema1" - mAppSearchImpl.setSchema( - "package", - "database", - ImmutableList.of( - new AppSearchSchema.Builder("schema1").build(), - new AppSearchSchema.Builder("schema2").build()), - /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"), - /*schemasPackageAccessible=*/ ImmutableMap.of( - "schema1", - ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))), - /*forceOverride=*/ false); - - // Check that "schema1" still has the same visibility settings - assertThat( - mAppSearchImpl - .getVisibilityStoreLocked() - .isSchemaSearchableByCaller( - prefix, prefix + "schema1", mGlobalQuerierUid)) - .isFalse(); - assertThat( - mAppSearchImpl - .getVisibilityStoreLocked() - .isSchemaSearchableByCaller(prefix, prefix + "schema1", uidFoo)) - .isTrue(); - - // "schema2" has default visibility settings - assertThat( - mAppSearchImpl - .getVisibilityStoreLocked() - .isSchemaSearchableByCaller( - prefix, prefix + "schema2", mGlobalQuerierUid)) - .isTrue(); - assertThat( - mAppSearchImpl - .getVisibilityStoreLocked() - .isSchemaSearchableByCaller(prefix, prefix + "schema2", uidFoo)) - .isFalse(); - } - @Test public void testRemoveSchema() throws Exception { List existingSchemas = @@ -1120,167 +916,6 @@ public class AppSearchImplTest { .containsExactlyElementsIn(expectedTypes); } - @Test - public void testRemoveSchema_removedFromVisibilityStore() throws Exception { - // Values for a "foo" client - String packageNameFoo = "packageFoo"; - byte[] sha256CertFoo = new byte[] {10}; - int uidFoo = 1; - - // Make sure foo package will pass package manager checks. - mMockPackageManager.mockGetPackageUid(packageNameFoo, uidFoo); - mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo); - - String prefix = AppSearchImpl.createPrefix("package", "database"); - mAppSearchImpl.setSchema( - "package", - "database", - Collections.singletonList(new AppSearchSchema.Builder("schema1").build()), - /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"), - /*schemasPackageAccessible=*/ ImmutableMap.of( - "schema1", - ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))), - /*forceOverride=*/ false); - - // "schema1" is platform hidden now and package accessible - assertThat( - mAppSearchImpl - .getVisibilityStoreLocked() - .isSchemaSearchableByCaller( - prefix, prefix + "schema1", mGlobalQuerierUid)) - .isFalse(); - assertThat( - mAppSearchImpl - .getVisibilityStoreLocked() - .isSchemaSearchableByCaller(prefix, prefix + "schema1", uidFoo)) - .isTrue(); - - // Remove "schema1" by force overriding - mAppSearchImpl.setSchema( - "package", - "database", - /*schemas=*/ Collections.emptyList(), - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), - /*forceOverride=*/ true); - - // Check that "schema1" is no longer considered platform hidden or package accessible - assertThat( - mAppSearchImpl - .getVisibilityStoreLocked() - .isSchemaSearchableByCaller( - prefix, prefix + "schema1", mGlobalQuerierUid)) - .isTrue(); - assertThat( - mAppSearchImpl - .getVisibilityStoreLocked() - .isSchemaSearchableByCaller(prefix, prefix + "schema1", uidFoo)) - .isFalse(); - - // Add "schema1" back, it gets default visibility settings which means it's not platform - // hidden and not package accessible - mAppSearchImpl.setSchema( - "package", - "database", - Collections.singletonList(new AppSearchSchema.Builder("schema1").build()), - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), - /*forceOverride=*/ false); - assertThat( - mAppSearchImpl - .getVisibilityStoreLocked() - .isSchemaSearchableByCaller( - prefix, prefix + "schema1", mGlobalQuerierUid)) - .isTrue(); - assertThat( - mAppSearchImpl - .getVisibilityStoreLocked() - .isSchemaSearchableByCaller(prefix, prefix + "schema1", uidFoo)) - .isFalse(); - } - - @Test - public void testSetSchema_defaultPlatformVisible() throws Exception { - String prefix = AppSearchImpl.createPrefix("package", "database"); - mAppSearchImpl.setSchema( - "package", - "database", - Collections.singletonList(new AppSearchSchema.Builder("Schema").build()), - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), - /*forceOverride=*/ false); - assertThat( - mAppSearchImpl - .getVisibilityStoreLocked() - .isSchemaSearchableByCaller( - prefix, prefix + "Schema", mGlobalQuerierUid)) - .isTrue(); - } - - @Test - public void testSetSchema_platformHidden() throws Exception { - String prefix = AppSearchImpl.createPrefix("package", "database"); - mAppSearchImpl.setSchema( - "package", - "database", - Collections.singletonList(new AppSearchSchema.Builder("Schema").build()), - /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("Schema"), - /*schemasPackageAccessible=*/ Collections.emptyMap(), - /*forceOverride=*/ false); - assertThat( - mAppSearchImpl - .getVisibilityStoreLocked() - .isSchemaSearchableByCaller( - prefix, prefix + "Schema", mGlobalQuerierUid)) - .isFalse(); - } - - @Test - public void testSetSchema_defaultNotPackageAccessible() throws Exception { - String prefix = AppSearchImpl.createPrefix("package", "database"); - mAppSearchImpl.setSchema( - "package", - "database", - Collections.singletonList(new AppSearchSchema.Builder("Schema").build()), - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), - /*forceOverride=*/ false); - assertThat( - mAppSearchImpl - .getVisibilityStoreLocked() - .isSchemaSearchableByCaller( - prefix, prefix + "Schema", /*callerUid=*/ 42)) - .isFalse(); - } - - @Test - public void testSetSchema_packageAccessible() throws Exception { - // Values for a "foo" client - String packageNameFoo = "packageFoo"; - byte[] sha256CertFoo = new byte[] {10}; - int uidFoo = 1; - - // Make sure foo package will pass package manager checks. - mMockPackageManager.mockGetPackageUid(packageNameFoo, uidFoo); - mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo); - - String prefix = AppSearchImpl.createPrefix("package", "database"); - mAppSearchImpl.setSchema( - "package", - "database", - Collections.singletonList(new AppSearchSchema.Builder("Schema").build()), - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ ImmutableMap.of( - "Schema", - ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))), - /*forceOverride=*/ false); - assertThat( - mAppSearchImpl - .getVisibilityStoreLocked() - .isSchemaSearchableByCaller(prefix, prefix + "Schema", uidFoo)) - .isTrue(); - } - @Test public void testHasSchemaType() throws Exception { // Nothing exists yet @@ -1300,14 +935,12 @@ public class AppSearchImplTest { } @Test - public void testGetDatabases() throws Exception { - // No client databases exist yet, but the VisibilityStore's does - assertThat(mAppSearchImpl.getPrefixesLocked()) - .containsExactly( - AppSearchImpl.createPrefix( - VisibilityStore.PACKAGE_NAME, VisibilityStore.DATABASE_NAME)); + public void testGetPrefixes() throws Exception { + Set existingPrefixes = mAppSearchImpl.getPrefixesLocked(); // Has database1 + Set expectedPrefixes = new ArraySet<>(existingPrefixes); + expectedPrefixes.add(AppSearchImpl.createPrefix("package", "database1")); mAppSearchImpl.setSchema( "package", "database1", @@ -1315,13 +948,10 @@ public class AppSearchImplTest { /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), /*schemasPackageAccessible=*/ Collections.emptyMap(), /*forceOverride=*/ false); - assertThat(mAppSearchImpl.getPrefixesLocked()) - .containsExactly( - AppSearchImpl.createPrefix( - VisibilityStore.PACKAGE_NAME, VisibilityStore.DATABASE_NAME), - AppSearchImpl.createPrefix("package", "database1")); + assertThat(mAppSearchImpl.getPrefixesLocked()).containsExactlyElementsIn(expectedPrefixes); // Has both databases + expectedPrefixes.add(AppSearchImpl.createPrefix("package", "database2")); mAppSearchImpl.setSchema( "package", "database2", @@ -1329,12 +959,7 @@ public class AppSearchImplTest { /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), /*schemasPackageAccessible=*/ Collections.emptyMap(), /*forceOverride=*/ false); - assertThat(mAppSearchImpl.getPrefixesLocked()) - .containsExactly( - AppSearchImpl.createPrefix( - VisibilityStore.PACKAGE_NAME, VisibilityStore.DATABASE_NAME), - AppSearchImpl.createPrefix("package", "database1"), - AppSearchImpl.createPrefix("package", "database2")); + assertThat(mAppSearchImpl.getPrefixesLocked()).containsExactlyElementsIn(expectedPrefixes); } @Test diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/MockPackageManager.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/MockPackageManager.java deleted file mode 100644 index c2a8243bcf340..0000000000000 --- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/MockPackageManager.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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; - -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; - -import android.annotation.NonNull; -import android.content.pm.PackageManager; - -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** - * Mock to help test package name, UID, and certificate verification - * - * @hide - */ -public class MockPackageManager { - - @Mock private PackageManager mMockPackageManager; - - public MockPackageManager() { - MockitoAnnotations.initMocks(this); - } - - @NonNull - public PackageManager getMockPackageManager() { - return mMockPackageManager; - } - - /** Mock a NameNotFoundException if the package name isn't installed. */ - public void mockThrowsNameNotFoundException(String packageName) { - try { - when(mMockPackageManager.getPackageUid(eq(packageName), /*flags=*/ anyInt())) - .thenThrow(new PackageManager.NameNotFoundException()); - } catch (PackageManager.NameNotFoundException e) { - // Shouldn't ever happen since we're mocking the exception - e.printStackTrace(); - } - } - - /** Mocks that {@code uid} contains the {@code packageName} */ - public void mockGetPackageUid(String packageName, int uid) { - try { - when(mMockPackageManager.getPackageUid(eq(packageName), /*flags=*/ anyInt())) - .thenReturn(uid); - } catch (PackageManager.NameNotFoundException e) { - // Shouldn't ever happen since we're mocking the method. - e.printStackTrace(); - } - } - - /** Mocks that {@code packageName} has been signed with {@code sha256Cert}. */ - public void mockAddSigningCertificate(String packageName, byte[] sha256Cert) { - when(mMockPackageManager.hasSigningCertificate( - packageName, sha256Cert, PackageManager.CERT_INPUT_SHA256)) - .thenReturn(true); - } - - /** Mocks that {@code packageName} has NOT been signed with {@code sha256Cert}. */ - public void mockRemoveSigningCertificate(String packageName, byte[] sha256Cert) { - when(mMockPackageManager.hasSigningCertificate( - packageName, sha256Cert, PackageManager.CERT_INPUT_SHA256)) - .thenReturn(false); - } -} diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/VisibilityStoreTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/VisibilityStoreTest.java deleted file mode 100644 index da3e999bf25f7..0000000000000 --- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/VisibilityStoreTest.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * 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 com.android.server.appsearch.external.localstorage; - -import static com.google.common.truth.Truth.assertThat; - -import android.app.appsearch.PackageIdentifier; -import android.content.Context; -import android.content.ContextWrapper; -import android.content.pm.PackageManager; - -import androidx.test.core.app.ApplicationProvider; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -import java.util.Collections; - -public class VisibilityStoreTest { - - @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder(); - private MockPackageManager mMockPackageManager = new MockPackageManager(); - private Context mContext; - private AppSearchImpl mAppSearchImpl; - private VisibilityStore mVisibilityStore; - private int mGlobalQuerierUid; - - @Before - public void setUp() throws Exception { - Context context = ApplicationProvider.getApplicationContext(); - mContext = - new ContextWrapper(context) { - @Override - public PackageManager getPackageManager() { - return mMockPackageManager.getMockPackageManager(); - } - }; - - // Give ourselves global query permissions - mAppSearchImpl = - AppSearchImpl.create( - mTemporaryFolder.newFolder(), - mContext, - /*globalQuerierPackage=*/ mContext.getPackageName()); - mGlobalQuerierUid = - mContext.getPackageManager().getPackageUid(mContext.getPackageName(), /*flags=*/ 0); - - mVisibilityStore = mAppSearchImpl.getVisibilityStoreLocked(); - } - - /** - * Make sure that we don't conflict with any special characters that AppSearchImpl has reserved. - */ - @Test - public void testValidPackageName() { - assertThat(VisibilityStore.PACKAGE_NAME) - .doesNotContain( - "" + AppSearchImpl.PACKAGE_DELIMITER); // Convert the chars to CharSequences - assertThat(VisibilityStore.PACKAGE_NAME) - .doesNotContain( - "" - + AppSearchImpl - .DATABASE_DELIMITER); // Convert the chars to CharSequences - } - - /** - * Make sure that we don't conflict with any special characters that AppSearchImpl has reserved. - */ - @Test - public void testValidDatabaseName() { - assertThat(VisibilityStore.DATABASE_NAME) - .doesNotContain( - "" + AppSearchImpl.PACKAGE_DELIMITER); // Convert the chars to CharSequences - assertThat(VisibilityStore.DATABASE_NAME) - .doesNotContain( - "" - + AppSearchImpl - .DATABASE_DELIMITER); // Convert the chars to CharSequences - } - - @Test - public void testSetVisibility_platformSurfaceable() throws Exception { - mVisibilityStore.setVisibility( - "prefix", - /*schemasNotPlatformSurfaceable=*/ ImmutableSet.of( - "prefix/schema1", "prefix/schema2"), - /*schemasPackageAccessible=*/ Collections.emptyMap()); - assertThat( - mVisibilityStore.isSchemaSearchableByCaller( - "prefix", "prefix/schema1", mGlobalQuerierUid)) - .isFalse(); - assertThat( - mVisibilityStore.isSchemaSearchableByCaller( - "prefix", "prefix/schema2", mGlobalQuerierUid)) - .isFalse(); - - // New .setVisibility() call completely overrides previous visibility settings. So - // "schema2" isn't preserved. - mVisibilityStore.setVisibility( - "prefix", - /*schemasNotPlatformSurfaceable=*/ ImmutableSet.of( - "prefix/schema1", "prefix/schema3"), - /*schemasPackageAccessible=*/ Collections.emptyMap()); - assertThat( - mVisibilityStore.isSchemaSearchableByCaller( - "prefix", "prefix/schema1", mGlobalQuerierUid)) - .isFalse(); - assertThat( - mVisibilityStore.isSchemaSearchableByCaller( - "prefix", "prefix/schema2", mGlobalQuerierUid)) - .isTrue(); - assertThat( - mVisibilityStore.isSchemaSearchableByCaller( - "prefix", "prefix/schema3", mGlobalQuerierUid)) - .isFalse(); - - // Everything defaults to visible again. - mVisibilityStore.setVisibility( - "prefix", - /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(), - /*schemasPackageAccessible=*/ Collections.emptyMap()); - assertThat( - mVisibilityStore.isSchemaSearchableByCaller( - "prefix", "prefix/schema1", mGlobalQuerierUid)) - .isTrue(); - assertThat( - mVisibilityStore.isSchemaSearchableByCaller( - "prefix", "prefix/schema2", mGlobalQuerierUid)) - .isTrue(); - assertThat( - mVisibilityStore.isSchemaSearchableByCaller( - "prefix", "prefix/schema3", mGlobalQuerierUid)) - .isTrue(); - } - - @Test - public void testIsSchemaSearchableByCaller_platformQuerierHandlesNameNotFoundException() - throws Exception { - // Initialized the VisibilityStore with this context's package name as the global querier. - mMockPackageManager.mockThrowsNameNotFoundException(mContext.getPackageName()); - - // Create a new VisibilityStore instance since we look up the UID on initialization - AppSearchImpl appSearchImpl = - AppSearchImpl.create( - mTemporaryFolder.newFolder(), - mContext, - /*globalQuerierPackage=*/ mContext.getPackageName()); - VisibilityStore visibilityStore = appSearchImpl.getVisibilityStoreLocked(); - - // Use some arbitrary callerUid. If we can't find the global querier's uid though, - // nothing should be platform surfaceable. - assertThat( - visibilityStore.isSchemaSearchableByCaller( - "prefix", "prefix/schemaFoo", /*callerUid=*/ 0)) - .isFalse(); - } - - @Test - public void testSetVisibility_packageAccessible() throws Exception { - // Values for a "foo" client - String packageNameFoo = "packageFoo"; - byte[] sha256CertFoo = new byte[] {10}; - int uidFoo = 1; - - // Values for a "bar" client - String packageNameBar = "packageBar"; - byte[] sha256CertBar = new byte[] {100}; - int uidBar = 2; - - // Can't be the same value as uidFoo nor uidBar - int uidNotFooOrBar = 3; - - // By default, a schema isn't package accessible. - assertThat( - mVisibilityStore.isSchemaSearchableByCaller( - "prefix", "prefix/schemaFoo", uidFoo)) - .isFalse(); - assertThat( - mVisibilityStore.isSchemaSearchableByCaller( - "prefix", "prefix/schemaBar", uidBar)) - .isFalse(); - - // Grant package access - mVisibilityStore.setVisibility( - "prefix", - /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(), - /*schemasPackageAccessible=*/ ImmutableMap.of( - "prefix/schemaFoo", - ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo)), - "prefix/schemaBar", - ImmutableList.of(new PackageIdentifier(packageNameBar, sha256CertBar)))); - - // Should fail if PackageManager doesn't see that it has the proper certificate - mMockPackageManager.mockGetPackageUid(packageNameFoo, uidFoo); - mMockPackageManager.mockRemoveSigningCertificate(packageNameFoo, sha256CertFoo); - assertThat( - mVisibilityStore.isSchemaSearchableByCaller( - "prefix", "prefix/schemaFoo", uidFoo)) - .isFalse(); - - // Should fail if PackageManager doesn't think the package belongs to the uid - mMockPackageManager.mockGetPackageUid(packageNameFoo, uidNotFooOrBar); - mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo); - assertThat( - mVisibilityStore.isSchemaSearchableByCaller( - "prefix", "prefix/schemaFoo", uidFoo)) - .isFalse(); - - // But if uid and certificate match, then we should have access - mMockPackageManager.mockGetPackageUid(packageNameFoo, uidFoo); - mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo); - assertThat( - mVisibilityStore.isSchemaSearchableByCaller( - "prefix", "prefix/schemaFoo", uidFoo)) - .isTrue(); - - mMockPackageManager.mockGetPackageUid(packageNameBar, uidBar); - mMockPackageManager.mockAddSigningCertificate(packageNameBar, sha256CertBar); - assertThat( - mVisibilityStore.isSchemaSearchableByCaller( - "prefix", "prefix/schemaBar", uidBar)) - .isTrue(); - - // New .setVisibility() call completely overrides previous visibility settings. So - // "schemaBar" settings aren't preserved. - mVisibilityStore.setVisibility( - "prefix", - /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(), - /*schemasPackageAccessible=*/ ImmutableMap.of( - "prefix/schemaFoo", - ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo)))); - - mMockPackageManager.mockGetPackageUid(packageNameFoo, uidFoo); - mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo); - assertThat( - mVisibilityStore.isSchemaSearchableByCaller( - "prefix", "prefix/schemaFoo", uidFoo)) - .isTrue(); - - mMockPackageManager.mockGetPackageUid(packageNameBar, uidBar); - mMockPackageManager.mockAddSigningCertificate(packageNameBar, sha256CertBar); - assertThat( - mVisibilityStore.isSchemaSearchableByCaller( - "prefix", "prefix/schemaBar", uidBar)) - .isFalse(); - } - - @Test - public void testIsSchemaSearchableByCaller_packageAccessibilityHandlesNameNotFoundException() - throws Exception { - // Values for a "foo" client - String packageNameFoo = "packageFoo"; - byte[] sha256CertFoo = new byte[] {10}; - int uidFoo = 1; - - // Pretend we can't find the Foo package. - mMockPackageManager.mockThrowsNameNotFoundException(packageNameFoo); - - // Grant package access - mVisibilityStore.setVisibility( - "prefix", - /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(), - /*schemasPackageAccessible=*/ ImmutableMap.of( - "prefix/schemaFoo", - ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo)))); - - // If we can't verify the Foo package that has access, assume it doesn't have access. - assertThat( - mVisibilityStore.isSchemaSearchableByCaller( - "prefix", "prefix/schemaFoo", uidFoo)) - .isFalse(); - } - - @Test - public void testEmptyPrefix() throws Exception { - // Values for a "foo" client - String packageNameFoo = "packageFoo"; - byte[] sha256CertFoo = new byte[] {10}; - int uidFoo = 1; - - mVisibilityStore.setVisibility( - /*prefix=*/ "", - /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(), - /*schemasPackageAccessible=*/ ImmutableMap.of( - "schema", - ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo)))); - - assertThat( - mVisibilityStore.isSchemaSearchableByCaller( - /*prefix=*/ "", "schema", mGlobalQuerierUid)) - .isTrue(); - - mMockPackageManager.mockGetPackageUid(packageNameFoo, uidFoo); - mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo); - assertThat(mVisibilityStore.isSchemaSearchableByCaller(/*prefix=*/ "", "schema", uidFoo)) - .isTrue(); - } -}