Guard system usage reporting by checking the caller has system access.

Adding this check in a testable way requires refactoring VisibilityStore
to pull it out of management by the AppSearchImpl object. It is now
initialized as a sibling of AppSearchImpl, managed by
AppSearchUserInstanceManager.

This has several benefits:
* Breaks the complicated initialization inter-dependency between
  AppSearchImpl and VisibilityStore
* Reduces duplicative singleton managers
* Allows AppSearchImpl to be tested more easily by accepting a
  "hasSystemSurfaceable" boolean that can be set in tests
* Reduces the number of times we have to call into VisStore; we can
  determine whether the caller has system access in advance instead of
  repeating the check for every schema type

Bug: 180058203
Bug: 183031844
Test: GlobalSearchSessionCtsTest#testReportSystemUsage_ForbiddenFromNonSystem
Test: GlobalSearchSessionPlatformCtsTest#testReportSystemUsage
Test: VisibilityStoreTest

Change-Id: I84c84819f287628ccf8af369f5481a8e90255f62
This commit is contained in:
Alexander Dorokhine
2021-06-18 10:48:58 -07:00
parent 5c86c0c10e
commit 9b26c3c9be
13 changed files with 810 additions and 956 deletions

View File

@@ -37,6 +37,7 @@ import android.app.appsearch.aidl.AppSearchResultParcel;
import android.app.appsearch.aidl.IAppSearchBatchResultCallback;
import android.app.appsearch.aidl.IAppSearchManager;
import android.app.appsearch.aidl.IAppSearchResultCallback;
import android.app.appsearch.exceptions.AppSearchException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -58,10 +59,7 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.server.LocalManagerRegistry;
import com.android.server.SystemService;
import com.android.server.appsearch.external.localstorage.AppSearchImpl;
import com.android.server.appsearch.external.localstorage.stats.CallStats;
import com.android.server.appsearch.stats.LoggerInstanceManager;
import com.android.server.appsearch.stats.PlatformLogger;
import com.android.server.appsearch.util.PackageUtil;
import com.android.server.appsearch.visibilitystore.VisibilityStore;
import com.android.server.usage.StorageStatsManagerLocal;
@@ -89,9 +87,8 @@ public class AppSearchManagerService extends SystemService {
private static final String TAG = "AppSearchManagerService";
private final Context mContext;
private PackageManager mPackageManager;
private ImplInstanceManager mImplInstanceManager;
private UserManager mUserManager;
private LoggerInstanceManager mLoggerInstanceManager;
private AppSearchUserInstanceManager mAppSearchUserInstanceManager;
// Never call shutdownNow(). It will cancel the futures it's returned. And since
// Executor#execute won't return anything, we will hang forever waiting for the execution.
@@ -116,9 +113,8 @@ public class AppSearchManagerService extends SystemService {
public void onStart() {
publishBinderService(Context.APP_SEARCH_SERVICE, new Stub());
mPackageManager = getContext().getPackageManager();
mImplInstanceManager = ImplInstanceManager.getInstance(mContext);
mAppSearchUserInstanceManager = AppSearchUserInstanceManager.getInstance();
mUserManager = mContext.getSystemService(UserManager.class);
mLoggerInstanceManager = LoggerInstanceManager.getInstance();
registerReceivers();
LocalManagerRegistry.getManager(StorageStatsManagerLocal.class)
.registerStorageStatsAugmenter(new AppSearchStorageStatsAugmenter(), TAG);
@@ -180,8 +176,7 @@ public class AppSearchManagerService extends SystemService {
*/
private void handleUserRemoved(@NonNull UserHandle userHandle) {
try {
mImplInstanceManager.closeAndRemoveAppSearchImplForUser(userHandle);
mLoggerInstanceManager.removePlatformLoggerForUser(userHandle);
mAppSearchUserInstanceManager.closeAndRemoveUserInstance(userHandle);
Log.i(TAG, "Removed AppSearchImpl instance for: " + userHandle);
} catch (Throwable t) {
Log.e(TAG, "Unable to remove data for: " + userHandle, t);
@@ -224,14 +219,13 @@ public class AppSearchManagerService extends SystemService {
return;
}
// Only clear the package's data if AppSearch exists for this user.
if (ImplInstanceManager.getAppSearchDir(userHandle).exists()) {
PlatformLogger logger = mLoggerInstanceManager.getOrCreatePlatformLogger(mContext,
userHandle, AppSearchConfig.getInstance(EXECUTOR));
AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(mContext,
userHandle, logger);
if (AppSearchUserInstanceManager.getAppSearchDir(userHandle).exists()) {
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getOrCreateUserInstance(
mContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
//TODO(b/145759910) clear visibility setting for package.
impl.clearPackageData(packageName);
logger.removeCachedUidForPackage(packageName);
instance.getAppSearchImpl().clearPackageData(packageName);
instance.getLogger().removeCachedUidForPackage(packageName);
}
} catch (Throwable t) {
Log.e(TAG, "Unable to remove data for package: " + packageName, t);
@@ -248,11 +242,10 @@ public class AppSearchManagerService extends SystemService {
EXECUTOR.execute(() -> {
try {
// Only clear the package's data if AppSearch exists for this user.
if (ImplInstanceManager.getAppSearchDir(userHandle).exists()) {
PlatformLogger logger = mLoggerInstanceManager.getOrCreatePlatformLogger(
mContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(mContext,
userHandle, logger);
if (AppSearchUserInstanceManager.getAppSearchDir(userHandle).exists()) {
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getOrCreateUserInstance(
mContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
List<PackageInfo> installedPackageInfos = mContext
.createContextAsUser(userHandle, /*flags=*/0)
.getPackageManager()
@@ -263,7 +256,7 @@ public class AppSearchManagerService extends SystemService {
}
packagesToKeep.add(VisibilityStore.PACKAGE_NAME);
//TODO(b/145759910) clear visibility setting for package.
impl.prunePackageData(packagesToKeep);
instance.getAppSearchImpl().prunePackageData(packagesToKeep);
}
} catch (Throwable t) {
Log.e(TAG, "Unable to prune packages for " + user, t);
@@ -279,7 +272,7 @@ public class AppSearchManagerService extends SystemService {
UserHandle userHandle = user.getUserHandle();
mUnlockedUsersLocked.remove(userHandle);
try {
mImplInstanceManager.closeAndRemoveAppSearchImplForUser(userHandle);
mAppSearchUserInstanceManager.closeAndRemoveUserInstance(userHandle);
} catch (Throwable t) {
Log.e(TAG, "Error handling user stopping.", t);
}
@@ -311,7 +304,7 @@ public class AppSearchManagerService extends SystemService {
@NonNull String databaseName,
@NonNull List<Bundle> schemaBundles,
@NonNull List<String> schemasNotDisplayedBySystem,
@NonNull Map<String, List<Bundle>> schemasPackageAccessibleBundles,
@NonNull Map<String, List<Bundle>> schemasVisibleToPackagesBundles,
boolean forceOverride,
int schemaVersion,
@NonNull UserHandle userHandle,
@@ -321,7 +314,7 @@ public class AppSearchManagerService extends SystemService {
Objects.requireNonNull(databaseName);
Objects.requireNonNull(schemaBundles);
Objects.requireNonNull(schemasNotDisplayedBySystem);
Objects.requireNonNull(schemasPackageAccessibleBundles);
Objects.requireNonNull(schemasVisibleToPackagesBundles);
Objects.requireNonNull(userHandle);
Objects.requireNonNull(callback);
@@ -330,7 +323,7 @@ public class AppSearchManagerService extends SystemService {
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
@AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
PlatformLogger logger = null;
AppSearchUserInstance instance = null;
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
@@ -341,9 +334,9 @@ public class AppSearchManagerService extends SystemService {
schemas.add(new AppSearchSchema(schemaBundles.get(i)));
}
Map<String, List<PackageIdentifier>> schemasPackageAccessible =
new ArrayMap<>(schemasPackageAccessibleBundles.size());
new ArrayMap<>(schemasVisibleToPackagesBundles.size());
for (Map.Entry<String, List<Bundle>> entry :
schemasPackageAccessibleBundles.entrySet()) {
schemasVisibleToPackagesBundles.entrySet()) {
List<PackageIdentifier> packageIdentifiers =
new ArrayList<>(entry.getValue().size());
for (int i = 0; i < entry.getValue().size(); i++) {
@@ -352,12 +345,12 @@ public class AppSearchManagerService extends SystemService {
}
schemasPackageAccessible.put(entry.getKey(), packageIdentifiers);
}
AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUser);
logger = mLoggerInstanceManager.getPlatformLogger(callingUser);
SetSchemaResponse setSchemaResponse = impl.setSchema(
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
SetSchemaResponse setSchemaResponse = instance.getAppSearchImpl().setSchema(
packageName,
databaseName,
schemas,
instance.getVisibilityStore(),
schemasNotDisplayedBySystem,
schemasPackageAccessible,
forceOverride,
@@ -370,12 +363,12 @@ public class AppSearchManagerService extends SystemService {
statusCode = throwableToFailedResult(t).getResultCode();
invokeCallbackOnError(callback, t);
} finally {
if (logger != null) {
if (instance != null) {
int estimatedBinderLatencyMillis =
2 * (int) (totalLatencyStartTimeMillis - binderCallStartTimeMillis);
int totalLatencyMillis =
(int) (SystemClock.elapsedRealtime() - totalLatencyStartTimeMillis);
logger.logStats(new CallStats.Builder()
instance.getLogger().logStats(new CallStats.Builder()
.setPackageName(packageName)
.setDatabase(databaseName)
.setStatusCode(statusCode)
@@ -410,8 +403,10 @@ public class AppSearchManagerService extends SystemService {
try {
verifyUserUnlocked(callingUser);
verifyCallingPackage(callingUser, callingUid, packageName);
AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUser);
GetSchemaResponse response = impl.getSchema(packageName, databaseName);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
GetSchemaResponse response =
instance.getAppSearchImpl().getSchema(packageName, databaseName);
invokeCallbackOnResult(
callback,
AppSearchResult.newSuccessfulResult(response.getBundle()));
@@ -438,10 +433,12 @@ public class AppSearchManagerService extends SystemService {
try {
verifyUserUnlocked(callingUser);
verifyCallingPackage(callingUser, callingUid, packageName);
AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUser);
List<String> namespaces = impl.getNamespaces(packageName, databaseName);
invokeCallbackOnResult(callback,
AppSearchResult.newSuccessfulResult(namespaces));
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
List<String> namespaces =
instance.getAppSearchImpl().getNamespaces(packageName, databaseName);
invokeCallbackOnResult(
callback, AppSearchResult.newSuccessfulResult(namespaces));
} catch (Throwable t) {
invokeCallbackOnError(callback, t);
}
@@ -467,7 +464,7 @@ public class AppSearchManagerService extends SystemService {
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
@AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
PlatformLogger logger = null;
AppSearchUserInstance instance = null;
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
@@ -475,17 +472,16 @@ public class AppSearchManagerService extends SystemService {
verifyCallingPackage(callingUser, callingUid, packageName);
AppSearchBatchResult.Builder<String, Void> resultBuilder =
new AppSearchBatchResult.Builder<>();
AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUser);
logger = mLoggerInstanceManager.getPlatformLogger(callingUser);
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
for (int i = 0; i < documentBundles.size(); i++) {
GenericDocument document = new GenericDocument(documentBundles.get(i));
try {
impl.putDocument(packageName, databaseName, document, logger);
resultBuilder.setSuccess(document.getId(), /*result=*/ null);
instance.getAppSearchImpl().putDocument(
packageName, databaseName, document, instance.getLogger());
resultBuilder.setSuccess(document.getId(), /*value=*/ null);
++operationSuccessCount;
} catch (Throwable t) {
resultBuilder.setResult(document.getId(),
throwableToFailedResult(t));
resultBuilder.setResult(document.getId(), throwableToFailedResult(t));
AppSearchResult<Void> result = throwableToFailedResult(t);
resultBuilder.setResult(document.getId(), result);
// Since we can only include one status code in the atom,
@@ -495,19 +491,19 @@ public class AppSearchManagerService extends SystemService {
}
}
// Now that the batch has been written. Persist the newly written data.
impl.persistToDisk(PersistType.Code.LITE);
instance.getAppSearchImpl().persistToDisk(PersistType.Code.LITE);
invokeCallbackOnResult(callback, resultBuilder.build());
} catch (Throwable t) {
++operationFailureCount;
statusCode = throwableToFailedResult(t).getResultCode();
invokeCallbackOnError(callback, t);
} finally {
if (logger != null) {
if (instance != null) {
int estimatedBinderLatencyMillis =
2 * (int) (totalLatencyStartTimeMillis - binderCallStartTimeMillis);
int totalLatencyMillis =
(int) (SystemClock.elapsedRealtime() - totalLatencyStartTimeMillis);
logger.logStats(new CallStats.Builder()
instance.getLogger().logStats(new CallStats.Builder()
.setPackageName(packageName)
.setDatabase(databaseName)
.setStatusCode(statusCode)
@@ -548,7 +544,7 @@ public class AppSearchManagerService extends SystemService {
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
@AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
PlatformLogger logger = null;
AppSearchUserInstance instance = null;
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
@@ -556,18 +552,16 @@ public class AppSearchManagerService extends SystemService {
verifyCallingPackage(callingUser, callingUid, packageName);
AppSearchBatchResult.Builder<String, Bundle> resultBuilder =
new AppSearchBatchResult.Builder<>();
AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUser);
logger = mLoggerInstanceManager.getPlatformLogger(callingUser);
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
for (int i = 0; i < ids.size(); i++) {
String id = ids.get(i);
try {
GenericDocument document =
impl.getDocument(
packageName,
databaseName,
namespace,
id,
typePropertyPaths);
GenericDocument document = instance.getAppSearchImpl().getDocument(
packageName,
databaseName,
namespace,
id,
typePropertyPaths);
++operationSuccessCount;
resultBuilder.setSuccess(id, document.getBundle());
} catch (Throwable t) {
@@ -585,12 +579,12 @@ public class AppSearchManagerService extends SystemService {
statusCode = throwableToFailedResult(t).getResultCode();
invokeCallbackOnError(callback, t);
} finally {
if (logger != null) {
if (instance != null) {
int estimatedBinderLatencyMillis =
2 * (int) (totalLatencyStartTimeMillis - binderCallStartTimeMillis);
int totalLatencyMillis =
(int) (SystemClock.elapsedRealtime() - totalLatencyStartTimeMillis);
logger.logStats(new CallStats.Builder()
instance.getLogger().logStats(new CallStats.Builder()
.setPackageName(packageName)
.setDatabase(databaseName)
.setStatusCode(statusCode)
@@ -629,21 +623,19 @@ public class AppSearchManagerService extends SystemService {
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
@AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
PlatformLogger logger = null;
AppSearchUserInstance instance = null;
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
verifyUserUnlocked(callingUser);
verifyCallingPackage(callingUser, callingUid, packageName);
AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUser);
logger = mLoggerInstanceManager.getPlatformLogger(callingUser);
SearchResultPage searchResultPage =
impl.query(
packageName,
databaseName,
queryExpression,
new SearchSpec(searchSpecBundle),
logger);
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
SearchResultPage searchResultPage = instance.getAppSearchImpl().query(
packageName,
databaseName,
queryExpression,
new SearchSpec(searchSpecBundle),
instance.getLogger());
++operationSuccessCount;
invokeCallbackOnResult(
callback,
@@ -653,12 +645,12 @@ public class AppSearchManagerService extends SystemService {
statusCode = throwableToFailedResult(t).getResultCode();
invokeCallbackOnError(callback, t);
} finally {
if (logger != null) {
if (instance != null) {
int estimatedBinderLatencyMillis =
2 * (int) (totalLatencyStartTimeMillis - binderCallStartTimeMillis);
int totalLatencyMillis =
(int) (SystemClock.elapsedRealtime() - totalLatencyStartTimeMillis);
logger.logStats(new CallStats.Builder()
instance.getLogger().logStats(new CallStats.Builder()
.setPackageName(packageName)
.setDatabase(databaseName)
.setStatusCode(statusCode)
@@ -695,21 +687,24 @@ public class AppSearchManagerService extends SystemService {
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
@AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
PlatformLogger logger = null;
AppSearchUserInstance instance = null;
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
verifyUserUnlocked(callingUser);
verifyCallingPackage(callingUser, callingUid, packageName);
logger = mLoggerInstanceManager.getPlatformLogger(callingUser);
AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUser);
SearchResultPage searchResultPage =
impl.globalQuery(
queryExpression,
new SearchSpec(searchSpecBundle),
packageName,
callingUid,
logger);
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
boolean callerHasSystemAccess =
instance.getVisibilityStore().doesCallerHaveSystemAccess(packageName);
SearchResultPage searchResultPage = instance.getAppSearchImpl().globalQuery(
queryExpression,
new SearchSpec(searchSpecBundle),
packageName,
instance.getVisibilityStore(),
callingUid,
callerHasSystemAccess,
instance.getLogger());
++operationSuccessCount;
invokeCallbackOnResult(
callback,
@@ -719,12 +714,12 @@ public class AppSearchManagerService extends SystemService {
statusCode = throwableToFailedResult(t).getResultCode();
invokeCallbackOnError(callback, t);
} finally {
if (logger != null) {
if (instance != null) {
int estimatedBinderLatencyMillis =
2 * (int) (totalLatencyStartTimeMillis - binderCallStartTimeMillis);
int totalLatencyMillis =
(int) (SystemClock.elapsedRealtime() - totalLatencyStartTimeMillis);
logger.logStats(new CallStats.Builder()
instance.getLogger().logStats(new CallStats.Builder()
.setPackageName(packageName)
.setStatusCode(statusCode)
.setTotalLatencyMillis(totalLatencyMillis)
@@ -756,8 +751,10 @@ public class AppSearchManagerService extends SystemService {
EXECUTOR.execute(() -> {
try {
verifyUserUnlocked(callingUser);
AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUser);
SearchResultPage searchResultPage = impl.getNextPage(nextPageToken);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
SearchResultPage searchResultPage =
instance.getAppSearchImpl().getNextPage(nextPageToken);
invokeCallbackOnResult(
callback,
AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
@@ -776,8 +773,9 @@ public class AppSearchManagerService extends SystemService {
EXECUTOR.execute(() -> {
try {
verifyUserUnlocked(callingUser);
AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUser);
impl.invalidateNextPageToken(nextPageToken);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
instance.getAppSearchImpl().invalidateNextPageToken(nextPageToken);
} catch (Throwable t) {
Log.e(TAG, "Unable to invalidate the query page token", t);
}
@@ -806,11 +804,12 @@ public class AppSearchManagerService extends SystemService {
EXECUTOR.execute(() -> {
try {
verifyCallingPackage(callingUser, callingUid, packageName);
AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUser);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
// we don't need to append the file. The file is always brand new.
try (DataOutputStream outputStream = new DataOutputStream(
new FileOutputStream(fileDescriptor.getFileDescriptor()))) {
SearchResultPage searchResultPage = impl.query(
SearchResultPage searchResultPage = instance.getAppSearchImpl().query(
packageName,
databaseName,
queryExpression,
@@ -822,7 +821,7 @@ public class AppSearchManagerService extends SystemService {
outputStream, searchResultPage.getResults().get(i)
.getGenericDocument().getBundle());
}
searchResultPage = impl.getNextPage(
searchResultPage = instance.getAppSearchImpl().getNextPage(
searchResultPage.getNextPageToken());
}
}
@@ -851,7 +850,8 @@ public class AppSearchManagerService extends SystemService {
EXECUTOR.execute(() -> {
try {
verifyCallingPackage(callingUser, callingUid, packageName);
AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUser);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
GenericDocument document;
ArrayList<Bundle> migrationFailureBundles = new ArrayList<>();
@@ -866,8 +866,8 @@ public class AppSearchManagerService extends SystemService {
break;
}
try {
impl.putDocument(packageName, databaseName, document,
/*logger=*/ null);
instance.getAppSearchImpl().putDocument(
packageName, databaseName, document, /*logger=*/ null);
} catch (Throwable t) {
migrationFailureBundles.add(new SetSchemaResponse.MigrationFailure(
document.getNamespace(),
@@ -878,7 +878,7 @@ public class AppSearchManagerService extends SystemService {
}
}
}
impl.persistToDisk(PersistType.Code.FULL);
instance.getAppSearchImpl().persistToDisk(PersistType.Code.FULL);
invokeCallbackOnResult(callback,
AppSearchResult.newSuccessfulResult(migrationFailureBundles));
} catch (Throwable t) {
@@ -909,17 +909,23 @@ public class AppSearchManagerService extends SystemService {
EXECUTOR.execute(() -> {
try {
verifyUserUnlocked(callingUser);
verifyCallingPackage(callingUser, callingUid, packageName);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
if (systemUsage) {
// TODO(b/183031844): Validate that the call comes from the system
if (systemUsage
&& !instance.getVisibilityStore()
.doesCallerHaveSystemAccess(packageName)) {
throw new AppSearchException(
AppSearchResult.RESULT_SECURITY_ERROR,
packageName + " does not have access to report system usage");
}
AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUser);
impl.reportUsage(
instance.getAppSearchImpl().reportUsage(
packageName, databaseName, namespace, documentId,
usageTimeMillis, systemUsage);
invokeCallbackOnResult(
callback, AppSearchResult.newSuccessfulResult(/*result=*/ null));
callback, AppSearchResult.newSuccessfulResult(/*value=*/ null));
} catch (Throwable t) {
invokeCallbackOnError(callback, t);
}
@@ -947,7 +953,7 @@ public class AppSearchManagerService extends SystemService {
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
@AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
PlatformLogger logger = null;
AppSearchUserInstance instance = null;
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
@@ -955,12 +961,11 @@ public class AppSearchManagerService extends SystemService {
verifyCallingPackage(callingUser, callingUid, packageName);
AppSearchBatchResult.Builder<String, Void> resultBuilder =
new AppSearchBatchResult.Builder<>();
AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUser);
logger = mLoggerInstanceManager.getPlatformLogger(callingUser);
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
for (int i = 0; i < ids.size(); i++) {
String id = ids.get(i);
try {
impl.remove(
instance.getAppSearchImpl().remove(
packageName,
databaseName,
namespace,
@@ -978,19 +983,19 @@ public class AppSearchManagerService extends SystemService {
}
}
// Now that the batch has been written. Persist the newly written data.
impl.persistToDisk(PersistType.Code.LITE);
instance.getAppSearchImpl().persistToDisk(PersistType.Code.LITE);
invokeCallbackOnResult(callback, resultBuilder.build());
} catch (Throwable t) {
++operationFailureCount;
statusCode = throwableToFailedResult(t).getResultCode();
invokeCallbackOnError(callback, t);
} finally {
if (logger != null) {
if (instance != null) {
int estimatedBinderLatencyMillis =
2 * (int) (totalLatencyStartTimeMillis - binderCallStartTimeMillis);
int totalLatencyMillis =
(int) (SystemClock.elapsedRealtime() - totalLatencyStartTimeMillis);
logger.logStats(new CallStats.Builder()
instance.getLogger().logStats(new CallStats.Builder()
.setPackageName(packageName)
.setDatabase(databaseName)
.setStatusCode(statusCode)
@@ -1030,22 +1035,21 @@ public class AppSearchManagerService extends SystemService {
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
@AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
PlatformLogger logger = null;
AppSearchUserInstance instance = null;
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
verifyUserUnlocked(callingUser);
verifyCallingPackage(callingUser, callingUid, packageName);
AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUser);
logger = mLoggerInstanceManager.getPlatformLogger(callingUser);
impl.removeByQuery(
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
instance.getAppSearchImpl().removeByQuery(
packageName,
databaseName,
queryExpression,
new SearchSpec(searchSpecBundle),
/*removeStatsBuilder=*/ null);
// Now that the batch has been written. Persist the newly written data.
impl.persistToDisk(PersistType.Code.LITE);
instance.getAppSearchImpl().persistToDisk(PersistType.Code.LITE);
++operationSuccessCount;
invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
} catch (Throwable t) {
@@ -1053,12 +1057,12 @@ public class AppSearchManagerService extends SystemService {
statusCode = throwableToFailedResult(t).getResultCode();
invokeCallbackOnError(callback, t);
} finally {
if (logger != null) {
if (instance != null) {
int estimatedBinderLatencyMillis =
2 * (int) (totalLatencyStartTimeMillis - binderCallStartTimeMillis);
int totalLatencyMillis =
(int) (SystemClock.elapsedRealtime() - totalLatencyStartTimeMillis);
logger.logStats(new CallStats.Builder()
instance.getLogger().logStats(new CallStats.Builder()
.setPackageName(packageName)
.setDatabase(databaseName)
.setStatusCode(statusCode)
@@ -1093,9 +1097,10 @@ public class AppSearchManagerService extends SystemService {
try {
verifyUserUnlocked(callingUser);
verifyCallingPackage(callingUser, callingUid, packageName);
AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUser);
StorageInfo storageInfo = impl.getStorageInfoForDatabase(packageName,
databaseName);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
StorageInfo storageInfo = instance.getAppSearchImpl()
.getStorageInfoForDatabase(packageName, databaseName);
Bundle storageInfoBundle = storageInfo.getBundle();
invokeCallbackOnResult(
callback, AppSearchResult.newSuccessfulResult(storageInfoBundle));
@@ -1116,26 +1121,25 @@ public class AppSearchManagerService extends SystemService {
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
@AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
PlatformLogger logger = null;
AppSearchUserInstance instance = null;
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
verifyUserUnlocked(callingUser);
AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUser);
logger = mLoggerInstanceManager.getPlatformLogger(callingUser);
impl.persistToDisk(PersistType.Code.FULL);
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
instance.getAppSearchImpl().persistToDisk(PersistType.Code.FULL);
++operationSuccessCount;
} catch (Throwable t) {
++operationFailureCount;
statusCode = throwableToFailedResult(t).getResultCode();
Log.e(TAG, "Unable to persist the data to disk", t);
} finally {
if (logger != null) {
if (instance != null) {
int estimatedBinderLatencyMillis =
2 * (int) (totalLatencyStartTimeMillis - binderCallStartTimeMillis);
int totalLatencyMillis =
(int) (SystemClock.elapsedRealtime() - totalLatencyStartTimeMillis);
logger.logStats(new CallStats.Builder()
instance.getLogger().logStats(new CallStats.Builder()
.setStatusCode(statusCode)
.setTotalLatencyMillis(totalLatencyMillis)
.setCallType(CallStats.CALL_TYPE_FLUSH)
@@ -1164,15 +1168,13 @@ public class AppSearchManagerService extends SystemService {
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
@AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
PlatformLogger logger = null;
AppSearchUserInstance instance = null;
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
verifyUserUnlocked(callingUser);
logger = mLoggerInstanceManager.getOrCreatePlatformLogger(
mContext, callingUser,
AppSearchConfig.getInstance(EXECUTOR));
mImplInstanceManager.getOrCreateAppSearchImpl(mContext, callingUser, logger);
instance = mAppSearchUserInstanceManager.getOrCreateUserInstance(
mContext, callingUser, AppSearchConfig.getInstance(EXECUTOR));
++operationSuccessCount;
invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
} catch (Throwable t) {
@@ -1180,12 +1182,12 @@ public class AppSearchManagerService extends SystemService {
statusCode = throwableToFailedResult(t).getResultCode();
invokeCallbackOnError(callback, t);
} finally {
if (logger != null) {
if (instance != null) {
int estimatedBinderLatencyMillis =
2 * (int) (totalLatencyStartTimeMillis - binderCallStartTimeMillis);
int totalLatencyMillis =
(int) (SystemClock.elapsedRealtime() - totalLatencyStartTimeMillis);
logger.logStats(new CallStats.Builder()
instance.getLogger().logStats(new CallStats.Builder()
.setStatusCode(statusCode)
.setTotalLatencyMillis(totalLatencyMillis)
.setCallType(CallStats.CALL_TYPE_INITIALIZE)
@@ -1329,12 +1331,11 @@ public class AppSearchManagerService extends SystemService {
try {
verifyUserUnlocked(userHandle);
PlatformLogger logger = mLoggerInstanceManager.getOrCreatePlatformLogger(
mContext, userHandle,
AppSearchConfig.getInstance(EXECUTOR));
AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(
mContext, userHandle, logger);
stats.dataSize += impl.getStorageInfoForPackage(packageName).getSizeBytes();
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getOrCreateUserInstance(
mContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
stats.dataSize += instance.getAppSearchImpl()
.getStorageInfoForPackage(packageName).getSizeBytes();
} catch (Throwable t) {
Log.e(
TAG,
@@ -1358,14 +1359,12 @@ public class AppSearchManagerService extends SystemService {
if (packagesForUid == null) {
return;
}
PlatformLogger logger = mLoggerInstanceManager.getOrCreatePlatformLogger(
mContext, userHandle,
AppSearchConfig.getInstance(EXECUTOR));
AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(
mContext, userHandle, logger);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getOrCreateUserInstance(
mContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
for (int i = 0; i < packagesForUid.length; i++) {
stats.dataSize +=
impl.getStorageInfoForPackage(packagesForUid[i]).getSizeBytes();
stats.dataSize += instance.getAppSearchImpl()
.getStorageInfoForPackage(packagesForUid[i]).getSizeBytes();
}
} catch (Throwable t) {
Log.e(TAG, "Unable to augment storage stats for uid " + uid, t);
@@ -1388,14 +1387,13 @@ public class AppSearchManagerService extends SystemService {
if (packagesForUser == null) {
return;
}
PlatformLogger logger = mLoggerInstanceManager.getOrCreatePlatformLogger(
mContext, userHandle,
AppSearchConfig.getInstance(EXECUTOR));
AppSearchImpl impl =
mImplInstanceManager.getOrCreateAppSearchImpl(mContext, userHandle, logger);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getOrCreateUserInstance(
mContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
for (int i = 0; i < packagesForUser.size(); i++) {
String packageName = packagesForUser.get(i).packageName;
stats.dataSize += impl.getStorageInfoForPackage(packageName).getSizeBytes();
stats.dataSize += instance.getAppSearchImpl()
.getStorageInfoForPackage(packageName).getSizeBytes();
}
} catch (Throwable t) {
Log.e(TAG, "Unable to augment storage stats for " + userHandle, t);

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 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;
import android.annotation.NonNull;
import com.android.server.appsearch.external.localstorage.AppSearchImpl;
import com.android.server.appsearch.stats.PlatformLogger;
import com.android.server.appsearch.visibilitystore.VisibilityStore;
import java.util.Objects;
/**
* Container for AppSearch classes that should only be initialized once per device-user and make up
* the core of the AppSearch system.
*/
public final class AppSearchUserInstance {
private final PlatformLogger mLogger;
private final AppSearchImpl mAppSearchImpl;
private final VisibilityStore mVisibilityStore;
AppSearchUserInstance(
@NonNull PlatformLogger logger,
@NonNull AppSearchImpl appSearchImpl,
@NonNull VisibilityStore visibilityStore) {
mLogger = Objects.requireNonNull(logger);
mAppSearchImpl = Objects.requireNonNull(appSearchImpl);
mVisibilityStore = Objects.requireNonNull(visibilityStore);
}
@NonNull
public PlatformLogger getLogger() {
return mLogger;
}
@NonNull
public AppSearchImpl getAppSearchImpl() {
return mAppSearchImpl;
}
@NonNull
public VisibilityStore getVisibilityStore() {
return mVisibilityStore;
}
}

View File

@@ -0,0 +1,195 @@
/*
* Copyright (C) 2019 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;
import android.annotation.NonNull;
import android.app.appsearch.exceptions.AppSearchException;
import android.content.Context;
import android.os.Environment;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.server.appsearch.external.localstorage.AppSearchImpl;
import com.android.server.appsearch.external.localstorage.FrameworkOptimizeStrategy;
import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
import com.android.server.appsearch.stats.PlatformLogger;
import com.android.server.appsearch.visibilitystore.VisibilityStore;
import java.io.File;
import java.util.Map;
import java.util.Objects;
/**
* Manages the lifecycle of AppSearch classes that should only be initialized once per device-user
* and make up the core of the AppSearch system.
*
* @hide
*/
public final class AppSearchUserInstanceManager {
private static final String TAG = "AppSearchUserInstanceMa";
private static volatile AppSearchUserInstanceManager sAppSearchUserInstanceManager;
@GuardedBy("mInstancesLocked")
private final Map<UserHandle, AppSearchUserInstance> mInstancesLocked = new ArrayMap<>();
private AppSearchUserInstanceManager() {}
/**
* Gets an instance of AppSearchUserInstanceManager to be used.
*
* <p>If no instance has been initialized yet, a new one will be created. Otherwise, the
* existing instance will be returned.
*/
@NonNull
public static AppSearchUserInstanceManager getInstance() {
if (sAppSearchUserInstanceManager == null) {
synchronized (AppSearchUserInstanceManager.class) {
if (sAppSearchUserInstanceManager == null) {
sAppSearchUserInstanceManager = new AppSearchUserInstanceManager();
}
}
}
return sAppSearchUserInstanceManager;
}
/**
* Returns AppSearch directory in the credential encrypted system directory for the given user.
*
* <p>This folder should only be accessed after unlock.
*/
public static File getAppSearchDir(@NonNull UserHandle userHandle) {
// Duplicates the implementation of Environment#getDataSystemCeDirectory
// TODO(b/191059409): Unhide Environment#getDataSystemCeDirectory and switch to it.
File systemCeDir = new File(Environment.getDataDirectory(), "system_ce");
File systemCeUserDir = new File(systemCeDir, String.valueOf(userHandle.getIdentifier()));
return new File(systemCeUserDir, "appsearch");
}
/**
* Gets an instance of AppSearchUserInstance for the given user, or creates one if none exists.
*
* <p>If no AppSearchUserInstance exists for the unlocked user, Icing will be initialized and
* one will be created.
*
* @param context The context
* @param userHandle The multi-user handle of the device user calling AppSearch
* @param config Flag manager for AppSearch
* @return An initialized {@link AppSearchUserInstance} for this user
*/
@NonNull
public AppSearchUserInstance getOrCreateUserInstance(
@NonNull Context context,
@NonNull UserHandle userHandle,
@NonNull AppSearchConfig config)
throws AppSearchException {
Objects.requireNonNull(context);
Objects.requireNonNull(userHandle);
Objects.requireNonNull(config);
synchronized (mInstancesLocked) {
AppSearchUserInstance instance = mInstancesLocked.get(userHandle);
if (instance == null) {
Context userContext = context.createContextAsUser(userHandle, /*flags=*/ 0);
instance = createUserInstance(userContext, userHandle, config);
mInstancesLocked.put(userHandle, instance);
}
return instance;
}
}
/**
* Closes and removes an {@link AppSearchUserInstance} for the given user.
*
* <p>All mutations applied to the underlying {@link AppSearchImpl} will be persisted to disk.
*
* @param userHandle The multi-user user handle of the user that need to be removed.
*/
public void closeAndRemoveUserInstance(@NonNull UserHandle userHandle) {
Objects.requireNonNull(userHandle);
synchronized (mInstancesLocked) {
AppSearchUserInstance instance = mInstancesLocked.remove(userHandle);
if (instance != null) {
instance.getAppSearchImpl().close();
}
}
}
/**
* Gets an {@link AppSearchUserInstance} for the given user.
*
* <p>This method should only be called by an initialized SearchSession, which has already
* called {@link #getOrCreateUserInstance} before.
*
* @param userHandle The multi-user handle of the device user calling AppSearch
* @return An initialized {@link AppSearchUserInstance} for this user
* @throws IllegalStateException if {@link AppSearchUserInstance} haven't created for the given
* user.
*/
@NonNull
public AppSearchUserInstance getUserInstance(@NonNull UserHandle userHandle) {
Objects.requireNonNull(userHandle);
synchronized (mInstancesLocked) {
AppSearchUserInstance instance = mInstancesLocked.get(userHandle);
if (instance == null) {
// Impossible scenario, user cannot call an uninitialized SearchSession,
// getInstance should always find the instance for the given user and never try to
// create an instance for this user again.
throw new IllegalStateException(
"AppSearchUserInstance has never been created for: " + userHandle);
}
return instance;
}
}
@NonNull
private AppSearchUserInstance createUserInstance(
@NonNull Context userContext,
@NonNull UserHandle userHandle,
@NonNull AppSearchConfig config)
throws AppSearchException {
long totalLatencyStartMillis = SystemClock.elapsedRealtime();
InitializeStats.Builder initStatsBuilder = new InitializeStats.Builder();
// Initialize the classes that make up AppSearchUserInstance
PlatformLogger logger = new PlatformLogger(userContext, userHandle, config);
File appSearchDir = getAppSearchDir(userHandle);
File icingDir = new File(appSearchDir, "icing");
Log.i(TAG, "Creating new AppSearch instance at: " + icingDir);
AppSearchImpl appSearchImpl =
AppSearchImpl.create(icingDir, initStatsBuilder, new FrameworkOptimizeStrategy());
long prepareVisibilityStoreLatencyStartMillis = SystemClock.elapsedRealtime();
VisibilityStore visibilityStore = VisibilityStore.create(appSearchImpl, userContext);
long prepareVisibilityStoreLatencyEndMillis = SystemClock.elapsedRealtime();
initStatsBuilder
.setTotalLatencyMillis(
(int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis))
.setPrepareVisibilityStoreLatencyMillis(
(int)
(prepareVisibilityStoreLatencyEndMillis
- prepareVisibilityStoreLatencyStartMillis));
logger.logStats(initStatsBuilder.build());
return new AppSearchUserInstance(logger, appSearchImpl, visibilityStore);
}
}

View File

@@ -1,170 +0,0 @@
/*
* Copyright (C) 2019 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;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.appsearch.exceptions.AppSearchException;
import android.content.Context;
import android.os.Environment;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.server.appsearch.external.localstorage.AppSearchImpl;
import com.android.server.appsearch.external.localstorage.AppSearchLogger;
import com.android.server.appsearch.external.localstorage.FrameworkOptimizeStrategy;
import java.io.File;
import java.util.Map;
import java.util.Objects;
/**
* Manages the lifecycle of instances of {@link AppSearchImpl}.
*
* <p>These instances are managed per unique device-user.
* @hide
*/
public final class ImplInstanceManager {
private static final String TAG = "AppSearchImplInstanceMa";
private static ImplInstanceManager sImplInstanceManager;
@GuardedBy("mInstancesLocked")
private final Map<UserHandle, AppSearchImpl> mInstancesLocked = new ArrayMap<>();
/**
* Gets an instance of ImplInstanceManager to be used.
*
* <p>If no instance has been initialized yet, a new one will be created. Otherwise, the
* existing instance will be returned.
*/
@NonNull
public static ImplInstanceManager getInstance(@NonNull Context context) {
if (sImplInstanceManager == null) {
synchronized (ImplInstanceManager.class) {
if (sImplInstanceManager == null) {
sImplInstanceManager = new ImplInstanceManager();
}
}
}
return sImplInstanceManager;
}
/**
* Returns AppSearch directory in the credential encrypted system directory for the given user.
*
* <p>This folder should only be accessed after unlock.
*/
public static File getAppSearchDir(@NonNull UserHandle userHandle) {
// Duplicates the implementation of Environment#getDataSystemCeDirectory
// TODO(b/191059409): Unhide Environment#getDataSystemCeDirectory and switch to it.
File systemCeDir = new File(Environment.getDataDirectory(), "system_ce");
File systemCeUserDir = new File(systemCeDir, String.valueOf(userHandle.getIdentifier()));
return new File(systemCeUserDir, "appSearch");
}
/**
* Gets an instance of AppSearchImpl for the given user, or creates one if none exists.
*
* <p>If no AppSearchImpl instance exists for the unlocked user, Icing will be initialized and
* one will be created.
*
* @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
*/
@NonNull
public AppSearchImpl getOrCreateAppSearchImpl(
@NonNull Context context,
@NonNull UserHandle userHandle,
@Nullable AppSearchLogger logger) throws AppSearchException {
Objects.requireNonNull(context);
Objects.requireNonNull(userHandle);
synchronized (mInstancesLocked) {
AppSearchImpl instance = mInstancesLocked.get(userHandle);
if (instance == null) {
Context userContext = context.createContextAsUser(userHandle, /*flags=*/ 0);
instance = createImpl(userContext, userHandle, logger);
mInstancesLocked.put(userHandle, instance);
}
return instance;
}
}
/**
* Close and remove an instance of {@link AppSearchImpl} for the given user.
*
* <p>All mutation apply to this {@link AppSearchImpl} will be persisted to disk.
*
* @param userHandle The multi-user user handle of the user that need to be removed.
*/
public void closeAndRemoveAppSearchImplForUser(@NonNull UserHandle userHandle) {
Objects.requireNonNull(userHandle);
synchronized (mInstancesLocked) {
AppSearchImpl appSearchImpl = mInstancesLocked.get(userHandle);
if (appSearchImpl != null) {
appSearchImpl.close();
mInstancesLocked.remove(userHandle);
}
}
}
/**
* Gets an instance of AppSearchImpl for the given user.
*
* <p>This method should only be called by an initialized SearchSession, which has been already
* created the AppSearchImpl instance for the given user.
*
* @param userHandle The multi-user handle of the device user calling AppSearch
* @return An initialized {@link AppSearchImpl} for this user
* @throws IllegalStateException if {@link AppSearchImpl} haven't created for the given user.
*/
@NonNull
public AppSearchImpl getAppSearchImpl(@NonNull UserHandle userHandle) {
Objects.requireNonNull(userHandle);
synchronized (mInstancesLocked) {
AppSearchImpl instance = mInstancesLocked.get(userHandle);
if (instance == null) {
// Impossible scenario, user cannot call an uninitialized SearchSession,
// getInstance should always find the instance for the given user and never try to
// create an instance for this user again.
throw new IllegalStateException(
"AppSearchImpl has never been created for: " + userHandle);
}
return instance;
}
}
private AppSearchImpl createImpl(
@NonNull Context userContext,
@NonNull UserHandle userHandle,
@Nullable AppSearchLogger logger)
throws AppSearchException {
File appSearchDir = getAppSearchDir(userHandle);
File icingDir = new File(appSearchDir, "icing");
Log.i(TAG, "Creating new AppSearch instance at: " + icingDir);
return AppSearchImpl.create(
icingDir,
userContext,
/*logger=*/ null,
new FrameworkOptimizeStrategy());
}
}

View File

@@ -39,7 +39,6 @@ import android.app.appsearch.SetSchemaResponse;
import android.app.appsearch.StorageInfo;
import android.app.appsearch.exceptions.AppSearchException;
import android.app.appsearch.util.LogUtil;
import android.content.Context;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.ArrayMap;
@@ -157,9 +156,6 @@ public final class AppSearchImpl implements Closeable {
@VisibleForTesting
final IcingSearchEngine mIcingSearchEngineLocked;
@GuardedBy("mReadWriteLock")
private final VisibilityStore mVisibilityStoreLocked;
// This map contains schema types and SchemaTypeConfigProtos for all package-database
// prefixes. It maps each package-database prefix to an inner-map. The inner-map maps each
// prefixed schema type to its respective SchemaTypeConfigProto.
@@ -195,56 +191,27 @@ public final class AppSearchImpl implements Closeable {
* <p>Instead, logger instance needs to be passed to each individual method, like create, query
* and putDocument.
*
* @param logger collects stats for initialization if provided.
* @param initStatsBuilder collects stats for initialization if provided.
*/
@NonNull
public static AppSearchImpl create(
@NonNull File icingDir,
@NonNull Context userContext,
@Nullable AppSearchLogger logger,
@Nullable InitializeStats.Builder initStatsBuilder,
@NonNull OptimizeStrategy optimizeStrategy)
throws AppSearchException {
Objects.requireNonNull(icingDir);
Objects.requireNonNull(userContext);
Objects.requireNonNull(optimizeStrategy);
long totalLatencyStartMillis = SystemClock.elapsedRealtime();
InitializeStats.Builder initStatsBuilder = null;
if (logger != null) {
initStatsBuilder = new InitializeStats.Builder();
}
AppSearchImpl appSearchImpl =
new AppSearchImpl(
icingDir, userContext, initStatsBuilder, optimizeStrategy);
long prepareVisibilityStoreLatencyStartMillis = SystemClock.elapsedRealtime();
appSearchImpl.initializeVisibilityStore();
long prepareVisibilityStoreLatencyEndMillis = SystemClock.elapsedRealtime();
if (logger != null) {
initStatsBuilder
.setTotalLatencyMillis(
(int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis))
.setPrepareVisibilityStoreLatencyMillis(
(int)
(prepareVisibilityStoreLatencyEndMillis
- prepareVisibilityStoreLatencyStartMillis));
logger.logStats(initStatsBuilder.build());
}
return appSearchImpl;
return new AppSearchImpl(icingDir, initStatsBuilder, optimizeStrategy);
}
/** @param initStatsBuilder collects stats for initialization if provided. */
private AppSearchImpl(
@NonNull File icingDir,
@NonNull Context userContext,
@Nullable InitializeStats.Builder initStatsBuilder,
@NonNull OptimizeStrategy optimizeStrategy)
throws AppSearchException {
mReadWriteLock.writeLock().lock();
Objects.requireNonNull(icingDir);
mOptimizeStrategy = Objects.requireNonNull(optimizeStrategy);
mReadWriteLock.writeLock().lock();
try {
// We synchronize here because we don't want to call IcingSearchEngine.initialize() more
// than once. It's unnecessary and can be a costly operation.
@@ -258,9 +225,6 @@ public final class AppSearchImpl implements Closeable {
"Constructing IcingSearchEngine, response",
Objects.hashCode(mIcingSearchEngineLocked));
mVisibilityStoreLocked = new VisibilityStore(this, userContext);
mOptimizeStrategy = optimizeStrategy;
// The core initialization procedure. If any part of this fails, we bail into
// resetLocked(), deleting all data (but hopefully allowing AppSearchImpl to come up).
try {
@@ -342,23 +306,6 @@ public final class AppSearchImpl implements Closeable {
}
}
/**
* Initialize the visibility store in AppSearchImpl.
*
* @throws AppSearchException on IcingSearchEngine error.
*/
void initializeVisibilityStore() throws AppSearchException {
mReadWriteLock.writeLock().lock();
try {
throwIfClosedLocked();
mLogUtil.piiTrace("Initializing VisibilityStore, request");
mVisibilityStoreLocked.initialize();
mLogUtil.piiTrace("Initializing VisibilityStore, response");
} finally {
mReadWriteLock.writeLock().unlock();
}
}
@GuardedBy("mReadWriteLock")
private void throwIfClosedLocked() {
if (mClosedLocked) {
@@ -399,6 +346,8 @@ public final class AppSearchImpl implements Closeable {
* @param packageName The package name that owns the schemas.
* @param databaseName The name of the database where this schema lives.
* @param schemas Schemas to set for this app.
* @param visibilityStore If set, {@code schemasNotPlatformSurfaceable} and {@code
* schemasPackageAccessible} will be saved here if the schema is successfully applied.
* @param schemasNotPlatformSurfaceable Schema types that should not be surfaced on platform
* surfaces.
* @param schemasPackageAccessible Schema types that are visible to the specified packages.
@@ -416,6 +365,7 @@ public final class AppSearchImpl implements Closeable {
@NonNull String packageName,
@NonNull String databaseName,
@NonNull List<AppSearchSchema> schemas,
@Nullable VisibilityStore visibilityStore,
@NonNull List<String> schemasNotPlatformSurfaceable,
@NonNull Map<String, List<PackageIdentifier>> schemasPackageAccessible,
boolean forceOverride,
@@ -479,25 +429,27 @@ public final class AppSearchImpl implements Closeable {
removeFromMap(mSchemaMapLocked, prefix, schemaType);
}
Set<String> prefixedSchemasNotPlatformSurfaceable =
new ArraySet<>(schemasNotPlatformSurfaceable.size());
for (int i = 0; i < schemasNotPlatformSurfaceable.size(); i++) {
prefixedSchemasNotPlatformSurfaceable.add(
prefix + schemasNotPlatformSurfaceable.get(i));
}
if (visibilityStore != null) {
Set<String> prefixedSchemasNotPlatformSurfaceable =
new ArraySet<>(schemasNotPlatformSurfaceable.size());
for (int i = 0; i < schemasNotPlatformSurfaceable.size(); i++) {
prefixedSchemasNotPlatformSurfaceable.add(
prefix + schemasNotPlatformSurfaceable.get(i));
}
Map<String, List<PackageIdentifier>> prefixedSchemasPackageAccessible =
new ArrayMap<>(schemasPackageAccessible.size());
for (Map.Entry<String, List<PackageIdentifier>> entry :
schemasPackageAccessible.entrySet()) {
prefixedSchemasPackageAccessible.put(prefix + entry.getKey(), entry.getValue());
}
Map<String, List<PackageIdentifier>> prefixedSchemasPackageAccessible =
new ArrayMap<>(schemasPackageAccessible.size());
for (Map.Entry<String, List<PackageIdentifier>> entry :
schemasPackageAccessible.entrySet()) {
prefixedSchemasPackageAccessible.put(prefix + entry.getKey(), entry.getValue());
}
mVisibilityStoreLocked.setVisibility(
packageName,
databaseName,
prefixedSchemasNotPlatformSurfaceable,
prefixedSchemasPackageAccessible);
visibilityStore.setVisibility(
packageName,
databaseName,
prefixedSchemasNotPlatformSurfaceable,
prefixedSchemasPackageAccessible);
}
return SetSchemaResponseToProtoConverter.toSetSchemaResponse(
setSchemaResultProto, prefix);
@@ -817,7 +769,11 @@ public final class AppSearchImpl implements Closeable {
* @param searchSpec Spec for setting filters, raw query etc.
* @param callerPackageName Package name of the caller, should belong to the {@code
* userContext}.
* @param visibilityStore Optional visibility store to obtain system and package visibility
* settings from
* @param callerUid UID of the client making the globalQuery call.
* @param callerHasSystemAccess Whether the caller has been positively identified as having
* access to schemas marked system surfaceable.
* @param logger logger to collect globalQuery stats
* @return The results of performing this search. It may contain an empty list of results if no
* documents matched the query.
@@ -828,7 +784,9 @@ public final class AppSearchImpl implements Closeable {
@NonNull String queryExpression,
@NonNull SearchSpec searchSpec,
@NonNull String callerPackageName,
@Nullable VisibilityStore visibilityStore,
int callerUid,
boolean callerHasSystemAccess,
@Nullable AppSearchLogger logger)
throws AppSearchException {
long totalLatencyStartMillis = SystemClock.elapsedRealtime();
@@ -885,15 +843,18 @@ public final class AppSearchImpl implements Closeable {
if (packageName.equals(callerPackageName)) {
// Callers can always retrieve their own data
allow = true;
} else if (visibilityStore == null) {
// If there's no visibility store, there's no extra access
allow = false;
} else {
String databaseName = getDatabaseName(prefixedSchema);
allow =
mVisibilityStoreLocked.isSchemaSearchableByCaller(
visibilityStore.isSchemaSearchableByCaller(
packageName,
databaseName,
prefixedSchema,
callerPackageName,
callerUid);
callerUid,
callerHasSystemAccess);
}
if (!allow) {
@@ -1488,9 +1449,6 @@ public final class AppSearchImpl implements Closeable {
/**
* Clears documents and schema across all packages and databaseNames.
*
* <p>This method also clear all data in {@link VisibilityStore}, an {@link
* #initializeVisibilityStore()} must be called after this.
*
* <p>This method belongs to mutate group.
*
* @throws AppSearchException on IcingSearchEngine error.
@@ -1514,9 +1472,6 @@ public final class AppSearchImpl implements Closeable {
.setResetStatusCode(statusProtoToResultCode(resetResultProto.getStatus()));
}
// Must be called after everything else since VisibilityStore may repopulate
// IcingSearchEngine with an initial schema.
mVisibilityStoreLocked.handleReset();
checkSuccess(resetResultProto.getStatus());
}
@@ -2075,13 +2030,6 @@ public final class AppSearchImpl implements Closeable {
return result;
}
@GuardedBy("mReadWriteLock")
@NonNull
@VisibleForTesting
VisibilityStore getVisibilityStoreLocked() {
return mVisibilityStoreLocked;
}
/**
* Converts an erroneous status code from the Icing status enums to the AppSearchResult enums.
*

View File

@@ -1,126 +0,0 @@
/*
* Copyright (C) 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.stats;
import android.annotation.NonNull;
import android.content.Context;
import android.os.UserHandle;
import android.util.ArrayMap;
import com.android.internal.annotations.GuardedBy;
import com.android.server.appsearch.AppSearchConfig;
import com.android.server.appsearch.AppSearchManagerService;
import java.util.Map;
import java.util.Objects;
/**
* Manages the lifecycle of instances of {@link PlatformLogger}.
*
* <p>These instances are managed per unique device-user.
*/
public final class LoggerInstanceManager {
private static volatile LoggerInstanceManager sLoggerInstanceManager;
@GuardedBy("mInstancesLocked")
private final Map<UserHandle, PlatformLogger> mInstancesLocked = new ArrayMap<>();
private LoggerInstanceManager() {
}
/**
* Gets an instance of {@link LoggerInstanceManager} to be used.
*
* <p>If no instance has been initialized yet, a new one will be created. Otherwise, the
* existing instance will be returned.
*/
@NonNull
public static LoggerInstanceManager getInstance() {
if (sLoggerInstanceManager == null) {
synchronized (LoggerInstanceManager.class) {
if (sLoggerInstanceManager == null) {
sLoggerInstanceManager =
new LoggerInstanceManager();
}
}
}
return sLoggerInstanceManager;
}
/**
* Gets an instance of PlatformLogger for the given user, or creates one if none exists.
*
* @param context The context
* @param userHandle The multi-user handle of the device user calling AppSearch
* @return An initialized {@link PlatformLogger} for this user
*/
@NonNull
public PlatformLogger getOrCreatePlatformLogger(
@NonNull Context context, @NonNull UserHandle userHandle,
@NonNull AppSearchConfig config) {
Objects.requireNonNull(userHandle);
synchronized (mInstancesLocked) {
PlatformLogger instance = mInstancesLocked.get(userHandle);
if (instance == null) {
instance = new PlatformLogger(context, userHandle, config);
mInstancesLocked.put(userHandle, instance);
}
return instance;
}
}
/**
* Gets an instance of PlatformLogger for the given user.
*
* <p>This method should only be called by an initialized SearchSession, which has been already
* created the PlatformLogger instance for the given user.
*
* @param userHandle The multi-user handle of the device user calling AppSearch
* @return An initialized {@link PlatformLogger} for this user
* @throws IllegalStateException if {@link PlatformLogger} haven't created for the given user.
*/
@NonNull
public PlatformLogger getPlatformLogger(@NonNull UserHandle userHandle) {
Objects.requireNonNull(userHandle);
synchronized (mInstancesLocked) {
PlatformLogger instance = mInstancesLocked.get(userHandle);
if (instance == null) {
// Impossible scenario, user cannot call an uninitialized SearchSession,
// getInstance should always find the instance for the given user and never try to
// create an instance for this user again.
throw new IllegalStateException(
"PlatformLogger has never been created for: " + userHandle);
}
return instance;
}
}
/**
* Remove an instance of {@link PlatformLogger} for the given user.
*
* <p>This method should only be called if {@link AppSearchManagerService} receives an
* ACTION_USER_REMOVED, which the logger instance of given user should be removed.
*
* @param userHandle The multi-user handle of the user that need to be removed.
*/
public void removePlatformLoggerForUser(@NonNull UserHandle userHandle) {
Objects.requireNonNull(userHandle);
synchronized (mInstancesLocked) {
mInstancesLocked.remove(userHandle);
}
}
}

View File

@@ -73,9 +73,4 @@ class NotPlatformSurfaceableMap {
// isn't one of those opt-outs, it's surfaceable.
return !schemaTypes.contains(prefixedSchema);
}
/** Discards all data in the map. */
public void clear() {
mMap.clear();
}
}

View File

@@ -82,9 +82,4 @@ class PackageAccessibleMap {
}
return accessiblePackages;
}
/** Discards all data in the map. */
public void clear() {
mMap.clear();
}
}

View File

@@ -99,28 +99,23 @@ public class VisibilityStore {
private final PackageAccessibleMap mPackageAccessibleMap = new PackageAccessibleMap();
/**
* Creates an uninitialized VisibilityStore object. Callers must also call {@link #initialize()}
* before using the object.
* Creates and initializes VisibilityStore.
*
* @param appSearchImpl AppSearchImpl instance
* @param userContext Context of the user that the call is being made as
*/
public VisibilityStore(@NonNull AppSearchImpl appSearchImpl, @NonNull Context userContext) {
mAppSearchImpl = Objects.requireNonNull(appSearchImpl);
mUserContext = Objects.requireNonNull(userContext);
@NonNull
public static VisibilityStore create(
@NonNull AppSearchImpl appSearchImpl, @NonNull Context userContext)
throws AppSearchException {
return new VisibilityStore(appSearchImpl, userContext);
}
/**
* Initializes schemas and member variables to track visibility settings.
*
* <p>This is kept separate from the constructor because this will call methods on
* AppSearchImpl. Some may even then recursively call back into VisibilityStore (for example,
* {@link AppSearchImpl#setSchema} will call {@link #setVisibility}. We need to have both
* AppSearchImpl and VisibilityStore fully initialized for this call flow to work.
*
* @throws AppSearchException AppSearchException on AppSearchImpl error.
*/
public void initialize() throws AppSearchException {
private VisibilityStore(@NonNull AppSearchImpl appSearchImpl, @NonNull Context userContext)
throws AppSearchException {
mAppSearchImpl = Objects.requireNonNull(appSearchImpl);
mUserContext = Objects.requireNonNull(userContext);
GetSchemaResponse getSchemaResponse = mAppSearchImpl.getSchema(PACKAGE_NAME, DATABASE_NAME);
boolean hasVisibilityType = false;
boolean hasPackageAccessibleType = false;
@@ -142,6 +137,7 @@ public class VisibilityStore {
PACKAGE_NAME,
DATABASE_NAME,
Arrays.asList(VisibilityDocument.SCHEMA, PackageAccessibleDocument.SCHEMA),
/*visibilityStore=*/ null, // Avoid recursive calls
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -149,7 +145,6 @@ public class VisibilityStore {
}
// Populate visibility settings set
mNotPlatformSurfaceableMap.clear();
for (Map.Entry<String, Set<String>> entry :
mAppSearchImpl.getPackageToDatabases().entrySet()) {
String packageName = entry.getKey();
@@ -280,39 +275,46 @@ public class VisibilityStore {
packageName, databaseName, schemaToPackageIdentifierMap);
}
/**
* Checks whether the given package has access to system-surfaceable schemas.
*
* @param callerPackageName Package name of the caller.
*/
public boolean doesCallerHaveSystemAccess(@NonNull String callerPackageName) {
Objects.requireNonNull(callerPackageName);
return mUserContext.getPackageManager()
.checkPermission(READ_GLOBAL_APP_SEARCH_DATA, callerPackageName)
== PackageManager.PERMISSION_GRANTED;
}
/**
* 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.
* @param callerUid UID of the client making the globalQuery call.
* @param callerHasSystemAccess Whether the caller has been identified as having
* access to schemas marked system surfaceable by {@link
* #doesCallerHaveSystemAccess}.
*/
public boolean isSchemaSearchableByCaller(
@NonNull String packageName,
@NonNull String databaseName,
@NonNull String prefixedSchema,
@NonNull String callerPackageName,
int callerUid) {
int callerUid,
boolean callerHasSystemAccess) {
Objects.requireNonNull(packageName);
Objects.requireNonNull(databaseName);
Objects.requireNonNull(prefixedSchema);
Objects.requireNonNull(callerPackageName);
if (packageName.equals(PACKAGE_NAME)) {
return false; // VisibilityStore schemas are for internal bookkeeping.
}
// 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) {
if (callerHasSystemAccess
&& mNotPlatformSurfaceableMap.isSchemaPlatformSurfaceable(
packageName, databaseName, prefixedSchema)) {
return true;
}
@@ -372,16 +374,6 @@ public class VisibilityStore {
return false;
}
/**
* Handles an {@code AppSearchImpl#reset()} by clearing any cached state.
*
* <p>{@link #initialize()} must be called after this.
*/
public void handleReset() {
mNotPlatformSurfaceableMap.clear();
mPackageAccessibleMap.clear();
}
/**
* Adds a prefix to create a visibility store document's id.
*

View File

@@ -42,6 +42,7 @@ import androidx.test.core.app.ApplicationProvider;
import com.android.compatibility.common.util.SystemUtil;
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;
@@ -66,6 +67,7 @@ public class AppSearchImplPlatformTest {
private final Map<UserHandle, PackageManager> mMockPackageManagers = new ArrayMap<>();
private Context mContext;
private AppSearchImpl mAppSearchImpl;
private VisibilityStore mVisibilityStore;
private int mGlobalQuerierUid;
@Before
@@ -89,13 +91,9 @@ public class AppSearchImplPlatformTest {
};
// Give ourselves global query permissions
mAppSearchImpl =
AppSearchImpl.create(
mTemporaryFolder.newFolder(),
mContext,
/*logger=*/ null,
ALWAYS_OPTIMIZE);
mAppSearchImpl = AppSearchImpl.create(
mTemporaryFolder.newFolder(), /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
mVisibilityStore = VisibilityStore.create(mAppSearchImpl, mContext);
mGlobalQuerierUid =
mContext.getPackageManager().getPackageUid(mContext.getPackageName(), /*flags=*/ 0);
}
@@ -128,6 +126,7 @@ public class AppSearchImplPlatformTest {
"package",
"database",
Collections.singletonList(new AppSearchSchema.Builder("schema1").build()),
mVisibilityStore,
/*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"),
/*schemasPackageAccessible=*/ ImmutableMap.of(
"schema1",
@@ -136,26 +135,20 @@ public class AppSearchImplPlatformTest {
/*schemaVersion=*/ 0);
// "schema1" is platform hidden now and package visible to package1
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
mContext.getPackageName(),
mGlobalQuerierUid))
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
mGlobalQuerierUid,
/*callerHasSystemAccess=*/ true))
.isFalse();
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
packageNameFoo,
uidFoo))
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
uidFoo,
/*callerHasSystemAccess=*/ false))
.isTrue();
// Add a new schema, and include the already-existing "schema1"
@@ -165,6 +158,7 @@ public class AppSearchImplPlatformTest {
ImmutableList.of(
new AppSearchSchema.Builder("schema1").build(),
new AppSearchSchema.Builder("schema2").build()),
mVisibilityStore,
/*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"),
/*schemasPackageAccessible=*/ ImmutableMap.of(
"schema1",
@@ -174,50 +168,40 @@ public class AppSearchImplPlatformTest {
// Check that "schema1" still has the same visibility settings
SystemUtil.runWithShellPermissionIdentity(() -> assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
mContext.getPackageName(),
mGlobalQuerierUid))
mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
mGlobalQuerierUid,
/*callerHasSystemAccess=*/ true))
.isFalse(),
READ_GLOBAL_APP_SEARCH_DATA);
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
packageNameFoo,
uidFoo))
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
uidFoo,
/*callerHasSystemAccess=*/ false))
.isTrue();
// "schema2" has default visibility settings
SystemUtil.runWithShellPermissionIdentity(() -> assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema2",
mContext.getPackageName(),
mGlobalQuerierUid))
mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema2",
mGlobalQuerierUid,
/*callerHasSystemAccess=*/ true))
.isTrue(),
READ_GLOBAL_APP_SEARCH_DATA);
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema2",
packageNameFoo,
uidFoo))
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema2",
uidFoo,
/*callerHasSystemAccess=*/ false))
.isFalse();
}
@@ -248,6 +232,7 @@ public class AppSearchImplPlatformTest {
"package",
"database",
Collections.singletonList(new AppSearchSchema.Builder("schema1").build()),
mVisibilityStore,
/*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"),
/*schemasPackageAccessible=*/ ImmutableMap.of(
"schema1",
@@ -256,26 +241,20 @@ public class AppSearchImplPlatformTest {
/*schemaVersion=*/ 0);
// "schema1" is platform hidden now and package accessible
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
mContext.getPackageName(),
mGlobalQuerierUid))
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
mGlobalQuerierUid,
/*callerHasSystemAccess=*/ true))
.isFalse();
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
packageNameFoo,
uidFoo))
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
uidFoo,
/*callerHasSystemAccess=*/ false))
.isTrue();
// Remove "schema1" by force overriding
@@ -283,32 +262,27 @@ public class AppSearchImplPlatformTest {
"package",
"database",
/*schemas=*/ Collections.emptyList(),
mVisibilityStore,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ true,
/*schemaVersion=*/ 0);
// Check that "schema1" is no longer considered platform hidden or package accessible
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
mContext.getPackageName(),
mGlobalQuerierUid))
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
mGlobalQuerierUid,
/*callerHasSystemAccess=*/ true))
.isTrue();
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
packageNameFoo,
uidFoo))
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
uidFoo,
/*callerHasSystemAccess=*/ false))
.isFalse();
// Add "schema1" back, it gets default visibility settings which means it's not platform
@@ -317,30 +291,25 @@ public class AppSearchImplPlatformTest {
"package",
"database",
Collections.singletonList(new AppSearchSchema.Builder("schema1").build()),
mVisibilityStore,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*schemaVersion=*/ 0);
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
mContext.getPackageName(),
mGlobalQuerierUid))
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
mGlobalQuerierUid,
/*callerHasSystemAccess=*/ true))
.isTrue();
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
packageNameFoo,
uidFoo))
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
prefix + "schema1",
uidFoo,
/*callerHasSystemAccess=*/ false))
.isFalse();
}
@@ -357,20 +326,18 @@ public class AppSearchImplPlatformTest {
"package",
"database",
Collections.singletonList(new AppSearchSchema.Builder("Schema").build()),
mVisibilityStore,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*schemaVersion=*/ 0);
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "Schema",
mContext.getPackageName(),
mGlobalQuerierUid))
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
prefix + "Schema",
mGlobalQuerierUid,
/*callerHasSystemAccess=*/ true))
.isTrue();
}
@@ -387,20 +354,18 @@ public class AppSearchImplPlatformTest {
"package",
"database",
Collections.singletonList(new AppSearchSchema.Builder("Schema").build()),
mVisibilityStore,
/*schemasNotPlatformSurfaceable=*/ Collections.singletonList("Schema"),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*schemaVersion=*/ 0);
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "Schema",
mContext.getPackageName(),
mGlobalQuerierUid))
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
prefix + "Schema",
mGlobalQuerierUid,
/*callerHasSystemAccess=*/ true))
.isFalse();
}
@@ -418,19 +383,18 @@ public class AppSearchImplPlatformTest {
"package",
"database",
Collections.singletonList(new AppSearchSchema.Builder("Schema").build()),
mVisibilityStore,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*schemaVersion=*/ 0);
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
assertThat(mVisibilityStore
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "Schema",
packageName,
/*callerUid=*/ 42))
/*callerUid=*/ 42,
/*callerHasSystemAccess=*/ false))
.isFalse();
}
@@ -458,21 +422,20 @@ public class AppSearchImplPlatformTest {
"package",
"database",
Collections.singletonList(new AppSearchSchema.Builder("Schema").build()),
mVisibilityStore,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ ImmutableMap.of(
"Schema",
ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))),
/*forceOverride=*/ false,
/*schemaVersion=*/ 0);
assertThat(
mAppSearchImpl
.getVisibilityStoreLocked()
assertThat(mVisibilityStore
.isSchemaSearchableByCaller(
"package",
"database",
prefix + "Schema",
packageNameFoo,
uidFoo))
uidFoo,
/*callerHasSystemAccess=*/ false))
.isTrue();
}

View File

@@ -88,15 +88,10 @@ public class VisibilityStoreTest {
};
// Give ourselves global query permissions
AppSearchImpl appSearchImpl =
AppSearchImpl.create(
mTemporaryFolder.newFolder(),
mContext,
/*logger=*/ null,
ALWAYS_OPTIMIZE);
AppSearchImpl appSearchImpl = AppSearchImpl.create(
mTemporaryFolder.newFolder(), /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
mVisibilityStore = VisibilityStore.create(appSearchImpl, mContext);
mUid = mContext.getPackageManager().getPackageUid(mContext.getPackageName(), /*flags=*/ 0);
mVisibilityStore = appSearchImpl.getVisibilityStoreLocked();
}
/**
@@ -121,6 +116,21 @@ public class VisibilityStoreTest {
.doesNotContain(String.valueOf(PrefixUtil.DATABASE_DELIMITER));
}
@Test
public void testDoesCallerHaveSystemAccess() {
PackageManager mockPackageManager = getMockPackageManager(mContext.getUser());
when(mockPackageManager
.checkPermission(READ_GLOBAL_APP_SEARCH_DATA, mContext.getPackageName()))
.thenReturn(PERMISSION_GRANTED);
assertThat(mVisibilityStore.doesCallerHaveSystemAccess(mContext.getPackageName())).isTrue();
when(mockPackageManager
.checkPermission(READ_GLOBAL_APP_SEARCH_DATA, mContext.getPackageName()))
.thenReturn(PERMISSION_DENIED);
assertThat(mVisibilityStore.doesCallerHaveSystemAccess(mContext.getPackageName()))
.isFalse();
}
@Test
public void testSetVisibility_platformSurfaceable() throws Exception {
// Make sure we have global query privileges
@@ -128,6 +138,7 @@ public class VisibilityStoreTest {
when(mockPackageManager
.checkPermission(READ_GLOBAL_APP_SEARCH_DATA, mContext.getPackageName()))
.thenReturn(PERMISSION_GRANTED);
assertThat(mVisibilityStore.doesCallerHaveSystemAccess(mContext.getPackageName())).isTrue();
mVisibilityStore.setVisibility(
"package",
@@ -140,16 +151,16 @@ public class VisibilityStoreTest {
"package",
"database",
"prefix/schema1",
mContext.getPackageName(),
mUid))
mUid,
/*callerHasSystemAccess=*/ true))
.isFalse();
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
"prefix/schema2",
mContext.getPackageName(),
mUid))
mUid,
/*callerHasSystemAccess=*/ true))
.isFalse();
// New .setVisibility() call completely overrides previous visibility settings.
@@ -165,24 +176,24 @@ public class VisibilityStoreTest {
"package",
"database",
"prefix/schema1",
mContext.getPackageName(),
mUid))
mUid,
/*callerHasSystemAccess=*/ true))
.isFalse();
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
"prefix/schema2",
mContext.getPackageName(),
mUid))
mUid,
/*callerHasSystemAccess=*/ true))
.isTrue();
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
"prefix/schema3",
mContext.getPackageName(),
mUid))
mUid,
/*callerHasSystemAccess=*/ true))
.isFalse();
// Everything defaults to visible again.
@@ -196,24 +207,24 @@ public class VisibilityStoreTest {
"package",
"database",
"prefix/schema1",
mContext.getPackageName(),
mUid))
mUid,
/*callerHasSystemAccess=*/ true))
.isTrue();
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
"prefix/schema2",
mContext.getPackageName(),
mUid))
mUid,
/*callerHasSystemAccess=*/ true))
.isTrue();
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
"prefix/schema3",
mContext.getPackageName(),
mUid))
mUid,
/*callerHasSystemAccess=*/ true))
.isTrue();
}
@@ -242,13 +253,19 @@ public class VisibilityStoreTest {
.thenReturn(PERMISSION_DENIED);
// By default, a schema isn't package accessible.
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"package", "database", "prefix/schemaFoo", packageNameFoo, uidFoo))
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
"prefix/schemaFoo",
uidFoo,
/*callerHasSystemAccess=*/ false))
.isFalse();
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"package", "database", "prefix/schemaBar", packageNameBar, uidBar))
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
"prefix/schemaBar",
uidBar,
/*callerHasSystemAccess=*/ false))
.isFalse();
// Grant package access
@@ -268,9 +285,12 @@ public class VisibilityStoreTest {
when(mockPackageManager.hasSigningCertificate(
packageNameFoo, sha256CertFoo, PackageManager.CERT_INPUT_SHA256))
.thenReturn(false);
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"package", "database", "prefix/schemaFoo", packageNameFoo, uidFoo))
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
"prefix/schemaFoo",
uidFoo,
/*callerHasSystemAccess=*/ false))
.isFalse();
// Should fail if PackageManager doesn't think the package belongs to the uid
@@ -279,9 +299,12 @@ public class VisibilityStoreTest {
when(mockPackageManager.hasSigningCertificate(
packageNameFoo, sha256CertFoo, PackageManager.CERT_INPUT_SHA256))
.thenReturn(true);
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"package", "database", "prefix/schemaFoo", packageNameFoo, uidFoo))
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
"prefix/schemaFoo",
uidFoo,
/*callerHasSystemAccess=*/ false))
.isFalse();
// But if uid and certificate match, then we should have access
@@ -290,9 +313,12 @@ public class VisibilityStoreTest {
when(mockPackageManager.hasSigningCertificate(
packageNameFoo, sha256CertFoo, PackageManager.CERT_INPUT_SHA256))
.thenReturn(true);
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"package", "database", "prefix/schemaFoo", packageNameFoo, uidFoo))
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
"prefix/schemaFoo",
uidFoo,
/*callerHasSystemAccess=*/ false))
.isTrue();
when(mockPackageManager.getPackageUid(eq(packageNameBar), /*flags=*/ anyInt()))
@@ -300,9 +326,12 @@ public class VisibilityStoreTest {
when(mockPackageManager.hasSigningCertificate(
packageNameBar, sha256CertBar, PackageManager.CERT_INPUT_SHA256))
.thenReturn(true);
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"package", "database", "prefix/schemaBar", packageNameBar, uidBar))
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
"prefix/schemaBar",
uidBar,
/*callerHasSystemAccess=*/ false))
.isTrue();
// New .setVisibility() call completely overrides previous visibility settings. So
@@ -320,9 +349,12 @@ public class VisibilityStoreTest {
when(mockPackageManager.hasSigningCertificate(
packageNameFoo, sha256CertFoo, PackageManager.CERT_INPUT_SHA256))
.thenReturn(true);
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"package", "database", "prefix/schemaFoo", packageNameFoo, uidFoo))
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
"prefix/schemaFoo",
uidFoo,
/*callerHasSystemAccess=*/ false))
.isTrue();
when(mockPackageManager.getPackageUid(eq(packageNameBar), /*flags=*/ anyInt()))
@@ -330,9 +362,12 @@ public class VisibilityStoreTest {
when(mockPackageManager.hasSigningCertificate(
packageNameBar, sha256CertBar, PackageManager.CERT_INPUT_SHA256))
.thenReturn(true);
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"package", "database", "prefix/schemaBar", packageNameBar, uidBar))
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
"prefix/schemaBar",
uidBar,
/*callerHasSystemAccess=*/ false))
.isFalse();
}
@@ -363,9 +398,12 @@ public class VisibilityStoreTest {
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(
"package", "database", "prefix/schemaFoo", packageNameFoo, uidFoo))
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
"database",
"prefix/schemaFoo",
uidFoo,
/*callerHasSystemAccess=*/ false))
.isFalse();
}
@@ -397,8 +435,8 @@ public class VisibilityStoreTest {
/*packageName=*/ "",
/*databaseName=*/ "",
"schema",
mContext.getPackageName(),
mUid))
mUid,
/*callerHasSystemAccess=*/ true))
.isTrue();
when(mockPackageManager.getPackageUid(eq(packageNameFoo), /*flags=*/ anyInt()))
@@ -411,8 +449,8 @@ public class VisibilityStoreTest {
/*packageName=*/ "",
/*databaseName=*/ "",
"schema",
packageNameFoo,
uidFoo))
uidFoo,
/*callerHasSystemAccess=*/ false))
.isTrue();
}

View File

@@ -83,15 +83,9 @@ public class AppSearchImplTest {
@Before
public void setUp() throws Exception {
Context context = ApplicationProvider.getApplicationContext();
// Give ourselves global query permissions.
mAppSearchImpl =
AppSearchImpl.create(
mTemporaryFolder.newFolder(),
context,
/*logger=*/ null,
ALWAYS_OPTIMIZE);
mTemporaryFolder.newFolder(), /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
}
/**
@@ -149,7 +143,7 @@ public class AppSearchImplTest {
.build();
AppSearchImpl.RewrittenSchemaResults rewrittenSchemaResults =
mAppSearchImpl.rewriteSchema(
AppSearchImpl.rewriteSchema(
createPrefix("package", "newDatabase"), existingSchemaBuilder, newSchema);
// We rewrote all the new types that were added. And nothing was removed.
@@ -249,7 +243,7 @@ public class AppSearchImplTest {
.build();
AppSearchImpl.RewrittenSchemaResults rewrittenSchemaResults =
mAppSearchImpl.rewriteSchema(
AppSearchImpl.rewriteSchema(
createPrefix("package", "existingDatabase"),
existingSchemaBuilder,
newSchema);
@@ -284,7 +278,7 @@ public class AppSearchImplTest {
.build();
AppSearchImpl.RewrittenSchemaResults rewrittenSchemaResults =
mAppSearchImpl.rewriteSchema(
AppSearchImpl.rewriteSchema(
createPrefix("package", "existingDatabase"),
existingSchemaBuilder,
newSchema);
@@ -386,7 +380,7 @@ public class AppSearchImplTest {
}
@Test
public void testRemoveDatabasesFromDocumentThrowsException() throws Exception {
public void testRemoveDatabasesFromDocumentThrowsException() {
// Set two different database names in the document, which should never happen
DocumentProto documentProto =
DocumentProto.newBuilder()
@@ -403,7 +397,7 @@ public class AppSearchImplTest {
}
@Test
public void testNestedRemoveDatabasesFromDocumentThrowsException() throws Exception {
public void testNestedRemoveDatabasesFromDocumentThrowsException() {
// Set two different database names in the outer and inner document, which should never
// happen.
DocumentProto insideDocument =
@@ -436,6 +430,7 @@ public class AppSearchImplTest {
"package",
"database",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -473,11 +468,7 @@ public class AppSearchImplTest {
Context context = ApplicationProvider.getApplicationContext();
File appsearchDir = mTemporaryFolder.newFolder();
AppSearchImpl appSearchImpl =
AppSearchImpl.create(
appsearchDir,
context,
/*logger=*/ null,
ALWAYS_OPTIMIZE);
AppSearchImpl.create(appsearchDir, /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
// Insert schema
List<AppSearchSchema> schemas =
@@ -488,6 +479,7 @@ public class AppSearchImplTest {
context.getPackageName(),
"database1",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -506,7 +498,9 @@ public class AppSearchImplTest {
/*queryExpression=*/ "",
new SearchSpec.Builder().addFilterSchemas("Type1").build(),
context.getPackageName(),
/*visibilityStore=*/ null,
VisibilityStore.NO_OP_UID,
/*callerHasSystemAccess=*/ false,
/*logger=*/ null);
assertThat(results.getResults()).hasSize(1);
assertThat(results.getResults().get(0).getGenericDocument()).isEqualTo(validDoc);
@@ -532,18 +526,13 @@ public class AppSearchImplTest {
PutResultProto putResultProto = appSearchImpl.mIcingSearchEngineLocked.put(invalidDoc);
assertThat(putResultProto.getStatus().getCode()).isEqualTo(StatusProto.Code.OK);
// Create a logger for capturing initialization to make sure we are logging the recovery
// process correctly.
AppSearchLoggerTest.TestLogger testLogger = new AppSearchLoggerTest.TestLogger();
// Initialize AppSearchImpl. This should cause a reset.
InitializeStats.Builder initStatsBuilder = new InitializeStats.Builder();
appSearchImpl.close();
appSearchImpl =
AppSearchImpl.create(
appsearchDir, context, testLogger, ALWAYS_OPTIMIZE);
appSearchImpl = AppSearchImpl.create(appsearchDir, initStatsBuilder, ALWAYS_OPTIMIZE);
// Check recovery state
InitializeStats initStats = testLogger.mInitializeStats;
InitializeStats initStats = initStatsBuilder.build();
assertThat(initStats).isNotNull();
assertThat(initStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_INTERNAL_ERROR);
assertThat(initStats.hasDeSync()).isFalse();
@@ -568,7 +557,9 @@ public class AppSearchImplTest {
/*queryExpression=*/ "",
new SearchSpec.Builder().addFilterSchemas("Type1").build(),
context.getPackageName(),
/*visibilityStore=*/ null,
VisibilityStore.NO_OP_UID,
/*callerHasSystemAccess=*/ false,
/*logger=*/ null);
assertThat(results.getResults()).isEmpty();
@@ -577,6 +568,7 @@ public class AppSearchImplTest {
context.getPackageName(),
"database1",
Collections.singletonList(new AppSearchSchema.Builder("Type1").build()),
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -592,7 +584,9 @@ public class AppSearchImplTest {
/*queryExpression=*/ "",
new SearchSpec.Builder().addFilterSchemas("Type1").build(),
context.getPackageName(),
/*visibilityStore=*/ null,
VisibilityStore.NO_OP_UID,
/*callerHasSystemAccess=*/ false,
/*logger=*/ null);
assertThat(results.getResults()).hasSize(1);
assertThat(results.getResults().get(0).getGenericDocument()).isEqualTo(validDoc);
@@ -609,6 +603,7 @@ public class AppSearchImplTest {
"package",
"database",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -642,6 +637,7 @@ public class AppSearchImplTest {
"package",
"database1",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -650,6 +646,7 @@ public class AppSearchImplTest {
"package",
"database2",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -694,6 +691,7 @@ public class AppSearchImplTest {
"package",
"database",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -735,6 +733,7 @@ public class AppSearchImplTest {
"package1",
"database1",
schema1,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -747,6 +746,7 @@ public class AppSearchImplTest {
"package2",
"database2",
schema2,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -789,6 +789,7 @@ public class AppSearchImplTest {
"package1",
"database1",
schema1,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -801,6 +802,7 @@ public class AppSearchImplTest {
"package2",
"database2",
schema2,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -848,7 +850,9 @@ public class AppSearchImplTest {
"",
searchSpec,
/*callerPackageName=*/ "",
/*visibilityStore=*/ null,
VisibilityStore.NO_OP_UID,
/*callerHasSystemAccess=*/ false,
/*logger=*/ null);
assertThat(searchResultPage.getResults()).isEmpty();
}
@@ -888,6 +892,7 @@ public class AppSearchImplTest {
"package",
"database1",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -911,9 +916,6 @@ public class AppSearchImplTest {
@Test
public void testSetSchema_incompatible() throws Exception {
List<SchemaTypeConfigProto> existingSchemas =
mAppSearchImpl.getSchemaProtoLocked().getTypesList();
List<AppSearchSchema> oldSchemas = new ArrayList<>();
oldSchemas.add(
new AppSearchSchema.Builder("Email")
@@ -935,6 +937,7 @@ public class AppSearchImplTest {
"package",
"database1",
oldSchemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -950,6 +953,7 @@ public class AppSearchImplTest {
"package",
"database1",
newSchemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ true,
@@ -972,6 +976,7 @@ public class AppSearchImplTest {
"package",
"database1",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -1004,6 +1009,7 @@ public class AppSearchImplTest {
"package",
"database1",
finalSchemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -1017,6 +1023,7 @@ public class AppSearchImplTest {
"package",
"database1",
finalSchemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ true,
@@ -1054,6 +1061,7 @@ public class AppSearchImplTest {
"package",
"database1",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -1062,6 +1070,7 @@ public class AppSearchImplTest {
"package",
"database2",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -1101,6 +1110,7 @@ public class AppSearchImplTest {
"package",
"database1",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ true,
@@ -1145,6 +1155,7 @@ public class AppSearchImplTest {
"package",
"database",
schema,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -1206,6 +1217,7 @@ public class AppSearchImplTest {
"packageA",
"database",
schema,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -1214,6 +1226,7 @@ public class AppSearchImplTest {
"packageB",
"database",
schema,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -1259,6 +1272,7 @@ public class AppSearchImplTest {
"package1",
"database1",
Collections.singletonList(new AppSearchSchema.Builder("schema").build()),
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -1272,6 +1286,7 @@ public class AppSearchImplTest {
"package1",
"database2",
Collections.singletonList(new AppSearchSchema.Builder("schema").build()),
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -1285,6 +1300,7 @@ public class AppSearchImplTest {
"package2",
"database1",
Collections.singletonList(new AppSearchSchema.Builder("schema").build()),
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -1343,6 +1359,7 @@ public class AppSearchImplTest {
"package",
"database",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -1493,6 +1510,7 @@ public class AppSearchImplTest {
"package1",
"database",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -1515,6 +1533,7 @@ public class AppSearchImplTest {
"package1",
"database",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -1530,6 +1549,7 @@ public class AppSearchImplTest {
"package2",
"database",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -1578,6 +1598,7 @@ public class AppSearchImplTest {
"package1",
"database",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -1600,6 +1621,7 @@ public class AppSearchImplTest {
"package1",
"database1",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -1621,6 +1643,7 @@ public class AppSearchImplTest {
"package1",
"database1",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -1629,6 +1652,7 @@ public class AppSearchImplTest {
"package1",
"database2",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -1664,13 +1688,9 @@ public class AppSearchImplTest {
@Test
public void testThrowsExceptionIfClosed() throws Exception {
Context context = ApplicationProvider.getApplicationContext();
AppSearchImpl appSearchImpl =
AppSearchImpl.create(
mTemporaryFolder.newFolder(),
context,
/*logger=*/ null,
ALWAYS_OPTIMIZE);
mTemporaryFolder.newFolder(), /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
// Initial check that we could do something at first.
List<AppSearchSchema> schemas =
@@ -1679,6 +1699,7 @@ public class AppSearchImplTest {
"package",
"database",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -1689,140 +1710,115 @@ public class AppSearchImplTest {
// Check all our public APIs
expectThrows(
IllegalStateException.class,
() -> {
appSearchImpl.setSchema(
"package",
"database",
schemas,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
});
() ->
appSearchImpl.setSchema(
"package",
"database",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0));
expectThrows(
IllegalStateException.class, () -> appSearchImpl.getSchema("package", "database"));
expectThrows(
IllegalStateException.class,
() -> {
appSearchImpl.getSchema("package", "database");
});
() ->
appSearchImpl.putDocument(
"package",
"database",
new GenericDocument.Builder<>("namespace", "id", "type").build(),
/*logger=*/ null));
expectThrows(
IllegalStateException.class,
() -> {
appSearchImpl.putDocument(
"package",
"database",
new GenericDocument.Builder<>("namespace", "id", "type").build(),
/*logger=*/ null);
});
() ->
appSearchImpl.getDocument(
"package", "database", "namespace", "id", Collections.emptyMap()));
expectThrows(
IllegalStateException.class,
() -> {
appSearchImpl.getDocument(
"package", "database", "namespace", "id", Collections.emptyMap());
});
() ->
appSearchImpl.query(
"package",
"database",
"query",
new SearchSpec.Builder().build(),
/*logger=*/ null));
expectThrows(
IllegalStateException.class,
() -> {
appSearchImpl.query(
"package",
"database",
"query",
new SearchSpec.Builder()
.setTermMatch(TermMatchType.Code.PREFIX_VALUE)
.build(),
/*logger=*/ null);
});
() ->
appSearchImpl.globalQuery(
"query",
new SearchSpec.Builder().build(),
"package",
/*visibilityStore=*/ null,
VisibilityStore.NO_OP_UID,
/*callerHasSystemAccess=*/ false,
/*logger=*/ null));
expectThrows(
IllegalStateException.class,
() -> {
appSearchImpl.globalQuery(
"query",
new SearchSpec.Builder()
.setTermMatch(TermMatchType.Code.PREFIX_VALUE)
.build(),
"package",
VisibilityStore.NO_OP_UID,
/*logger=*/ null);
});
() -> appSearchImpl.getNextPage(/*nextPageToken=*/ 1L));
expectThrows(
IllegalStateException.class,
() -> {
appSearchImpl.getNextPage(/*nextPageToken=*/ 1L);
});
() -> appSearchImpl.invalidateNextPageToken(/*nextPageToken=*/ 1L));
expectThrows(
IllegalStateException.class,
() -> {
appSearchImpl.invalidateNextPageToken(/*nextPageToken=*/ 1L);
});
() ->
appSearchImpl.reportUsage(
"package",
"database",
"namespace",
"id",
/*usageTimestampMillis=*/ 1000L,
/*systemUsage=*/ false));
expectThrows(
IllegalStateException.class,
() -> {
appSearchImpl.reportUsage(
"package",
"database",
"namespace",
"id",
/*usageTimestampMillis=*/ 1000L,
/*systemUsage=*/ false);
});
() ->
appSearchImpl.remove(
"package",
"database",
"namespace",
"id",
/*removeStatsBuilder=*/ null));
expectThrows(
IllegalStateException.class,
() -> {
appSearchImpl.remove(
"package", "database", "namespace", "id", /*statsBuilder=*/ null);
});
() ->
appSearchImpl.removeByQuery(
"package",
"database",
"query",
new SearchSpec.Builder().build(),
/*removeStatsBuilder=*/ null));
expectThrows(
IllegalStateException.class,
() -> {
appSearchImpl.removeByQuery(
"package",
"database",
"query",
new SearchSpec.Builder()
.setTermMatch(TermMatchType.Code.PREFIX_VALUE)
.build(),
/*statsBuilder=*/ null);
});
() -> appSearchImpl.getStorageInfoForPackage("package"));
expectThrows(
IllegalStateException.class,
() -> {
appSearchImpl.getStorageInfoForPackage("package");
});
() -> appSearchImpl.getStorageInfoForDatabase("package", "database"));
expectThrows(
IllegalStateException.class,
() -> {
appSearchImpl.getStorageInfoForDatabase("package", "database");
});
expectThrows(
IllegalStateException.class,
() -> {
appSearchImpl.persistToDisk(PersistType.Code.FULL);
});
() -> appSearchImpl.persistToDisk(PersistType.Code.FULL));
}
@Test
public void testPutPersistsWithLiteFlush() throws Exception {
// Setup the index
Context context = ApplicationProvider.getApplicationContext();
File appsearchDir = mTemporaryFolder.newFolder();
AppSearchImpl appSearchImpl =
AppSearchImpl.create(
appsearchDir,
context,
/*logger=*/ null,
ALWAYS_OPTIMIZE);
AppSearchImpl.create(appsearchDir, /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
List<AppSearchSchema> schemas =
Collections.singletonList(new AppSearchSchema.Builder("type").build());
@@ -1830,6 +1826,7 @@ public class AppSearchImplTest {
"package",
"database",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -1848,11 +1845,7 @@ public class AppSearchImplTest {
// That document should be visible even from another instance.
AppSearchImpl appSearchImpl2 =
AppSearchImpl.create(
appsearchDir,
context,
/*logger=*/ null,
ALWAYS_OPTIMIZE);
AppSearchImpl.create(appsearchDir, /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
getResult =
appSearchImpl2.getDocument(
"package", "database", "namespace1", "id1", Collections.emptyMap());
@@ -1862,14 +1855,9 @@ public class AppSearchImplTest {
@Test
public void testDeletePersistsWithLiteFlush() throws Exception {
// Setup the index
Context context = ApplicationProvider.getApplicationContext();
File appsearchDir = mTemporaryFolder.newFolder();
AppSearchImpl appSearchImpl =
AppSearchImpl.create(
appsearchDir,
context,
/*logger=*/ null,
ALWAYS_OPTIMIZE);
AppSearchImpl.create(appsearchDir, /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
List<AppSearchSchema> schemas =
Collections.singletonList(new AppSearchSchema.Builder("type").build());
@@ -1877,6 +1865,7 @@ public class AppSearchImplTest {
"package",
"database",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -1919,11 +1908,7 @@ public class AppSearchImplTest {
// Only the second document should be retrievable from another instance.
AppSearchImpl appSearchImpl2 =
AppSearchImpl.create(
appsearchDir,
context,
/*logger=*/ null,
ALWAYS_OPTIMIZE);
AppSearchImpl.create(appsearchDir, /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
expectThrows(
AppSearchException.class,
() ->
@@ -1942,14 +1927,9 @@ public class AppSearchImplTest {
@Test
public void testDeleteByQueryPersistsWithLiteFlush() throws Exception {
// Setup the index
Context context = ApplicationProvider.getApplicationContext();
File appsearchDir = mTemporaryFolder.newFolder();
AppSearchImpl appSearchImpl =
AppSearchImpl.create(
appsearchDir,
context,
/*logger=*/ null,
ALWAYS_OPTIMIZE);
AppSearchImpl.create(appsearchDir, /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
List<AppSearchSchema> schemas =
Collections.singletonList(new AppSearchSchema.Builder("type").build());
@@ -1957,6 +1937,7 @@ public class AppSearchImplTest {
"package",
"database",
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -2007,11 +1988,7 @@ public class AppSearchImplTest {
// Only the second document should be retrievable from another instance.
AppSearchImpl appSearchImpl2 =
AppSearchImpl.create(
appsearchDir,
context,
/*logger=*/ null,
ALWAYS_OPTIMIZE);
AppSearchImpl.create(appsearchDir, /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
expectThrows(
AppSearchException.class,
() ->

View File

@@ -25,9 +25,6 @@ import android.app.appsearch.AppSearchSchema;
import android.app.appsearch.GenericDocument;
import android.app.appsearch.SearchResultPage;
import android.app.appsearch.SearchSpec;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import com.android.server.appsearch.external.localstorage.stats.CallStats;
import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
@@ -60,15 +57,9 @@ public class AppSearchLoggerTest {
@Before
public void setUp() throws Exception {
Context context = ApplicationProvider.getApplicationContext();
// Give ourselves global query permissions
mAppSearchImpl =
AppSearchImpl.create(
mTemporaryFolder.newFolder(),
context,
/*logger=*/ null,
ALWAYS_OPTIMIZE);
mTemporaryFolder.newFolder(), /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
mLogger = new TestLogger();
}
@@ -289,20 +280,15 @@ public class AppSearchLoggerTest {
//
@Test
public void testLoggingStats_initialize() throws Exception {
Context context = ApplicationProvider.getApplicationContext();
// Create an unused AppSearchImpl to generated an InitializeStats.
AppSearchImpl appSearchImpl =
AppSearchImpl.create(
mTemporaryFolder.newFolder(),
context,
mLogger,
ALWAYS_OPTIMIZE);
InitializeStats.Builder initStatsBuilder = new InitializeStats.Builder();
AppSearchImpl.create(mTemporaryFolder.newFolder(), initStatsBuilder, ALWAYS_OPTIMIZE);
InitializeStats iStats = initStatsBuilder.build();
InitializeStats iStats = mLogger.mInitializeStats;
assertThat(iStats).isNotNull();
assertThat(iStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
assertThat(iStats.getTotalLatencyMillis()).isGreaterThan(0);
// Total latency captured in LocalStorage
assertThat(iStats.getTotalLatencyMillis()).isEqualTo(0);
assertThat(iStats.hasDeSync()).isFalse();
assertThat(iStats.getNativeLatencyMillis()).isGreaterThan(0);
assertThat(iStats.getDocumentStoreDataStatus())
@@ -322,6 +308,7 @@ public class AppSearchLoggerTest {
testPackageName,
testDatabase,
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -350,10 +337,12 @@ public class AppSearchLoggerTest {
testPackageName,
testDatabase,
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
GenericDocument document = new GenericDocument.Builder<>("namespace", "id", "type").build();
mAppSearchImpl.putDocument(testPackageName, testDatabase, document, mLogger);
@@ -401,6 +390,7 @@ public class AppSearchLoggerTest {
testPackageName,
testDatabase,
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
@@ -432,6 +422,7 @@ public class AppSearchLoggerTest {
testPackageName,
testDatabase,
schemas,
/*visibilityStore=*/ null,
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false,