Merge "Update VisibilityStore to handle role-based system visibility." into sc-dev

This commit is contained in:
Cassie Wang
2021-06-03 22:16:06 +00:00
committed by Android (Google) Code Review
13 changed files with 599 additions and 509 deletions

View File

@@ -16,18 +16,15 @@
package com.android.server.appsearch;
import static android.content.pm.PackageManager.MATCH_FACTORY_ONLY;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.appsearch.exceptions.AppSearchException;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.os.UserHandle;
import android.util.ArrayMap;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.server.appsearch.external.localstorage.AppSearchImpl;
import com.android.server.appsearch.external.localstorage.AppSearchLogger;
@@ -49,12 +46,6 @@ public final class ImplInstanceManager {
@GuardedBy("mInstancesLocked")
private final Map<UserHandle, AppSearchImpl> mInstancesLocked = new ArrayMap<>();
private final String mGlobalQuerierPackage;
private ImplInstanceManager(@NonNull String globalQuerierPackage) {
mGlobalQuerierPackage = globalQuerierPackage;
}
/**
* Gets an instance of ImplInstanceManager to be used.
*
@@ -66,9 +57,7 @@ public final class ImplInstanceManager {
if (sImplInstanceManager == null) {
synchronized (ImplInstanceManager.class) {
if (sImplInstanceManager == null) {
sImplInstanceManager =
new ImplInstanceManager(
getGlobalAppSearchDataQuerierPackageName(context));
sImplInstanceManager = new ImplInstanceManager();
}
}
}
@@ -91,7 +80,7 @@ public final class ImplInstanceManager {
* <p>If no AppSearchImpl instance exists for the unlocked user, Icing will be initialized and
* one will be created.
*
* @param context The context
* @param context The system context
* @param userHandle The multi-user handle of the device user calling AppSearch
* @return An initialized {@link AppSearchImpl} for this user
*/
@@ -106,7 +95,8 @@ public final class ImplInstanceManager {
synchronized (mInstancesLocked) {
AppSearchImpl instance = mInstancesLocked.get(userHandle);
if (instance == null) {
instance = createImpl(context, userHandle, logger);
Context userContext = context.createContextAsUser(userHandle, /*flags=*/ 0);
instance = createImpl(userContext, userHandle, logger);
mInstancesLocked.put(userHandle, instance);
}
return instance;
@@ -177,7 +167,7 @@ public final class ImplInstanceManager {
}
private AppSearchImpl createImpl(
@NonNull Context context,
@NonNull Context userContext,
@NonNull UserHandle userHandle,
@Nullable AppSearchLogger logger)
throws AppSearchException {
@@ -185,33 +175,8 @@ public final class ImplInstanceManager {
// TODO(b/181787682): Swap AppSearchImpl and VisibilityStore to accept a UserHandle too
return AppSearchImpl.create(
appSearchDir,
context,
userContext,
userHandle.getIdentifier(),
mGlobalQuerierPackage,
/*logger=*/ null);
}
/**
* Returns the global querier package if it's a system package. Otherwise, empty string.
*
* @param context Context of the system service.
*/
@NonNull
private static String getGlobalAppSearchDataQuerierPackageName(@NonNull Context context) {
String globalAppSearchDataQuerierPackage =
context.getString(R.string.config_globalAppSearchDataQuerierPackage);
try {
if (context.getPackageManager()
.getPackageInfoAsUser(
globalAppSearchDataQuerierPackage,
MATCH_FACTORY_ONLY,
UserHandle.USER_SYSTEM)
== null) {
return "";
}
} catch (PackageManager.NameNotFoundException e) {
return "";
}
return globalAppSearchDataQuerierPackage;
}
}

View File

@@ -17,7 +17,6 @@
package com.android.server.appsearch.external.localstorage;
import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.addPrefixToDocument;
import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.createPackagePrefix;
import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.createPrefix;
import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.getDatabaseName;
import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.getPackageName;
@@ -60,6 +59,7 @@ import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
import com.android.server.appsearch.external.localstorage.stats.SearchStats;
import com.android.server.appsearch.visibilitystore.VisibilityStore;
import com.google.android.icing.IcingSearchEngine;
import com.google.android.icing.proto.DeleteByQueryResultProto;
@@ -98,6 +98,7 @@ import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -199,14 +200,12 @@ public final class AppSearchImpl implements Closeable {
@NonNull
public static AppSearchImpl create(
@NonNull File icingDir,
@NonNull Context context,
@NonNull Context userContext,
int userId,
@NonNull String globalQuerierPackage,
@Nullable AppSearchLogger logger)
throws AppSearchException {
Objects.requireNonNull(icingDir);
Objects.requireNonNull(context);
Objects.requireNonNull(globalQuerierPackage);
Objects.requireNonNull(userContext);
long totalLatencyStartMillis = SystemClock.elapsedRealtime();
InitializeStats.Builder initStatsBuilder = null;
@@ -215,8 +214,7 @@ public final class AppSearchImpl implements Closeable {
}
AppSearchImpl appSearchImpl =
new AppSearchImpl(
icingDir, context, userId, globalQuerierPackage, initStatsBuilder);
new AppSearchImpl(icingDir, userContext, userId, initStatsBuilder);
long prepareVisibilityStoreLatencyStartMillis = SystemClock.elapsedRealtime();
appSearchImpl.initializeVisibilityStore();
@@ -239,9 +237,8 @@ public final class AppSearchImpl implements Closeable {
/** @param initStatsBuilder collects stats for initialization if provided. */
private AppSearchImpl(
@NonNull File icingDir,
@NonNull Context context,
@NonNull Context userContext,
int userId,
@NonNull String globalQuerierPackage,
@Nullable InitializeStats.Builder initStatsBuilder)
throws AppSearchException {
mReadWriteLock.writeLock().lock();
@@ -259,8 +256,7 @@ public final class AppSearchImpl implements Closeable {
"Constructing IcingSearchEngine, response",
Objects.hashCode(mIcingSearchEngineLocked));
mVisibilityStoreLocked =
new VisibilityStore(this, context, userId, globalQuerierPackage);
mVisibilityStoreLocked = new VisibilityStore(this, userContext, userId);
// The core initialization procedure. If any part of this fails, we bail into
// resetLocked(), deleting all data (but hopefully allowing AppSearchImpl to come up).
@@ -495,7 +491,8 @@ public final class AppSearchImpl implements Closeable {
}
mVisibilityStoreLocked.setVisibility(
prefix,
packageName,
databaseName,
prefixedSchemasNotPlatformSurfaceable,
prefixedSchemasPackageAccessible);
@@ -844,17 +841,17 @@ public final class AppSearchImpl implements Closeable {
try {
throwIfClosedLocked();
// Convert package filters to prefix filters
Set<String> packageFilters = new ArraySet<>(searchSpec.getFilterPackageNames());
Set<String> prefixFilters = new ArraySet<>();
Set<String> allPrefixes = mNamespaceMapLocked.keySet();
if (packageFilters.isEmpty()) {
// Client didn't restrict their search over packages. Try to query over all
// packages/prefixes
prefixFilters = allPrefixes;
prefixFilters = mNamespaceMapLocked.keySet();
} else {
// Client did restrict their search over packages. Only include the prefixes that
// belong to the specified packages.
for (String prefix : allPrefixes) {
for (String prefix : mNamespaceMapLocked.keySet()) {
String packageName = getPackageName(prefix);
if (packageFilters.contains(packageName)) {
prefixFilters.add(prefix);
@@ -862,41 +859,50 @@ public final class AppSearchImpl implements Closeable {
}
}
// Find which schemas the client is allowed to query over.
Set<String> allowedPrefixedSchemas = new ArraySet<>();
List<String> schemaFilters = searchSpec.getFilterSchemas();
// Convert schema filters to prefixed schema filters
ArraySet<String> prefixedSchemaFilters = new ArraySet<>();
for (String prefix : prefixFilters) {
String packageName = getPackageName(prefix);
if (!schemaFilters.isEmpty()) {
for (String schema : schemaFilters) {
// Client specified some schemas to search over, check each one
String prefixedSchema = prefix + schema;
if (packageName.equals(callerPackageName)
|| mVisibilityStoreLocked.isSchemaSearchableByCaller(
prefix, prefixedSchema, callerUid)) {
allowedPrefixedSchemas.add(prefixedSchema);
}
}
} else {
List<String> schemaFilters = searchSpec.getFilterSchemas();
if (schemaFilters.isEmpty()) {
// Client didn't specify certain schemas to search over, check all schemas
Map<String, SchemaTypeConfigProto> prefixedSchemas =
mSchemaMapLocked.get(prefix);
if (prefixedSchemas != null) {
for (String prefixedSchema : prefixedSchemas.keySet()) {
if (packageName.equals(callerPackageName)
|| mVisibilityStoreLocked.isSchemaSearchableByCaller(
prefix, prefixedSchema, callerUid)) {
allowedPrefixedSchemas.add(prefixedSchema);
}
}
prefixedSchemaFilters.addAll(mSchemaMapLocked.get(prefix).keySet());
} else {
// Client specified some schemas to search over, check each one
for (int i = 0; i < schemaFilters.size(); i++) {
prefixedSchemaFilters.add(prefix + schemaFilters.get(i));
}
}
}
// Remove the schemas the client is not allowed to search over
Iterator<String> prefixedSchemaIt = prefixedSchemaFilters.iterator();
while (prefixedSchemaIt.hasNext()) {
String prefixedSchema = prefixedSchemaIt.next();
String packageName = getPackageName(prefixedSchema);
boolean allow;
if (packageName.equals(callerPackageName)) {
// Callers can always retrieve their own data
allow = true;
} else {
String databaseName = getDatabaseName(prefixedSchema);
allow =
mVisibilityStoreLocked.isSchemaSearchableByCaller(
packageName,
databaseName,
prefixedSchema,
callerPackageName,
callerUid);
}
if (!allow) {
prefixedSchemaIt.remove();
}
}
return doQueryLocked(
prefixFilters,
allowedPrefixedSchemas,
prefixedSchemaFilters,
queryExpression,
searchSpec,
sStatsBuilder);
@@ -1404,20 +1410,47 @@ public final class AppSearchImpl implements Closeable {
mReadWriteLock.writeLock().lock();
try {
throwIfClosedLocked();
Set<String> existingPackages = getPackageToDatabases().keySet();
if (existingPackages.contains(packageName)) {
existingPackages.remove(packageName);
prunePackageData(existingPackages);
}
} finally {
mReadWriteLock.writeLock().unlock();
}
}
/**
* Remove all {@link AppSearchSchema}s and {@link GenericDocument}s that doesn't belong to any
* of the given installed packages
*
* @param installedPackages The name of all installed package.
* @throws AppSearchException if we cannot remove the data.
*/
public void prunePackageData(@NonNull Set<String> installedPackages) throws AppSearchException {
mReadWriteLock.writeLock().lock();
try {
throwIfClosedLocked();
Map<String, Set<String>> packageToDatabases = getPackageToDatabases();
if (installedPackages.containsAll(packageToDatabases.keySet())) {
// No package got removed. We are good.
return;
}
// Prune schema proto
SchemaProto existingSchema = getSchemaProtoLocked();
SchemaProto.Builder newSchemaBuilder = SchemaProto.newBuilder();
String prefix = createPackagePrefix(packageName);
for (int i = 0; i < existingSchema.getTypesCount(); i++) {
if (!existingSchema.getTypes(i).getSchemaType().startsWith(prefix)) {
String packageName = getPackageName(existingSchema.getTypes(i).getSchemaType());
if (installedPackages.contains(packageName)) {
newSchemaBuilder.addTypes(existingSchema.getTypes(i));
}
}
SchemaProto finalSchema = newSchemaBuilder.build();
// Apply schema, set force override to true to remove all schemas and documents under
// that package.
// Apply schema, set force override to true to remove all schemas and documents that
// doesn't belong to any of these installed packages.
mLogUtil.piiTrace(
"clearPackageData.setSchema, request",
finalSchema.getTypesCount(),
@@ -1432,6 +1465,20 @@ public final class AppSearchImpl implements Closeable {
// Determine whether it succeeded.
checkSuccess(setSchemaResultProto.getStatus());
// Prune cached maps
for (Map.Entry<String, Set<String>> entry : packageToDatabases.entrySet()) {
String packageName = entry.getKey();
Set<String> databaseNames = entry.getValue();
if (!installedPackages.contains(packageName) && databaseNames != null) {
for (String databaseName : databaseNames) {
String removedPrefix = createPrefix(packageName, databaseName);
mSchemaMapLocked.remove(removedPrefix);
mNamespaceMapLocked.remove(removedPrefix);
}
}
}
// TODO(b/145759910) clear visibility setting for package.
} finally {
mReadWriteLock.writeLock().unlock();
}
@@ -1857,14 +1904,6 @@ public final class AppSearchImpl implements Closeable {
return schemaProto.getSchema();
}
/** Returns a set of all prefixes AppSearchImpl knows about. */
// TODO(b/180058203): Remove this method once platform has switched away from using this method.
@GuardedBy("mReadWriteLock")
@NonNull
Set<String> getPrefixesLocked() {
return mSchemaMapLocked.keySet();
}
private static void addToMap(
Map<String, Set<String>> map, String prefix, String prefixedValue) {
Set<String> values = map.get(prefix);

View File

@@ -26,36 +26,52 @@ import java.util.Set;
* {@link android.app.appsearch.SetSchemaRequest.Builder#setSchemaTypeDisplayedBySystem} API.
*
* This object is not thread safe.
* @hide
*/
public class NotPlatformSurfaceableMap {
class NotPlatformSurfaceableMap {
/**
* Maps prefixes to the set of prefixed schemas that are platform-hidden within that prefix.
* Maps packages to databases to the set of prefixed schemas that are platform-hidden within
* that database.
*/
private final Map<String, Set<String>> mMap = new ArrayMap<>();
private final Map<String, Map<String, Set<String>>> mMap = new ArrayMap<>();
/**
* Sets the prefixed schemas that are opted out of platform surfacing for the prefix.
* Sets the prefixed schemas that are opted out of platform surfacing for the database.
*
* <p>Any existing mappings for this prefix are overwritten.
*/
public void setNotPlatformSurfaceable(@NonNull String prefix, @NonNull Set<String> schemas) {
mMap.put(prefix, schemas);
public void setNotPlatformSurfaceable(
@NonNull String packageName,
@NonNull String databaseName,
@NonNull Set<String> prefixedSchemas) {
Map<String, Set<String>> databaseToSchemas = mMap.get(packageName);
if (databaseToSchemas == null) {
databaseToSchemas = new ArrayMap<>();
mMap.put(packageName, databaseToSchemas);
}
databaseToSchemas.put(databaseName, prefixedSchemas);
}
/**
* Returns whether the given prefixed schema is platform surfaceable (has not opted out) in the
* given prefix.
* given database.
*/
public boolean isSchemaPlatformSurfaceable(@NonNull String prefix, @NonNull String schemaType) {
Set<String> schemaTypes = mMap.get(prefix);
public boolean isSchemaPlatformSurfaceable(
@NonNull String packageName,
@NonNull String databaseName,
@NonNull String prefixedSchema) {
Map<String, Set<String>> databaseToSchemaType = mMap.get(packageName);
if (databaseToSchemaType == null) {
// No opt-outs for this package
return true;
}
Set<String> schemaTypes = databaseToSchemaType.get(databaseName);
if (schemaTypes == null) {
// No opt-outs for this prefix
// No opt-outs for this database
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);
return !schemaTypes.contains(prefixedSchema);
}
/** Discards all data in the map. */

View File

@@ -26,9 +26,8 @@ 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 {
class PackageAccessibleDocument extends GenericDocument {
/** Schema type for nested documents that hold package accessible information. */
public static final String SCHEMA_TYPE = "PackageAccessibleType";

View File

@@ -28,23 +28,31 @@ import java.util.Set;
* {@link android.app.appsearch.SetSchemaRequest.Builder#setSchemaTypeVisibilityForPackage} API.
*
* This object is not thread safe.
* @hide
*/
public class PackageAccessibleMap {
class PackageAccessibleMap {
/**
* Maps prefixes to prefixed schema types to PackageIdentifiers that have access to that schema.
* Maps packages to databases to prefixed schemas to PackageIdentifiers that have access to that
* schema.
*/
private final Map<String, Map<String, Set<PackageIdentifier>>> mMap = new ArrayMap<>();
private final Map<String, Map<String, Map<String, Set<PackageIdentifier>>>> mMap =
new ArrayMap<>();
/**
* Sets the prefixed schemas that have package visibility in the given prefix.
* Sets the prefixed schemas that have package visibility in the given database.
*
* <p>Any existing mappings for this prefix are overwritten.
*/
public void setPackageAccessible(
@NonNull String prefix,
@NonNull String packageName,
@NonNull String databaseName,
@NonNull Map<String, Set<PackageIdentifier>> schemaToPackageIdentifier) {
mMap.put(prefix, schemaToPackageIdentifier);
Map<String, Map<String, Set<PackageIdentifier>>> databaseToSchemaTypeToVisibility =
mMap.get(packageName);
if (databaseToSchemaTypeToVisibility == null) {
databaseToSchemaTypeToVisibility = new ArrayMap<>();
mMap.put(packageName, databaseToSchemaTypeToVisibility);
}
databaseToSchemaTypeToVisibility.put(databaseName, schemaToPackageIdentifier);
}
/**
@@ -55,12 +63,20 @@ public class PackageAccessibleMap {
*/
@NonNull
public Set<PackageIdentifier> getAccessiblePackages(
@NonNull String prefix, @NonNull String schemaType) {
Map<String, Set<PackageIdentifier>> schemaTypeToVisibility = mMap.get(prefix);
@NonNull String packageName,
@NonNull String databaseName,
@NonNull String prefixedSchema) {
Map<String, Map<String, Set<PackageIdentifier>>> databaseToSchemaTypeToVisibility =
mMap.get(packageName);
if (databaseToSchemaTypeToVisibility == null) {
return Collections.emptySet();
}
Map<String, Set<PackageIdentifier>> schemaTypeToVisibility =
databaseToSchemaTypeToVisibility.get(databaseName);
if (schemaTypeToVisibility == null) {
return Collections.emptySet();
}
Set<PackageIdentifier> accessiblePackages = schemaTypeToVisibility.get(schemaType);
Set<PackageIdentifier> accessiblePackages = schemaTypeToVisibility.get(prefixedSchema);
if (accessiblePackages == null) {
return Collections.emptySet();
}

View File

@@ -21,11 +21,8 @@ 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 {
/** Holds the visibility settings that apply to a package's databases. */
class VisibilityDocument extends GenericDocument {
/** Schema type for documents that hold AppSearch's metadata, e.g. visibility settings */
public static final String SCHEMA_TYPE = "VisibilityType";

View File

@@ -13,11 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.appsearch.visibilitystore;
// TODO(b/169883602): This is purposely a different package from the path so that it can access
// AppSearchImpl's methods without having to make them public. This should be moved into a proper
// package once AppSearchImpl-VisibilityStore's dependencies are refactored.
package com.android.server.appsearch.external.localstorage;
import static android.Manifest.permission.READ_GLOBAL_APP_SEARCH_DATA;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
@@ -33,13 +31,10 @@ import android.os.Process;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.appsearch.external.localstorage.AppSearchImpl;
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;
@@ -85,38 +80,24 @@ public class VisibilityStore {
* These cannot have any of the special characters used by AppSearchImpl (e.g. {@code
* AppSearchImpl#PACKAGE_DELIMITER} or {@code AppSearchImpl#DATABASE_DELIMITER}.
*/
static final String PACKAGE_NAME = "VS#Pkg";
@VisibleForTesting public static final String PACKAGE_NAME = "VS#Pkg";
static final String DATABASE_NAME = "VS#Db";
/**
* Prefix that AppSearchImpl creates for the VisibilityStore based on our package name and
* database name. Tracked here to tell when we're looking at our own prefix when looking through
* AppSearchImpl.
*/
static final String VISIBILITY_STORE_PREFIX =
PrefixUtil.createPrefix(PACKAGE_NAME, DATABASE_NAME);
@VisibleForTesting public static final String DATABASE_NAME = "VS#Db";
/** Namespace of documents that contain visibility settings */
private static final String NAMESPACE = "";
/**
* Prefix to add to all visibility document ids. IcingSearchEngine doesn't allow empty ids.
*/
/** Prefix to add to all visibility document ids. IcingSearchEngine doesn't allow empty ids. */
private static final String ID_PREFIX = "uri:";
private final AppSearchImpl mAppSearchImpl;
// Context of the system service.
private final Context mContext;
// Context of the user that the call is being made as.
private final Context mUserContext;
// User ID of the caller who we're checking visibility settings for.
private final int mUserId;
// UID of the package that has platform-query privileges, i.e. can query for all
// platform-surfaceable content.
private int mGlobalQuerierUid;
/** Stores the schemas that are platform-hidden. All values are prefixed. */
private final NotPlatformSurfaceableMap mNotPlatformSurfaceableMap =
new NotPlatformSurfaceableMap();
@@ -129,16 +110,15 @@ public class VisibilityStore {
* before using the object.
*
* @param appSearchImpl AppSearchImpl instance
* @param userContext Context of the user that the call is being made as
*/
public VisibilityStore(
@NonNull AppSearchImpl appSearchImpl,
@NonNull Context context,
@UserIdInt int userId,
@NonNull String globalQuerierPackage) {
@NonNull Context userContext,
@UserIdInt int userId) {
mAppSearchImpl = appSearchImpl;
mContext = context;
mUserContext = userContext;
mUserId = userId;
mGlobalQuerierUid = getGlobalQuerierUid(globalQuerierPackage);
}
/**
@@ -181,28 +161,44 @@ public class VisibilityStore {
// Populate visibility settings set
mNotPlatformSurfaceableMap.clear();
for (String prefix : mAppSearchImpl.getPrefixesLocked()) {
if (prefix.equals(VISIBILITY_STORE_PREFIX)) {
// Our own prefix. Skip
continue;
for (Map.Entry<String, Set<String>> entry :
mAppSearchImpl.getPackageToDatabases().entrySet()) {
String packageName = entry.getKey();
if (packageName.equals(PACKAGE_NAME)) {
continue; // Our own package. Skip.
}
try {
// Note: We use the other clients' prefixed names as ids
VisibilityDocument visibilityDocument = new VisibilityDocument(
mAppSearchImpl.getDocument(
PACKAGE_NAME,
DATABASE_NAME,
NAMESPACE,
/*id=*/ addIdPrefix(prefix),
/*typePropertyPaths=*/ Collections.emptyMap()));
for (String databaseName : entry.getValue()) {
VisibilityDocument visibilityDocument;
try {
// Note: We use the other clients' prefixed names as ids
visibilityDocument =
new VisibilityDocument(
mAppSearchImpl.getDocument(
PACKAGE_NAME,
DATABASE_NAME,
NAMESPACE,
/*id=*/ getVisibilityDocumentId(
packageName, databaseName),
/*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;
}
// Update platform visibility settings
String[] notPlatformSurfaceableSchemas =
visibilityDocument.getNotPlatformSurfaceableSchemas();
if (notPlatformSurfaceableSchemas != null) {
mNotPlatformSurfaceableMap.setNotPlatformSurfaceable(
prefix,
packageName,
databaseName,
new ArraySet<>(notPlatformSurfaceableSchemas));
}
@@ -226,25 +222,18 @@ public class VisibilityStore {
schemaToPackageIdentifierMap.put(prefixedSchema, packageIdentifiers);
}
}
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
// 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;
mPackageAccessibleMap.setPackageAccessible(
packageName, databaseName, schemaToPackageIdentifierMap);
}
}
}
/**
* Sets visibility settings for {@code prefix}. Any previous visibility settings will be
* Sets visibility settings for the given database. Any previous visibility settings will be
* overwritten.
*
* @param prefix Prefix that identifies who owns the {@code schemasNotPlatformSurfaceable}.
* @param packageName Package of app that owns the {@code schemasNotPlatformSurfaceable}.
* @param databaseName Database that owns the {@code schemasNotPlatformSurfaceable}.
* @param schemasNotPlatformSurfaceable Set of prefixed schemas that should be hidden from the
* platform.
* @param schemasPackageAccessible Map of prefixed schemas to a list of package identifiers that
@@ -252,17 +241,20 @@ public class VisibilityStore {
* @throws AppSearchException on AppSearchImpl error.
*/
public void setVisibility(
@NonNull String prefix,
@NonNull String packageName,
@NonNull String databaseName,
@NonNull Set<String> schemasNotPlatformSurfaceable,
@NonNull Map<String, List<PackageIdentifier>> schemasPackageAccessible)
throws AppSearchException {
Objects.requireNonNull(prefix);
Objects.requireNonNull(packageName);
Objects.requireNonNull(databaseName);
Objects.requireNonNull(schemasNotPlatformSurfaceable);
Objects.requireNonNull(schemasPackageAccessible);
// Persist the document
VisibilityDocument.Builder visibilityDocument =
new VisibilityDocument.Builder(NAMESPACE, /*id=*/ addIdPrefix(prefix));
new VisibilityDocument.Builder(
NAMESPACE, /*id=*/ getVisibilityDocumentId(packageName, databaseName));
if (!schemasNotPlatformSurfaceable.isEmpty()) {
visibilityDocument.setSchemasNotPlatformSurfaceable(
schemasNotPlatformSurfaceable.toArray(new String[0]));
@@ -293,29 +285,50 @@ public class VisibilityStore {
mAppSearchImpl.persistToDisk(PersistType.Code.LITE);
// Update derived data structures.
mNotPlatformSurfaceableMap.setNotPlatformSurfaceable(prefix, schemasNotPlatformSurfaceable);
mPackageAccessibleMap.setPackageAccessible(prefix, schemaToPackageIdentifierMap);
mNotPlatformSurfaceableMap.setNotPlatformSurfaceable(
packageName, databaseName, schemasNotPlatformSurfaceable);
mPackageAccessibleMap.setPackageAccessible(
packageName, databaseName, schemaToPackageIdentifierMap);
}
/** Checks whether {@code prefixedSchema} can be searched over by the {@code callerUid}. */
/**
* Checks whether {@code prefixedSchema} can be searched over by the {@code callerUid}.
*
* @param packageName Package that owns the schema.
* @param databaseName Database within the package that owns the schema.
* @param prefixedSchema Prefixed schema type the caller is trying to access.
* @param callerPackageName Package name of the caller.
* @param callerUid Uid of the caller.
*/
public boolean isSchemaSearchableByCaller(
@NonNull String prefix, @NonNull String prefixedSchema, int callerUid) {
Objects.requireNonNull(prefix);
@NonNull String packageName,
@NonNull String databaseName,
@NonNull String prefixedSchema,
@NonNull String callerPackageName,
int callerUid) {
Objects.requireNonNull(packageName);
Objects.requireNonNull(databaseName);
Objects.requireNonNull(prefixedSchema);
Objects.requireNonNull(callerPackageName);
if (prefix.equals(VISIBILITY_STORE_PREFIX)) {
if (packageName.equals(PACKAGE_NAME)) {
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)
&& mNotPlatformSurfaceableMap.isSchemaPlatformSurfaceable(prefix, prefixedSchema)) {
// TODO(b/180058203): If we can cache or pass in that a caller has the
// READ_GLOBAL_SEARCH_DATA permission, then we can save this package manager lookup for
// each schema we may check in the loop.
if (mNotPlatformSurfaceableMap.isSchemaPlatformSurfaceable(
packageName, databaseName, prefixedSchema)
&& mUserContext
.getPackageManager()
.checkPermission(READ_GLOBAL_APP_SEARCH_DATA, callerPackageName)
== PackageManager.PERMISSION_GRANTED) {
return true;
}
// May not be platform surfaceable, but might still be accessible through 3p access.
return isSchemaPackageAccessible(prefix, prefixedSchema, callerUid);
return isSchemaPackageAccessible(packageName, databaseName, prefixedSchema, callerUid);
}
/**
@@ -328,20 +341,32 @@ public class VisibilityStore {
* does not handle packages that have been signed by multiple certificates.
*/
private boolean isSchemaPackageAccessible(
@NonNull String prefix, @NonNull String prefixedSchema, int callerUid) {
@NonNull String packageName,
@NonNull String databaseName,
@NonNull String prefixedSchema,
int callerUid) {
Set<PackageIdentifier> packageIdentifiers =
mPackageAccessibleMap.getAccessiblePackages(prefix, prefixedSchema);
mPackageAccessibleMap.getAccessiblePackages(
packageName, databaseName, 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
// package manager could be costly. We would also need to update the cache on
// package-removals.
if (getPackageUidAsUser(packageIdentifier.getPackageName()) != callerUid) {
// 'callerUid' is the uid of the caller. The 'user' doesn't have to be the same one as
// the callerUid since clients can createContextAsUser with some other user, and then
// make calls to us. So just check if the appId portion of the uid is the same. This is
// essentially UserHandle.isSameApp, but that's not a system API for us to use.
int callerAppId = UserHandle.getAppId((callerUid));
int userAppId =
UserHandle.getAppId(getPackageUidAsUser(packageIdentifier.getPackageName()));
if (callerAppId != userAppId) {
continue;
}
// Check that the package also has the matching certificate
if (mContext.getPackageManager()
if (mUserContext
.getPackageManager()
.hasSigningCertificate(
packageIdentifier.getPackageName(),
packageIdentifier.getSha256Certificate(),
@@ -367,36 +392,14 @@ public class VisibilityStore {
/**
* Adds a prefix to create a visibility store document's id.
*
* @param id Non-prefixed id
* @param packageName Package to which the visibility doc refers
* @param databaseName Database to which the visibility doc refers
* @return Prefixed id
*/
private static String addIdPrefix(String id) {
return ID_PREFIX + id;
}
/**
* Finds the uid of the {@code globalQuerierPackage}. {@code globalQuerierPackage} must be a
* pre-installed, system app. Returns {@link Process#INVALID_UID} if unable to find the UID.
*/
private int getGlobalQuerierUid(@NonNull String globalQuerierPackage) {
try {
int flags =
PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
| PackageManager.MATCH_SYSTEM_ONLY;
// It doesn't matter that we're using the caller's userId here. We'll eventually check
// that the two uids in question belong to the same appId.
return mContext.getPackageManager()
.getPackageUidAsUser(globalQuerierPackage, flags, mUserId);
} catch (PackageManager.NameNotFoundException e) {
// Global querier doesn't exist.
Log.i(
TAG,
"AppSearch global querier package not found on device: '"
+ globalQuerierPackage
+ "'");
}
return Process.INVALID_UID;
@NonNull
private static String getVisibilityDocumentId(
@NonNull String packageName, @NonNull String databaseName) {
return ID_PREFIX + PrefixUtil.createPrefix(packageName, databaseName);
}
/**
@@ -405,7 +408,7 @@ public class VisibilityStore {
*/
private int getPackageUidAsUser(@NonNull String packageName) {
try {
return mContext.getPackageManager().getPackageUidAsUser(packageName, mUserId);
return mUserContext.getPackageManager().getPackageUidAsUser(packageName, mUserId);
} catch (PackageManager.NameNotFoundException e) {
// Package doesn't exist, continue
}

View File

@@ -1 +1 @@
be6d5138cbd64d3fd401a83d30bf9ad22a6c2d17
c35ced970a63a6c7b1d17f9706160579540850d6

View File

@@ -19,19 +19,21 @@
// global query integration tests that can test AppSearchImpl-VisibilityStore integration logic.
package com.android.server.appsearch.external.localstorage;
import static android.Manifest.permission.READ_GLOBAL_APP_SEARCH_DATA;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static com.google.common.truth.Truth.assertThat;
import android.app.appsearch.AppSearchSchema;
import android.app.appsearch.GenericDocument;
import android.app.appsearch.PackageIdentifier;
import android.app.appsearch.SearchResultPage;
import android.app.appsearch.SearchSpec;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.PackageManager;
import androidx.test.core.app.ApplicationProvider;
import com.android.compatibility.common.util.SystemUtil;
import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
import com.google.common.collect.ImmutableList;
@@ -43,7 +45,6 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.util.Collections;
import java.util.List;
/** This tests AppSearchImpl when it's running with a platform-backed VisibilityStore. */
public class AppSearchImplPlatformTest {
@@ -70,126 +71,11 @@ public class AppSearchImplPlatformTest {
mTemporaryFolder.newFolder(),
mContext,
mContext.getUserId(),
mContext.getPackageName(),
/*logger=*/ null);
mGlobalQuerierUid =
mContext.getPackageManager().getPackageUid(mContext.getPackageName(), /*flags=*/ 0);
}
/**
* 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<AppSearchSchema> schema1 =
ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
mAppSearchImpl.setSchema(
"package1",
"database1",
schema1,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*schemaVersion=*/ 0);
// Insert package2 schema
List<AppSearchSchema> schema2 =
ImmutableList.of(new AppSearchSchema.Builder("schema2").build());
mAppSearchImpl.setSchema(
"package2",
"database2",
schema2,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*schemaVersion=*/ 0);
// Insert package1 document
GenericDocument document1 =
new GenericDocument.Builder<>("namespace", "uri", "schema1").build();
mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
// Insert package2 document
GenericDocument document2 =
new GenericDocument.Builder<>("namespace", "uri", "schema2").build();
mAppSearchImpl.putDocument("package2", "database2", document2, /*logger=*/ null);
// No query filters specified, global query can retrieve all documents.
SearchSpec searchSpec =
new SearchSpec.Builder().setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY).build();
SearchResultPage searchResultPage = mAppSearchImpl.globalQuery(
"", searchSpec, mContext.getPackageName(), mGlobalQuerierUid, /*logger=*/ null);
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).getGenericDocument()).isEqualTo(document2);
assertThat(searchResultPage.getResults().get(1).getGenericDocument()).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<AppSearchSchema> schema1 =
ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
mAppSearchImpl.setSchema(
"package1",
"database1",
schema1,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*schemaVersion=*/ 0);
// Insert package2 schema
List<AppSearchSchema> schema2 =
ImmutableList.of(new AppSearchSchema.Builder("schema2").build());
mAppSearchImpl.setSchema(
"package2",
"database2",
schema2,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*schemaVersion=*/ 0);
// Insert package1 document
GenericDocument document1 =
new GenericDocument.Builder<>("namespace", "uri", "schema1").build();
mAppSearchImpl.putDocument("package1", "database1", document1, /*logger=*/ null);
// Insert package2 document
GenericDocument document2 =
new GenericDocument.Builder<>("namespace", "uri", "schema2").build();
mAppSearchImpl.putDocument("package2", "database2", document2, /*logger=*/ null);
// "package1" filter specified
SearchSpec searchSpec =
new SearchSpec.Builder()
.setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
.addFilterPackageNames("package1")
.build();
SearchResultPage searchResultPage = mAppSearchImpl.globalQuery(
"", searchSpec, mContext.getPackageName(), mGlobalQuerierUid, /*logger=*/ null);
assertThat(searchResultPage.getResults()).hasSize(1);
assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
// "package2" filter specified
searchSpec =
new SearchSpec.Builder()
.setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
.addFilterPackageNames("package2")
.build();
searchResultPage = mAppSearchImpl.globalQuery(
"", searchSpec, mContext.getPackageName(), mGlobalQuerierUid, /*logger=*/ null);
assertThat(searchResultPage.getResults()).hasSize(1);
assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
}
@Test
public void testSetSchema_existingSchemaRetainsVisibilitySetting() throws Exception {
@@ -202,6 +88,12 @@ public class AppSearchImplPlatformTest {
mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
// Make sure we have global query privileges and "foo" doesn't
mMockPackageManager.mockCheckPermission(
READ_GLOBAL_APP_SEARCH_DATA, mContext.getPackageName(), PERMISSION_GRANTED);
mMockPackageManager.mockCheckPermission(
READ_GLOBAL_APP_SEARCH_DATA, packageNameFoo, PERMISSION_DENIED);
// Set schema1
String prefix = PrefixUtil.createPrefix("package", "database");
mAppSearchImpl.setSchema(
@@ -220,12 +112,22 @@ public class AppSearchImplPlatformTest {
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
prefix, prefix + "schema1", mGlobalQuerierUid))
"package",
"database",
prefix + "schema1",
mContext.getPackageName(),
mGlobalQuerierUid))
.isFalse();
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(prefix, prefix + "schema1", uidFoo))
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
packageNameFoo,
uidFoo))
.isTrue();
// Add a new schema, and include the already-existing "schema1"
@@ -243,29 +145,57 @@ public class AppSearchImplPlatformTest {
/*schemaVersion=*/ 0);
// Check that "schema1" still has the same visibility settings
SystemUtil.runWithShellPermissionIdentity(
() -> {
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
mContext.getPackageName(),
mGlobalQuerierUid))
.isFalse();
},
READ_GLOBAL_APP_SEARCH_DATA);
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
prefix, prefix + "schema1", mGlobalQuerierUid))
.isFalse();
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(prefix, prefix + "schema1", uidFoo))
"package",
"database",
prefix + "schema1",
packageNameFoo,
uidFoo))
.isTrue();
// "schema2" has default visibility settings
SystemUtil.runWithShellPermissionIdentity(
() -> {
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema2",
mContext.getPackageName(),
mGlobalQuerierUid))
.isTrue();
},
READ_GLOBAL_APP_SEARCH_DATA);
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
prefix, prefix + "schema2", mGlobalQuerierUid))
.isTrue();
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(prefix, prefix + "schema2", uidFoo))
"package",
"database",
prefix + "schema2",
packageNameFoo,
uidFoo))
.isFalse();
}
@@ -280,6 +210,12 @@ public class AppSearchImplPlatformTest {
mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
// Make sure we have global query privileges and "foo" doesn't
mMockPackageManager.mockCheckPermission(
READ_GLOBAL_APP_SEARCH_DATA, mContext.getPackageName(), PERMISSION_GRANTED);
mMockPackageManager.mockCheckPermission(
READ_GLOBAL_APP_SEARCH_DATA, packageNameFoo, PERMISSION_DENIED);
String prefix = PrefixUtil.createPrefix("package", "database");
mAppSearchImpl.setSchema(
"package",
@@ -297,12 +233,22 @@ public class AppSearchImplPlatformTest {
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
prefix, prefix + "schema1", mGlobalQuerierUid))
"package",
"database",
prefix + "schema1",
mContext.getPackageName(),
mGlobalQuerierUid))
.isFalse();
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(prefix, prefix + "schema1", uidFoo))
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
packageNameFoo,
uidFoo))
.isTrue();
// Remove "schema1" by force overriding
@@ -320,12 +266,22 @@ public class AppSearchImplPlatformTest {
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
prefix, prefix + "schema1", mGlobalQuerierUid))
"package",
"database",
prefix + "schema1",
mContext.getPackageName(),
mGlobalQuerierUid))
.isTrue();
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(prefix, prefix + "schema1", uidFoo))
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
packageNameFoo,
uidFoo))
.isFalse();
// Add "schema1" back, it gets default visibility settings which means it's not platform
@@ -338,21 +294,35 @@ public class AppSearchImplPlatformTest {
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*schemaVersion=*/ 0);
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
prefix, prefix + "schema1", mGlobalQuerierUid))
"package",
"database",
prefix + "schema1",
mContext.getPackageName(),
mGlobalQuerierUid))
.isTrue();
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(prefix, prefix + "schema1", uidFoo))
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
packageNameFoo,
uidFoo))
.isFalse();
}
@Test
public void testSetSchema_defaultPlatformVisible() throws Exception {
// Make sure we have global query privileges
mMockPackageManager.mockCheckPermission(
READ_GLOBAL_APP_SEARCH_DATA, mContext.getPackageName(), PERMISSION_GRANTED);
String prefix = PrefixUtil.createPrefix("package", "database");
mAppSearchImpl.setSchema(
"package",
@@ -362,16 +332,25 @@ public class AppSearchImplPlatformTest {
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*schemaVersion=*/ 0);
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
prefix, prefix + "Schema", mGlobalQuerierUid))
"package",
"database",
prefix + "Schema",
mContext.getPackageName(),
mGlobalQuerierUid))
.isTrue();
}
@Test
public void testSetSchema_platformHidden() throws Exception {
// Make sure we have global query privileges
mMockPackageManager.mockCheckPermission(
READ_GLOBAL_APP_SEARCH_DATA, mContext.getPackageName(), PERMISSION_GRANTED);
String prefix = PrefixUtil.createPrefix("package", "database");
mAppSearchImpl.setSchema(
"package",
@@ -381,16 +360,27 @@ public class AppSearchImplPlatformTest {
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*schemaVersion=*/ 0);
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
prefix, prefix + "Schema", mGlobalQuerierUid))
"package",
"database",
prefix + "Schema",
mContext.getPackageName(),
mGlobalQuerierUid))
.isFalse();
}
@Test
public void testSetSchema_defaultNotPackageAccessible() throws Exception {
String packageName = "com.package";
// Make sure package doesn't global query privileges
mMockPackageManager.mockCheckPermission(
READ_GLOBAL_APP_SEARCH_DATA, packageName, PERMISSION_DENIED);
String prefix = PrefixUtil.createPrefix("package", "database");
mAppSearchImpl.setSchema(
"package",
@@ -404,7 +394,11 @@ public class AppSearchImplPlatformTest {
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
prefix, prefix + "Schema", /*callerUid=*/ 42))
"package",
"database",
prefix + "Schema",
packageName,
/*callerUid=*/ 42))
.isFalse();
}
@@ -419,6 +413,10 @@ public class AppSearchImplPlatformTest {
mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
// Make sure foo doesn't have global query privileges
mMockPackageManager.mockCheckPermission(
READ_GLOBAL_APP_SEARCH_DATA, packageNameFoo, PERMISSION_DENIED);
String prefix = PrefixUtil.createPrefix("package", "database");
mAppSearchImpl.setSchema(
"package",
@@ -433,7 +431,12 @@ public class AppSearchImplPlatformTest {
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(prefix, prefix + "Schema", uidFoo))
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "Schema",
packageNameFoo,
uidFoo))
.isTrue();
}
}

View File

@@ -44,6 +44,12 @@ public class MockPackageManager {
return mMockPackageManager;
}
/** Mock a checkPermission call. */
public void mockCheckPermission(String permission, String packageName, int permissionResult) {
when(mMockPackageManager.checkPermission(permission, packageName))
.thenReturn(permissionResult);
}
/** Mock a NameNotFoundException if the package name isn't installed. */
public void mockThrowsNameNotFoundException(String packageName) {
try {

View File

@@ -15,10 +15,14 @@
*/
// TODO(b/169883602): This is purposely a different package from the path so that it can access
// AppSearchImpl and VisibilityStore methods without having to make methods public. This should be
// moved into a proper package once AppSearchImpl-VisibilityStore's dependencies are refactored.
// AppSearchImpl methods without having to make methods public. This should be moved into a proper
// package once AppSearchImpl-VisibilityStore's dependencies are refactored.
package com.android.server.appsearch.external.localstorage;
import static android.Manifest.permission.READ_GLOBAL_APP_SEARCH_DATA;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static com.google.common.truth.Truth.assertThat;
import android.app.appsearch.PackageIdentifier;
@@ -29,6 +33,7 @@ import android.content.pm.PackageManager;
import androidx.test.core.app.ApplicationProvider;
import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
import com.android.server.appsearch.visibilitystore.VisibilityStore;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -48,7 +53,7 @@ public class VisibilityStoreTest {
private Context mContext;
private AppSearchImpl mAppSearchImpl;
private VisibilityStore mVisibilityStore;
private int mGlobalQuerierUid;
private int mUid;
@Before
public void setUp() throws Exception {
@@ -67,11 +72,9 @@ public class VisibilityStoreTest {
mTemporaryFolder.newFolder(),
mContext,
mContext.getUserId(),
/*globalQuerierPackage=*/ mContext.getPackageName(),
/*logger=*/ null);
mGlobalQuerierUid =
mContext.getPackageManager().getPackageUid(mContext.getPackageName(), /*flags=*/ 0);
mUid = mContext.getPackageManager().getPackageUid(mContext.getPackageName(), /*flags=*/ 0);
mVisibilityStore = mAppSearchImpl.getVisibilityStoreLocked();
}
@@ -99,83 +102,98 @@ public class VisibilityStoreTest {
@Test
public void testSetVisibility_platformSurfaceable() throws Exception {
// Make sure we have global query privileges
mMockPackageManager.mockCheckPermission(
READ_GLOBAL_APP_SEARCH_DATA, mContext.getPackageName(), PERMISSION_GRANTED);
mVisibilityStore.setVisibility(
"prefix",
"package",
"database",
/*schemasNotPlatformSurfaceable=*/ ImmutableSet.of(
"prefix/schema1", "prefix/schema2"),
/*schemasPackageAccessible=*/ Collections.emptyMap());
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"prefix", "prefix/schema1", mGlobalQuerierUid))
"package",
"database",
"prefix/schema1",
mContext.getPackageName(),
mUid))
.isFalse();
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"prefix", "prefix/schema2", mGlobalQuerierUid))
"package",
"database",
"prefix/schema2",
mContext.getPackageName(),
mUid))
.isFalse();
// New .setVisibility() call completely overrides previous visibility settings. So
// "schema2" isn't preserved.
// New .setVisibility() call completely overrides previous visibility settings.
// So "schema2" isn't preserved.
mVisibilityStore.setVisibility(
"prefix",
"package",
"database",
/*schemasNotPlatformSurfaceable=*/ ImmutableSet.of(
"prefix/schema1", "prefix/schema3"),
/*schemasPackageAccessible=*/ Collections.emptyMap());
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"prefix", "prefix/schema1", mGlobalQuerierUid))
"package",
"database",
"prefix/schema1",
mContext.getPackageName(),
mUid))
.isFalse();
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"prefix", "prefix/schema2", mGlobalQuerierUid))
"package",
"database",
"prefix/schema2",
mContext.getPackageName(),
mUid))
.isTrue();
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"prefix", "prefix/schema3", mGlobalQuerierUid))
"package",
"database",
"prefix/schema3",
mContext.getPackageName(),
mUid))
.isFalse();
// Everything defaults to visible again.
mVisibilityStore.setVisibility(
"prefix",
"package",
"database",
/*schemasNotPlatformSurfaceable=*/ Collections.emptySet(),
/*schemasPackageAccessible=*/ Collections.emptyMap());
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"prefix", "prefix/schema1", mGlobalQuerierUid))
"package",
"database",
"prefix/schema1",
mContext.getPackageName(),
mUid))
.isTrue();
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"prefix", "prefix/schema2", mGlobalQuerierUid))
"package",
"database",
"prefix/schema2",
mContext.getPackageName(),
mUid))
.isTrue();
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"prefix", "prefix/schema3", mGlobalQuerierUid))
"package",
"database",
"prefix/schema3",
mContext.getPackageName(),
mUid))
.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,
mContext.getUserId(),
/*globalQuerierPackage=*/ mContext.getPackageName(),
/*logger=*/ null);
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
@@ -191,19 +209,26 @@ public class VisibilityStoreTest {
// Can't be the same value as uidFoo nor uidBar
int uidNotFooOrBar = 3;
// Make sure none of them have global query privileges
mMockPackageManager.mockCheckPermission(
READ_GLOBAL_APP_SEARCH_DATA, packageNameFoo, PERMISSION_DENIED);
mMockPackageManager.mockCheckPermission(
READ_GLOBAL_APP_SEARCH_DATA, packageNameBar, PERMISSION_DENIED);
// By default, a schema isn't package accessible.
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"prefix", "prefix/schemaFoo", uidFoo))
"package", "database", "prefix/schemaFoo", packageNameFoo, uidFoo))
.isFalse();
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"prefix", "prefix/schemaBar", uidBar))
"package", "database", "prefix/schemaBar", packageNameBar, uidBar))
.isFalse();
// Grant package access
mVisibilityStore.setVisibility(
"prefix",
"package",
"database",
/*schemasNotPlatformSurfaceable=*/ Collections.emptySet(),
/*schemasPackageAccessible=*/ ImmutableMap.of(
"prefix/schemaFoo",
@@ -216,7 +241,7 @@ public class VisibilityStoreTest {
mMockPackageManager.mockRemoveSigningCertificate(packageNameFoo, sha256CertFoo);
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"prefix", "prefix/schemaFoo", uidFoo))
"package", "database", "prefix/schemaFoo", packageNameFoo, uidFoo))
.isFalse();
// Should fail if PackageManager doesn't think the package belongs to the uid
@@ -225,7 +250,7 @@ public class VisibilityStoreTest {
mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"prefix", "prefix/schemaFoo", uidFoo))
"package", "database", "prefix/schemaFoo", packageNameFoo, uidFoo))
.isFalse();
// But if uid and certificate match, then we should have access
@@ -233,20 +258,21 @@ public class VisibilityStoreTest {
mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"prefix", "prefix/schemaFoo", uidFoo))
"package", "database", "prefix/schemaFoo", packageNameFoo, uidFoo))
.isTrue();
mMockPackageManager.mockGetPackageUidAsUser(packageNameBar, mContext.getUserId(), uidBar);
mMockPackageManager.mockAddSigningCertificate(packageNameBar, sha256CertBar);
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"prefix", "prefix/schemaBar", uidBar))
"package", "database", "prefix/schemaBar", packageNameBar, uidBar))
.isTrue();
// New .setVisibility() call completely overrides previous visibility settings. So
// "schemaBar" settings aren't preserved.
mVisibilityStore.setVisibility(
"prefix",
"package",
"database",
/*schemasNotPlatformSurfaceable=*/ Collections.emptySet(),
/*schemasPackageAccessible=*/ ImmutableMap.of(
"prefix/schemaFoo",
@@ -256,14 +282,14 @@ public class VisibilityStoreTest {
mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"prefix", "prefix/schemaFoo", uidFoo))
"package", "database", "prefix/schemaFoo", packageNameFoo, uidFoo))
.isTrue();
mMockPackageManager.mockGetPackageUidAsUser(packageNameBar, mContext.getUserId(), uidBar);
mMockPackageManager.mockAddSigningCertificate(packageNameBar, sha256CertBar);
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"prefix", "prefix/schemaBar", uidBar))
"package", "database", "prefix/schemaBar", packageNameBar, uidBar))
.isFalse();
}
@@ -278,9 +304,14 @@ public class VisibilityStoreTest {
// Pretend we can't find the Foo package.
mMockPackageManager.mockThrowsNameNotFoundException(packageNameFoo);
// Make sure "foo" doesn't have global query privileges
mMockPackageManager.mockCheckPermission(
READ_GLOBAL_APP_SEARCH_DATA, packageNameFoo, PERMISSION_DENIED);
// Grant package access
mVisibilityStore.setVisibility(
"prefix",
"package",
"database",
/*schemasNotPlatformSurfaceable=*/ Collections.emptySet(),
/*schemasPackageAccessible=*/ ImmutableMap.of(
"prefix/schemaFoo",
@@ -289,7 +320,7 @@ public class VisibilityStoreTest {
// If we can't verify the Foo package that has access, assume it doesn't have access.
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"prefix", "prefix/schemaFoo", uidFoo))
"package", "database", "prefix/schemaFoo", packageNameFoo, uidFoo))
.isFalse();
}
@@ -300,8 +331,15 @@ public class VisibilityStoreTest {
byte[] sha256CertFoo = new byte[] {10};
int uidFoo = 1;
// Set it up such that the test package has global query privileges, but "foo" doesn't.
mMockPackageManager.mockCheckPermission(
READ_GLOBAL_APP_SEARCH_DATA, mContext.getPackageName(), PERMISSION_GRANTED);
mMockPackageManager.mockCheckPermission(
READ_GLOBAL_APP_SEARCH_DATA, packageNameFoo, PERMISSION_DENIED);
mVisibilityStore.setVisibility(
/*prefix=*/ "",
/*packageName=*/ "",
/*databaseName=*/ "",
/*schemasNotPlatformSurfaceable=*/ Collections.emptySet(),
/*schemasPackageAccessible=*/ ImmutableMap.of(
"schema",
@@ -309,12 +347,22 @@ public class VisibilityStoreTest {
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
/*prefix=*/ "", "schema", mGlobalQuerierUid))
/*packageName=*/ "",
/*databaseName=*/ "",
"schema",
mContext.getPackageName(),
mUid))
.isTrue();
mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
assertThat(mVisibilityStore.isSchemaSearchableByCaller(/*prefix=*/ "", "schema", uidFoo))
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
/*packageName=*/ "",
/*databaseName=*/ "",
"schema",
packageNameFoo,
uidFoo))
.isTrue();
}
}

View File

@@ -55,6 +55,7 @@ import com.android.server.appsearch.proto.SearchSpecProto;
import com.android.server.appsearch.proto.StatusProto;
import com.android.server.appsearch.proto.StringIndexingConfig;
import com.android.server.appsearch.proto.TermMatchType;
import com.android.server.appsearch.visibilitystore.VisibilityStore;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -86,7 +87,6 @@ public class AppSearchImplTest {
mTemporaryFolder.newFolder(),
context,
VisibilityStore.NO_OP_USER_ID,
/*globalQuerierPackage=*/ context.getPackageName(),
/*logger=*/ null);
}
@@ -496,11 +496,7 @@ public class AppSearchImplTest {
File appsearchDir = mTemporaryFolder.newFolder();
AppSearchImpl appSearchImpl =
AppSearchImpl.create(
appsearchDir,
context,
VisibilityStore.NO_OP_USER_ID,
/*globalQuerierPackage=*/ "",
/*logger=*/ null);
appsearchDir, context, VisibilityStore.NO_OP_USER_ID, /*logger=*/ null);
// Insert schema
List<AppSearchSchema> schemas =
@@ -563,11 +559,7 @@ public class AppSearchImplTest {
appSearchImpl.close();
appSearchImpl =
AppSearchImpl.create(
appsearchDir,
context,
VisibilityStore.NO_OP_USER_ID,
/*globalQuerierPackage=*/ context.getPackageName(),
testLogger);
appsearchDir, context, VisibilityStore.NO_OP_USER_ID, testLogger);
// Check recovery state
InitializeStats initStats = testLogger.mInitializeStats;
@@ -1163,6 +1155,7 @@ public class AppSearchImplTest {
public void testClearPackageData() throws AppSearchException {
List<SchemaTypeConfigProto> existingSchemas =
mAppSearchImpl.getSchemaProtoLocked().getTypesList();
Map<String, Set<String>> existingDatabases = mAppSearchImpl.getPackageToDatabases();
// Insert package schema
List<AppSearchSchema> schema =
@@ -1210,6 +1203,67 @@ public class AppSearchImplTest {
// Verify the schema is cleared.
assertThat(mAppSearchImpl.getSchemaProtoLocked().getTypesList())
.containsExactlyElementsIn(existingSchemas);
assertThat(mAppSearchImpl.getPackageToDatabases())
.containsExactlyEntriesIn(existingDatabases);
}
@Test
public void testPrunePackageData() throws AppSearchException {
List<SchemaTypeConfigProto> existingSchemas =
mAppSearchImpl.getSchemaProtoLocked().getTypesList();
Map<String, Set<String>> existingDatabases = mAppSearchImpl.getPackageToDatabases();
Set<String> existingPackages = new ArraySet<>(existingSchemas.size());
for (int i = 0; i < existingSchemas.size(); i++) {
existingPackages.add(PrefixUtil.getPackageName(existingSchemas.get(i).getSchemaType()));
}
// Insert schema for package A and B.
List<AppSearchSchema> schema =
ImmutableList.of(new AppSearchSchema.Builder("schema").build());
mAppSearchImpl.setSchema(
"packageA",
"database",
schema,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
mAppSearchImpl.setSchema(
"packageB",
"database",
schema,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
// Verify these two packages is stored in AppSearch
SchemaProto expectedProto =
SchemaProto.newBuilder()
.addTypes(
SchemaTypeConfigProto.newBuilder()
.setSchemaType("packageA$database/schema")
.setVersion(0))
.addTypes(
SchemaTypeConfigProto.newBuilder()
.setSchemaType("packageB$database/schema")
.setVersion(0))
.build();
List<SchemaTypeConfigProto> expectedTypes = new ArrayList<>();
expectedTypes.addAll(existingSchemas);
expectedTypes.addAll(expectedProto.getTypesList());
assertThat(mAppSearchImpl.getSchemaProtoLocked().getTypesList())
.containsExactlyElementsIn(expectedTypes);
// Prune packages
mAppSearchImpl.prunePackageData(existingPackages);
// Verify the schema is same as beginning.
assertThat(mAppSearchImpl.getSchemaProtoLocked().getTypesList())
.containsExactlyElementsIn(existingSchemas);
assertThat(mAppSearchImpl.getPackageToDatabases())
.containsExactlyEntriesIn(existingDatabases);
}
@Test
@@ -1258,36 +1312,6 @@ public class AppSearchImplTest {
.containsExactlyEntriesIn(expectedMapping);
}
@Test
public void testGetPrefixes() throws Exception {
Set<String> existingPrefixes = mAppSearchImpl.getPrefixesLocked();
// Has database1
Set<String> expectedPrefixes = new ArraySet<>(existingPrefixes);
expectedPrefixes.add(createPrefix("package", "database1"));
mAppSearchImpl.setSchema(
"package",
"database1",
Collections.singletonList(new AppSearchSchema.Builder("schema").build()),
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
assertThat(mAppSearchImpl.getPrefixesLocked()).containsExactlyElementsIn(expectedPrefixes);
// Has both databases
expectedPrefixes.add(createPrefix("package", "database2"));
mAppSearchImpl.setSchema(
"package",
"database2",
Collections.singletonList(new AppSearchSchema.Builder("schema").build()),
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
assertThat(mAppSearchImpl.getPrefixesLocked()).containsExactlyElementsIn(expectedPrefixes);
}
@Test
public void testRewriteSearchResultProto() throws Exception {
final String prefix =
@@ -1665,7 +1689,6 @@ public class AppSearchImplTest {
mTemporaryFolder.newFolder(),
context,
VisibilityStore.NO_OP_USER_ID,
/*globalQuerierPackage=*/ "",
/*logger=*/ null);
// Initial check that we could do something at first.
@@ -1815,11 +1838,7 @@ public class AppSearchImplTest {
File appsearchDir = mTemporaryFolder.newFolder();
AppSearchImpl appSearchImpl =
AppSearchImpl.create(
appsearchDir,
context,
VisibilityStore.NO_OP_USER_ID,
/*globalQuerierPackage=*/ "",
/*logger=*/ null);
appsearchDir, context, VisibilityStore.NO_OP_USER_ID, /*logger=*/ null);
List<AppSearchSchema> schemas =
Collections.singletonList(new AppSearchSchema.Builder("type").build());
@@ -1846,11 +1865,7 @@ public class AppSearchImplTest {
// That document should be visible even from another instance.
AppSearchImpl appSearchImpl2 =
AppSearchImpl.create(
appsearchDir,
context,
VisibilityStore.NO_OP_USER_ID,
/*globalQuerierPackage=*/ "",
/*logger=*/ null);
appsearchDir, context, VisibilityStore.NO_OP_USER_ID, /*logger=*/ null);
getResult =
appSearchImpl2.getDocument(
"package", "database", "namespace1", "id1", Collections.emptyMap());
@@ -1864,11 +1879,7 @@ public class AppSearchImplTest {
File appsearchDir = mTemporaryFolder.newFolder();
AppSearchImpl appSearchImpl =
AppSearchImpl.create(
appsearchDir,
context,
VisibilityStore.NO_OP_USER_ID,
/*globalQuerierPackage=*/ "",
/*logger=*/ null);
appsearchDir, context, VisibilityStore.NO_OP_USER_ID, /*logger=*/ null);
List<AppSearchSchema> schemas =
Collections.singletonList(new AppSearchSchema.Builder("type").build());
@@ -1919,11 +1930,7 @@ public class AppSearchImplTest {
// Only the second document should be retrievable from another instance.
AppSearchImpl appSearchImpl2 =
AppSearchImpl.create(
appsearchDir,
context,
VisibilityStore.NO_OP_USER_ID,
/*globalQuerierPackage=*/ "",
/*logger=*/ null);
appsearchDir, context, VisibilityStore.NO_OP_USER_ID, /*logger=*/ null);
expectThrows(
AppSearchException.class,
() ->
@@ -1946,11 +1953,7 @@ public class AppSearchImplTest {
File appsearchDir = mTemporaryFolder.newFolder();
AppSearchImpl appSearchImpl =
AppSearchImpl.create(
appsearchDir,
context,
VisibilityStore.NO_OP_USER_ID,
/*globalQuerierPackage=*/ "",
/*logger=*/ null);
appsearchDir, context, VisibilityStore.NO_OP_USER_ID, /*logger=*/ null);
List<AppSearchSchema> schemas =
Collections.singletonList(new AppSearchSchema.Builder("type").build());
@@ -2009,11 +2012,7 @@ public class AppSearchImplTest {
// Only the second document should be retrievable from another instance.
AppSearchImpl appSearchImpl2 =
AppSearchImpl.create(
appsearchDir,
context,
VisibilityStore.NO_OP_USER_ID,
/*globalQuerierPackage=*/ "",
/*logger=*/ null);
appsearchDir, context, VisibilityStore.NO_OP_USER_ID, /*logger=*/ null);
expectThrows(
AppSearchException.class,
() ->

View File

@@ -40,6 +40,7 @@ import com.android.server.appsearch.proto.PutDocumentStatsProto;
import com.android.server.appsearch.proto.QueryStatsProto;
import com.android.server.appsearch.proto.ScoringSpecProto;
import com.android.server.appsearch.proto.TermMatchType;
import com.android.server.appsearch.visibilitystore.VisibilityStore;
import org.junit.Before;
import org.junit.Rule;
@@ -64,7 +65,6 @@ public class AppSearchLoggerTest {
mTemporaryFolder.newFolder(),
context,
VisibilityStore.NO_OP_USER_ID,
/*globalQuerierPackage=*/ context.getPackageName(),
/*logger=*/ null);
mLogger = new TestLogger();
}
@@ -293,7 +293,6 @@ public class AppSearchLoggerTest {
mTemporaryFolder.newFolder(),
context,
VisibilityStore.NO_OP_USER_ID,
/*globalQuerierPackage=*/ context.getPackageName(),
mLogger);
InitializeStats iStats = mLogger.mInitializeStats;