summaryrefslogtreecommitdiff
path: root/apex
diff options
context:
space:
mode:
authorAlexander Dorokhine <adorokhine@google.com>2021-06-18 10:48:58 -0700
committerAlexander Dorokhine <adorokhine@google.com>2021-06-18 10:48:58 -0700
commit9b26c3c9be866b1bf8b0199f20073e6eeab1a4dd (patch)
tree9fb9e7a2febcc4733c37eee870a898855957c7b8 /apex
parent5c86c0c10e71a6bc47582dd266da987198a0baa8 (diff)
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
Diffstat (limited to 'apex')
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java300
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstance.java58
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstanceManager.java195
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java170
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java132
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/stats/LoggerInstanceManager.java126
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/NotPlatformSurfaceableMap.java5
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/PackageAccessibleMap.java5
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStore.java72
9 files changed, 474 insertions, 589 deletions
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index 31203c73c76a..400c24138060 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -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);
-
- if (systemUsage) {
- // TODO(b/183031844): Validate that the call comes from the system
+ verifyCallingPackage(callingUser, callingUid, packageName);
+ AppSearchUserInstance instance =
+ mAppSearchUserInstanceManager.getUserInstance(callingUser);
+
+ 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);
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstance.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstance.java
new file mode 100644
index 000000000000..7e743edaf3ee
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstance.java
@@ -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;
+ }
+}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstanceManager.java
new file mode 100644
index 000000000000..cedc364f6072
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstanceManager.java
@@ -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);
+ }
+}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
deleted file mode 100644
index 2181dab90681..000000000000
--- a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
+++ /dev/null
@@ -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());
- }
-}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
index 4a1a9ae3546b..77a1bb402bd3 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
@@ -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.
*
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/stats/LoggerInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/stats/LoggerInstanceManager.java
deleted file mode 100644
index ea00f506b47f..000000000000
--- a/apex/appsearch/service/java/com/android/server/appsearch/stats/LoggerInstanceManager.java
+++ /dev/null
@@ -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);
- }
- }
-}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/NotPlatformSurfaceableMap.java b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/NotPlatformSurfaceableMap.java
index 5ad4276d9318..9e36fd02569f 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/NotPlatformSurfaceableMap.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/NotPlatformSurfaceableMap.java
@@ -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();
- }
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/PackageAccessibleMap.java b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/PackageAccessibleMap.java
index 2b3934718aed..cff729aa4e8a 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/PackageAccessibleMap.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/PackageAccessibleMap.java
@@ -82,9 +82,4 @@ class PackageAccessibleMap {
}
return accessiblePackages;
}
-
- /** Discards all data in the map. */
- public void clear() {
- mMap.clear();
- }
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStore.java b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStore.java
index a9f6adb20225..ae1ec56b4ee6 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStore.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStore.java
@@ -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) {
+ @NonNull
+ public static VisibilityStore create(
+ @NonNull AppSearchImpl appSearchImpl, @NonNull Context userContext)
+ throws AppSearchException {
+ return new VisibilityStore(appSearchImpl, userContext);
+ }
+
+ private VisibilityStore(@NonNull AppSearchImpl appSearchImpl, @NonNull Context userContext)
+ throws AppSearchException {
mAppSearchImpl = Objects.requireNonNull(appSearchImpl);
mUserContext = Objects.requireNonNull(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 {
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();
@@ -281,38 +276,45 @@ public class VisibilityStore {
}
/**
+ * 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;
}
@@ -373,16 +375,6 @@ public class VisibilityStore {
}
/**
- * 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.
*
* @param packageName Package to which the visibility doc refers