diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java index 6fa8f850100b6..ed4e0347b6a48 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java @@ -46,6 +46,7 @@ import java.util.function.Consumer; public class AppSearchManager { /** * The default empty database name. + * * @hide */ public static final String DEFAULT_DATABASE_NAME = ""; @@ -70,8 +71,8 @@ public class AppSearchManager { /** * Returns the name of the database to create or open. * - *

Databases with different names are fully separate with distinct types, namespaces, - * and data. + *

Databases with different names are fully separate with distinct types, namespaces, and + * data. */ @NonNull public String getDatabaseName() { @@ -126,11 +127,11 @@ public class AppSearchManager { * initialization process will create one under the user's credential encrypted directory. * * @param searchContext The {@link SearchContext} contains all information to create a new - * {@link AppSearchSession} - * @param executor Executor on which to invoke the callback. - * @param callback The {@link AppSearchResult}<{@link AppSearchSession}> of - * performing this operation. Or a {@link AppSearchResult} with failure - * reason code and error information. + * {@link AppSearchSession} + * @param executor Executor on which to invoke the callback. + * @param callback The {@link AppSearchResult}<{@link AppSearchSession}> of performing + * this operation. Or a {@link AppSearchResult} with failure reason code and error + * information. */ public void createSearchSession( @NonNull SearchContext searchContext, @@ -140,7 +141,12 @@ public class AppSearchManager { Objects.requireNonNull(executor); Objects.requireNonNull(callback); AppSearchSession.createSearchSession( - searchContext, mService, mContext.getUserId(), executor, callback); + searchContext, + mService, + mContext.getUserId(), + getPackageName(), + executor, + callback); } /** @@ -149,10 +155,10 @@ public class AppSearchManager { *

This process requires an AppSearch native indexing file system. If it's not created, the * initialization process will create one under the user's credential encrypted directory. * - * @param executor Executor on which to invoke the callback. - * @param callback The {@link AppSearchResult}<{@link GlobalSearchSession}> of - * performing this operation. Or a {@link AppSearchResult} with failure - * reason code and error information. + * @param executor Executor on which to invoke the callback. + * @param callback The {@link AppSearchResult}<{@link GlobalSearchSession}> of performing + * this operation. Or a {@link AppSearchResult} with failure reason code and error + * information. */ public void createGlobalSearchSession( @NonNull @CallbackExecutor Executor executor, @@ -160,7 +166,7 @@ public class AppSearchManager { Objects.requireNonNull(executor); Objects.requireNonNull(callback); GlobalSearchSession.createGlobalSearchSession( - mService, mContext.getUserId(), executor, callback); + mService, mContext.getUserId(), getPackageName(), executor, callback); } /** @@ -170,40 +176,42 @@ public class AppSearchManager { * to {@link #setSchema}, if any, to determine how to treat existing documents. The following * types of schema modifications are always safe and are made without deleting any existing * documents: + * *

* *

The following types of schema changes are not backwards-compatible: + * *

- *

Supplying a schema with such changes will result in this call returning an - * {@link AppSearchResult} with a code of {@link AppSearchResult#RESULT_INVALID_SCHEMA} and an - * error message describing the incompatibility. In this case the previously set schema will - * remain active. + * + *

Supplying a schema with such changes will result in this call returning an {@link + * AppSearchResult} with a code of {@link AppSearchResult#RESULT_INVALID_SCHEMA} and an error + * message describing the incompatibility. In this case the previously set schema will remain + * active. * *

If you need to make non-backwards-compatible changes as described above, instead use the * {@link #setSchema(List, boolean)} method with the {@code forceOverride} parameter set to @@ -214,8 +222,8 @@ public class AppSearchManager { * * @param request The schema update request. * @return the result of performing this operation. - * @deprecated use {@link AppSearchSession#setSchema} instead. * @hide + * @deprecated use {@link AppSearchSession#setSchema} instead. */ @NonNull public AppSearchResult setSchema(@NonNull SetSchemaRequest request) { @@ -229,6 +237,7 @@ public class AppSearchManager { AndroidFuture future = new AndroidFuture<>(); try { mService.setSchema( + getPackageName(), DEFAULT_DATABASE_NAME, schemaBundles, new ArrayList<>(request.getSchemasNotVisibleToSystemUi()), @@ -249,21 +258,19 @@ public class AppSearchManager { /** * Index {@link GenericDocument}s into AppSearch. * - *

You should not call this method directly; instead, use the - * {@code AppSearch#putDocuments()} API provided by JetPack. + *

You should not call this method directly; instead, use the {@code + * AppSearch#putDocuments()} API provided by JetPack. * *

Each {@link GenericDocument}'s {@code schemaType} field must be set to the name of a * schema type previously registered via the {@link #setSchema} method. * * @param request {@link PutDocumentsRequest} containing documents to be indexed - * @return The pending result of performing this operation. The keys of the returned - * {@link AppSearchBatchResult} are the URIs of the input documents. The values are - * {@code null} if they were successfully indexed, or a failed {@link AppSearchResult} - * otherwise. + * @return The pending result of performing this operation. The keys of the returned {@link + * AppSearchBatchResult} are the URIs of the input documents. The values are {@code null} if + * they were successfully indexed, or a failed {@link AppSearchResult} otherwise. * @throws RuntimeException If an error occurred during the execution. - * - * @deprecated use {@link AppSearchSession#putDocuments} instead. * @hide + * @deprecated use {@link AppSearchSession#putDocuments} instead. */ public AppSearchBatchResult putDocuments(@NonNull PutDocumentsRequest request) { // TODO(b/146386470): Transmit these documents as a RemoteStream instead of sending them in @@ -275,7 +282,11 @@ public class AppSearchManager { } AndroidFuture future = new AndroidFuture<>(); try { - mService.putDocuments(DEFAULT_DATABASE_NAME, documentBundles, mContext.getUserId(), + mService.putDocuments( + getPackageName(), + DEFAULT_DATABASE_NAME, + documentBundles, + mContext.getUserId(), new IAppSearchBatchResultCallback.Stub() { public void onResult(AppSearchBatchResult result) { future.complete(result); @@ -294,19 +305,18 @@ public class AppSearchManager { /** * Retrieves {@link GenericDocument}s by URI. * - *

You should not call this method directly; instead, use the - * {@code AppSearch#getDocuments()} API provided by JetPack. + *

You should not call this method directly; instead, use the {@code + * AppSearch#getDocuments()} API provided by JetPack. * * @param request {@link GetByUriRequest} containing URIs to be retrieved. - * @return The pending result of performing this operation. The keys of the returned - * {@link AppSearchBatchResult} are the input URIs. The values are the returned - * {@link GenericDocument}s on success, or a failed {@link AppSearchResult} otherwise. - * URIs that are not found will return a failed {@link AppSearchResult} with a result code - * of {@link AppSearchResult#RESULT_NOT_FOUND}. + * @return The pending result of performing this operation. The keys of the returned {@link + * AppSearchBatchResult} are the input URIs. The values are the returned {@link + * GenericDocument}s on success, or a failed {@link AppSearchResult} otherwise. URIs that + * are not found will return a failed {@link AppSearchResult} with a result code of {@link + * AppSearchResult#RESULT_NOT_FOUND}. * @throws RuntimeException If an error occurred during the execution. - * - * @deprecated use {@link AppSearchSession#getByUri} instead. * @hide + * @deprecated use {@link AppSearchSession#getByUri} instead. */ public AppSearchBatchResult getByUri( @NonNull GetByUriRequest request) { @@ -315,7 +325,11 @@ public class AppSearchManager { List uris = new ArrayList<>(request.getUris()); AndroidFuture future = new AndroidFuture<>(); try { - mService.getDocuments(DEFAULT_DATABASE_NAME, request.getNamespace(), uris, + mService.getDocuments( + getPackageName(), + DEFAULT_DATABASE_NAME, + request.getNamespace(), + uris, mContext.getUserId(), new IAppSearchBatchResultCallback.Stub() { public void onResult(AppSearchBatchResult result) { @@ -371,43 +385,39 @@ public class AppSearchManager { * provided by JetPack. * *

Currently we support following features in the raw query format: + * *

* * @param queryExpression Query String to search. * @param searchSpec Spec for setting filters, raw query etc. * @throws RuntimeException If an error occurred during the execution. - * - * @deprecated use AppSearchSession#query instead. * @hide + * @deprecated use AppSearchSession#query instead. */ @NonNull public AppSearchResult> query( @@ -416,7 +426,11 @@ public class AppSearchManager { // them in one big list. AndroidFuture future = new AndroidFuture<>(); try { - mService.query(DEFAULT_DATABASE_NAME, queryExpression, searchSpec.getBundle(), + mService.query( + getPackageName(), + DEFAULT_DATABASE_NAME, + queryExpression, + searchSpec.getBundle(), mContext.getUserId(), new IAppSearchResultCallback.Stub() { public void onResult(AppSearchResult result) { @@ -425,8 +439,8 @@ public class AppSearchManager { }); AppSearchResult bundleResult = getFutureOrThrow(future); if (!bundleResult.isSuccess()) { - return AppSearchResult.newFailedResult(bundleResult.getResultCode(), - bundleResult.getErrorMessage()); + return AppSearchResult.newFailedResult( + bundleResult.getResultCode(), bundleResult.getErrorMessage()); } SearchResultPage searchResultPage = new SearchResultPage(bundleResult.getResultValue()); return AppSearchResult.newSuccessfulResult(searchResultPage.getResults()); @@ -444,21 +458,23 @@ public class AppSearchManager { * provided by JetPack. * * @param request Request containing URIs to be removed. - * @return The pending result of performing this operation. The keys of the returned - * {@link AppSearchBatchResult} are the input URIs. The values are {@code null} on success, - * or a failed {@link AppSearchResult} otherwise. URIs that are not found will return a - * failed {@link AppSearchResult} with a result code of - * {@link AppSearchResult#RESULT_NOT_FOUND}. + * @return The pending result of performing this operation. The keys of the returned {@link + * AppSearchBatchResult} are the input URIs. The values are {@code null} on success, or a + * failed {@link AppSearchResult} otherwise. URIs that are not found will return a failed + * {@link AppSearchResult} with a result code of {@link AppSearchResult#RESULT_NOT_FOUND}. * @throws RuntimeException If an error occurred during the execution. - * - * @deprecated use {@link AppSearchSession#removeByUri} instead. * @hide + * @deprecated use {@link AppSearchSession#removeByUri} instead. */ public AppSearchBatchResult removeByUri(@NonNull RemoveByUriRequest request) { List uris = new ArrayList<>(request.getUris()); AndroidFuture future = new AndroidFuture<>(); try { - mService.removeByUri(DEFAULT_DATABASE_NAME, request.getNamespace(), uris, + mService.removeByUri( + getPackageName(), + DEFAULT_DATABASE_NAME, + request.getNamespace(), + uris, mContext.getUserId(), new IAppSearchBatchResultCallback.Stub() { public void onResult(AppSearchBatchResult result) { @@ -475,6 +491,12 @@ public class AppSearchManager { return getFutureOrThrow(future); } + /** Returns the package name that should be used for uid verification. */ + @NonNull + private String getPackageName() { + return mContext.getOpPackageName(); + } + private static T getFutureOrThrow(@NonNull AndroidFuture future) { try { return future.get(); diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java index 042757797dce4..270d601a20d02 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java @@ -45,6 +45,7 @@ import java.util.function.Consumer; */ public final class AppSearchSession implements Closeable { private static final String TAG = "AppSearchSession"; + private final String mPackageName; private final String mDatabaseName; @UserIdInt private final int mUserId; @@ -52,14 +53,20 @@ public final class AppSearchSession implements Closeable { private boolean mIsMutated = false; private boolean mIsClosed = false; + + /** + * Creates a search session for the client, defined by the {@code userId} and + * {@code packageName}. + */ static void createSearchSession( @NonNull AppSearchManager.SearchContext searchContext, @NonNull IAppSearchManager service, @UserIdInt int userId, + @NonNull String packageName, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer> callback) { AppSearchSession searchSession = - new AppSearchSession(service, userId, searchContext.mDatabaseName); + new AppSearchSession(service, userId, packageName, searchContext.mDatabaseName); searchSession.initialize(executor, callback); } @@ -87,10 +94,11 @@ public final class AppSearchSession implements Closeable { } private AppSearchSession(@NonNull IAppSearchManager service, @UserIdInt int userId, - @NonNull String databaseName) { - mDatabaseName = databaseName; + @NonNull String packageName, @NonNull String databaseName) { mService = service; mUserId = userId; + mPackageName = packageName; + mDatabaseName = databaseName; } /** @@ -144,7 +152,7 @@ public final class AppSearchSession implements Closeable { * Visibility settings for a schema type do not apply or persist across * {@link SetSchemaRequest}s. * - * @param request The schema update request. + * @param request The schema update request. * @param executor Executor on which to invoke the callback. * @param callback Callback to receive errors resulting from setting the schema. If the * operation succeeds, the callback will be invoked with {@code null}. @@ -175,6 +183,7 @@ public final class AppSearchSession implements Closeable { } try { mService.setSchema( + mPackageName, mDatabaseName, schemaBundles, new ArrayList<>(request.getSchemasNotVisibleToSystemUi()), @@ -206,6 +215,7 @@ public final class AppSearchSession implements Closeable { Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed"); try { mService.getSchema( + mPackageName, mDatabaseName, mUserId, new IAppSearchResultCallback.Stub() { @@ -261,7 +271,7 @@ public final class AppSearchSession implements Closeable { documentBundles.add(documents.get(i).getBundle()); } try { - mService.putDocuments(mDatabaseName, documentBundles, mUserId, + mService.putDocuments(mPackageName, mDatabaseName, documentBundles, mUserId, new IAppSearchBatchResultCallback.Stub() { public void onResult(AppSearchBatchResult result) { executor.execute(() -> callback.onResult(result)); @@ -280,7 +290,7 @@ public final class AppSearchSession implements Closeable { /** * Retrieves {@link GenericDocument}s by URI. * - * @param request {@link GetByUriRequest} containing URIs to be retrieved. + * @param request {@link GetByUriRequest} containing URIs to be retrieved. * @param executor Executor on which to invoke the callback. * @param callback Callback to receive the pending result of performing this operation. The keys * of the returned {@link AppSearchBatchResult} are the input URIs. The values @@ -301,7 +311,7 @@ public final class AppSearchSession implements Closeable { Objects.requireNonNull(callback); Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed"); try { - mService.getDocuments(mDatabaseName, request.getNamespace(), + mService.getDocuments(mPackageName, mDatabaseName, request.getNamespace(), new ArrayList<>(request.getUris()), mUserId, new IAppSearchBatchResultCallback.Stub() { public void onResult(AppSearchBatchResult result) { @@ -405,14 +415,14 @@ public final class AppSearchSession implements Closeable { Objects.requireNonNull(searchSpec); Objects.requireNonNull(executor); Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed"); - return new SearchResults(mService, mDatabaseName, queryExpression, searchSpec, mUserId, - executor); + return new SearchResults(mService, mPackageName, mDatabaseName, queryExpression, + searchSpec, mUserId, executor); } /** * Removes {@link GenericDocument}s from the index by URI. * - * @param request Request containing URIs to be removed. + * @param request Request containing URIs to be removed. * @param executor Executor on which to invoke the callback. * @param callback Callback to receive the pending result of performing this operation. The keys * of the returned {@link AppSearchBatchResult} are the input URIs. The values @@ -432,7 +442,7 @@ public final class AppSearchSession implements Closeable { Objects.requireNonNull(callback); Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed"); try { - mService.removeByUri(mDatabaseName, request.getNamespace(), + mService.removeByUri(mPackageName, mDatabaseName, request.getNamespace(), new ArrayList<>(request.getUris()), mUserId, new IAppSearchBatchResultCallback.Stub() { public void onResult(AppSearchBatchResult result) { @@ -478,7 +488,8 @@ public final class AppSearchSession implements Closeable { Objects.requireNonNull(callback); Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed"); try { - mService.removeByQuery(mDatabaseName, queryExpression, searchSpec.getBundle(), mUserId, + mService.removeByQuery(mPackageName, mDatabaseName, queryExpression, + searchSpec.getBundle(), mUserId, new IAppSearchResultCallback.Stub() { public void onResult(AppSearchResult result) { executor.execute(() -> callback.accept(result)); diff --git a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java index e4e030e0d18ab..6bb855480bc9a 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java +++ b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java @@ -37,16 +37,25 @@ import java.util.function.Consumer; public class GlobalSearchSession implements Closeable { private final IAppSearchManager mService; + @UserIdInt private final int mUserId; private boolean mIsClosed = false; + private final String mPackageName; + + /** + * Creates a search session for the client, defined by the {@code userId} and + * {@code packageName}. + */ static void createGlobalSearchSession( @NonNull IAppSearchManager service, @UserIdInt int userId, + @NonNull String packageName, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer> callback) { - GlobalSearchSession globalSearchSession = new GlobalSearchSession(service, userId); + GlobalSearchSession globalSearchSession = new GlobalSearchSession(service, userId, + packageName); globalSearchSession.initialize(executor, callback); } @@ -73,9 +82,11 @@ public class GlobalSearchSession implements Closeable { } } - private GlobalSearchSession(@NonNull IAppSearchManager service, @UserIdInt int userId) { + private GlobalSearchSession(@NonNull IAppSearchManager service, @UserIdInt int userId, + @NonNull String packageName) { mService = service; mUserId = userId; + mPackageName = packageName; } /** @@ -131,7 +142,7 @@ public class GlobalSearchSession implements Closeable { Objects.requireNonNull(searchSpec); Objects.requireNonNull(executor); Preconditions.checkState(!mIsClosed, "GlobalSearchSession has already been closed"); - return new SearchResults(mService, /*databaseName=*/null, queryExpression, + return new SearchResults(mService, mPackageName, /*databaseName=*/null, queryExpression, searchSpec, mUserId, executor); } diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl index 2b437774b4733..e9202cbed6a7c 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl +++ b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl @@ -30,6 +30,7 @@ interface IAppSearchManager { /** * Updates the AppSearch schema for this database. * + * @param packageName The name of the package that owns this schema. * @param databaseName The name of the database where this schema lives. * @param schemaBundles List of {@link AppSearchSchema} bundles. * @param schemasNotPlatformSurfaceable Schema types that should not be surfaced on platform @@ -43,6 +44,7 @@ interface IAppSearchManager { * {@link AppSearchResult}<{@link Void}>. */ void setSchema( + in String packageName, in String databaseName, in List schemaBundles, in List schemasNotPlatformSurfaceable, @@ -54,17 +56,23 @@ interface IAppSearchManager { /** * Retrieves the AppSearch schema for this database. * + * @param packageName The name of the package that owns the schema. * @param databaseName The name of the database to retrieve. * @param userId Id of the calling user * @param callback {@link IAppSearchResultCallback#onResult} will be called with an * {@link AppSearchResult}<{@link List}<{@link Bundle}>>, where the value are * AppSearchSchema bundle. */ - void getSchema(in String databaseName, in int userId, in IAppSearchResultCallback callback); + void getSchema( + in String packageName, + in String databaseName, + in int userId, + in IAppSearchResultCallback callback); /** * Inserts documents into the index. * + * @param packageName The name of the package that owns this document. * @param databaseName The name of the database where this document lives. * @param documentBundes List of GenericDocument bundles. * @param userId Id of the calling user @@ -76,6 +84,7 @@ interface IAppSearchManager { * where the keys are document URIs, and the values are {@code null}. */ void putDocuments( + in String packageName, in String databaseName, in List documentBundles, in int userId, @@ -84,6 +93,7 @@ interface IAppSearchManager { /** * Retrieves documents from the index. * + * @param packageName The name of the package that owns this document. * @param databaseName The databaseName this document resides in. * @param namespace The namespace this document resides in. * @param uris The URIs of the documents to retrieve @@ -96,6 +106,7 @@ interface IAppSearchManager { * where the keys are document URIs, and the values are Document bundles. */ void getDocuments( + in String packageName, in String databaseName, in String namespace, in List uris, @@ -105,6 +116,7 @@ interface IAppSearchManager { /** * Searches a document based on a given specifications. * + * @param packageName The name of the package to query over. * @param databaseName The databaseName this query for. * @param queryExpression String to search for * @param searchSpecBundle SearchSpec bundle @@ -113,6 +125,7 @@ interface IAppSearchManager { * operation. */ void query( + in String packageName, in String databaseName, in String queryExpression, in Bundle searchSpecBundle, @@ -123,6 +136,7 @@ interface IAppSearchManager { * Executes a global query, i.e. over all permitted databases, against the AppSearch index and * returns results. * + * @param packageName The name of the package making the query. * @param queryExpression String to search for * @param searchSpecBundle SearchSpec bundle * @param userId Id of the calling user @@ -130,6 +144,7 @@ interface IAppSearchManager { * operation. */ void globalQuery( + in String packageName, in String queryExpression, in Bundle searchSpecBundle, in int userId, @@ -158,6 +173,7 @@ interface IAppSearchManager { /** * Removes documents by URI. * + * @param packageName The name of the package the document is in. * @param databaseName The databaseName the document is in. * @param namespace Namespace of the document to remove. * @param uris The URIs of the documents to delete @@ -171,6 +187,7 @@ interface IAppSearchManager { * failure where the {@code throwable} is {@code null}. */ void removeByUri( + in String packageName, in String databaseName, in String namespace, in List uris, @@ -180,6 +197,7 @@ interface IAppSearchManager { /** * Removes documents by given query. * + * @param packageName The name of the package to query over. * @param databaseName The databaseName this query for. * @param queryExpression String to search for * @param searchSpecBundle SearchSpec bundle @@ -188,6 +206,7 @@ interface IAppSearchManager { * {@link AppSearchResult}<{@link Void}>. */ void removeByQuery( + in String packageName, in String databaseName, in String queryExpression, in Bundle searchSpecBundle, diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java index 0cb0ea42483e8..704509bce2a13 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java +++ b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java @@ -47,6 +47,9 @@ public class SearchResults implements Closeable { private final IAppSearchManager mService; + // The package name of the caller. + private final String mPackageName; + // The database name to search over. If null, this will search over all database names. @Nullable private final String mDatabaseName; @@ -68,12 +71,14 @@ public class SearchResults implements Closeable { SearchResults( @NonNull IAppSearchManager service, + @NonNull String packageName, @Nullable String databaseName, @NonNull String queryExpression, @NonNull SearchSpec searchSpec, @UserIdInt int userId, @NonNull @CallbackExecutor Executor executor) { mService = Objects.requireNonNull(service); + mPackageName = packageName; mDatabaseName = databaseName; mQueryExpression = Objects.requireNonNull(queryExpression); mSearchSpec = Objects.requireNonNull(searchSpec); @@ -98,13 +103,12 @@ public class SearchResults implements Closeable { mIsFirstLoad = false; if (mDatabaseName == null) { // Global query, there's no one package-database combination to check. - mService.globalQuery(mQueryExpression, mSearchSpec.getBundle(), mUserId, - wrapCallback(callback)); + mService.globalQuery(mPackageName, mQueryExpression, + mSearchSpec.getBundle(), mUserId, wrapCallback(callback)); } else { // Normal local query, pass in specified database. - mService.query( - mDatabaseName, mQueryExpression, mSearchSpec.getBundle(), mUserId, - wrapCallback(callback)); + mService.query(mPackageName, mDatabaseName, mQueryExpression, + mSearchSpec.getBundle(), mUserId, wrapCallback(callback)); } } else { mService.getNextPage(mNextPageToken, mUserId, wrapCallback(callback)); 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 1f1e9a1a28a80..87e0435bb2507 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java @@ -31,14 +31,17 @@ import android.app.appsearch.PackageIdentifier; import android.app.appsearch.SearchResultPage; import android.app.appsearch.SearchSpec; import android.content.Context; +import android.content.pm.PackageManagerInternal; import android.os.Binder; import android.os.Bundle; import android.os.ParcelableException; import android.os.RemoteException; +import android.os.UserHandle; import android.util.ArrayMap; import android.util.Log; import com.android.internal.util.Preconditions; +import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.appsearch.external.localstorage.AppSearchImpl; @@ -46,11 +49,10 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -/** - * TODO(b/142567528): add comments when implement this class - */ +/** TODO(b/142567528): add comments when implement this class */ public class AppSearchManagerService extends SystemService { private static final String TAG = "AppSearchManagerService"; + private PackageManagerInternal mPackageManagerInternal; public AppSearchManagerService(Context context) { super(context); @@ -59,11 +61,13 @@ public class AppSearchManagerService extends SystemService { @Override public void onStart() { publishBinderService(Context.APP_SEARCH_SERVICE, new Stub()); + mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); } private class Stub extends IAppSearchManager.Stub { @Override public void setSchema( + @NonNull String packageName, @NonNull String databaseName, @NonNull List schemaBundles, @NonNull List schemasNotPlatformSurfaceable, @@ -71,6 +75,7 @@ public class AppSearchManagerService extends SystemService { boolean forceOverride, @UserIdInt int userId, @NonNull IAppSearchResultCallback callback) { + Preconditions.checkNotNull(packageName); Preconditions.checkNotNull(databaseName); Preconditions.checkNotNull(schemaBundles); Preconditions.checkNotNull(callback); @@ -78,6 +83,7 @@ public class AppSearchManagerService extends SystemService { int callingUserId = handleIncomingUser(userId, callingUid); final long callingIdentity = Binder.clearCallingIdentity(); try { + verifyCallingPackage(callingUid, packageName); List schemas = new ArrayList<>(schemaBundles.size()); for (int i = 0; i < schemaBundles.size(); i++) { schemas.add(new AppSearchSchema(schemaBundles.get(i))); @@ -94,7 +100,6 @@ public class AppSearchManagerService extends SystemService { schemasPackageAccessible.put(entry.getKey(), packageIdentifiers); } AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); - String packageName = convertUidToPackageName(callingUid); impl.setSchema( packageName, databaseName, @@ -102,8 +107,8 @@ public class AppSearchManagerService extends SystemService { schemasNotPlatformSurfaceable, schemasPackageAccessible, forceOverride); - invokeCallbackOnResult(callback, - AppSearchResult.newSuccessfulResult(/*result=*/ null)); + invokeCallbackOnResult( + callback, AppSearchResult.newSuccessfulResult(/*result=*/ null)); } catch (Throwable t) { invokeCallbackOnError(callback, t); } finally { @@ -113,24 +118,26 @@ public class AppSearchManagerService extends SystemService { @Override public void getSchema( + @NonNull String packageName, @NonNull String databaseName, @UserIdInt int userId, @NonNull IAppSearchResultCallback callback) { + Preconditions.checkNotNull(packageName); Preconditions.checkNotNull(databaseName); Preconditions.checkNotNull(callback); int callingUid = Binder.getCallingUidOrThrow(); int callingUserId = handleIncomingUser(userId, callingUid); final long callingIdentity = Binder.clearCallingIdentity(); try { + verifyCallingPackage(callingUid, packageName); AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); - String packageName = convertUidToPackageName(callingUid); List schemas = impl.getSchema(packageName, databaseName); List schemaBundles = new ArrayList<>(schemas.size()); for (int i = 0; i < schemas.size(); i++) { schemaBundles.add(schemas.get(i).getBundle()); } - invokeCallbackOnResult(callback, - AppSearchResult.newSuccessfulResult(schemaBundles)); + invokeCallbackOnResult( + callback, AppSearchResult.newSuccessfulResult(schemaBundles)); } catch (Throwable t) { invokeCallbackOnError(callback, t); } finally { @@ -140,10 +147,12 @@ public class AppSearchManagerService extends SystemService { @Override public void putDocuments( + @NonNull String packageName, @NonNull String databaseName, @NonNull List documentBundles, @UserIdInt int userId, @NonNull IAppSearchBatchResultCallback callback) { + Preconditions.checkNotNull(packageName); Preconditions.checkNotNull(databaseName); Preconditions.checkNotNull(documentBundles); Preconditions.checkNotNull(callback); @@ -151,10 +160,10 @@ public class AppSearchManagerService extends SystemService { int callingUserId = handleIncomingUser(userId, callingUid); final long callingIdentity = Binder.clearCallingIdentity(); try { + verifyCallingPackage(callingUid, packageName); AppSearchBatchResult.Builder resultBuilder = new AppSearchBatchResult.Builder<>(); AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); - String packageName = convertUidToPackageName(callingUid); for (int i = 0; i < documentBundles.size(); i++) { GenericDocument document = new GenericDocument(documentBundles.get(i)); try { @@ -176,11 +185,13 @@ public class AppSearchManagerService extends SystemService { @Override public void getDocuments( + @NonNull String packageName, @NonNull String databaseName, @NonNull String namespace, @NonNull List uris, @UserIdInt int userId, @NonNull IAppSearchBatchResultCallback callback) { + Preconditions.checkNotNull(packageName); Preconditions.checkNotNull(databaseName); Preconditions.checkNotNull(namespace); Preconditions.checkNotNull(uris); @@ -189,15 +200,15 @@ public class AppSearchManagerService extends SystemService { int callingUserId = handleIncomingUser(userId, callingUid); final long callingIdentity = Binder.clearCallingIdentity(); try { + verifyCallingPackage(callingUid, packageName); AppSearchBatchResult.Builder resultBuilder = new AppSearchBatchResult.Builder<>(); AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); - String packageName = convertUidToPackageName(callingUid); for (int i = 0; i < uris.size(); i++) { String uri = uris.get(i); try { - GenericDocument document = impl.getDocument(packageName, databaseName, - namespace, uri); + GenericDocument document = + impl.getDocument(packageName, databaseName, namespace, uri); resultBuilder.setSuccess(uri, document.getBundle()); } catch (Throwable t) { resultBuilder.setResult(uri, throwableToFailedResult(t)); @@ -214,11 +225,13 @@ public class AppSearchManagerService extends SystemService { // TODO(sidchhabra): Do this in a threadpool. @Override public void query( + @NonNull String packageName, @NonNull String databaseName, @NonNull String queryExpression, @NonNull Bundle searchSpecBundle, @UserIdInt int userId, @NonNull IAppSearchResultCallback callback) { + Preconditions.checkNotNull(packageName); Preconditions.checkNotNull(databaseName); Preconditions.checkNotNull(queryExpression); Preconditions.checkNotNull(searchSpecBundle); @@ -227,14 +240,16 @@ public class AppSearchManagerService extends SystemService { int callingUserId = handleIncomingUser(userId, callingUid); final long callingIdentity = Binder.clearCallingIdentity(); try { + verifyCallingPackage(callingUid, packageName); AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); - String packageName = convertUidToPackageName(callingUid); - SearchResultPage searchResultPage = impl.query( - packageName, - databaseName, - queryExpression, - new SearchSpec(searchSpecBundle)); - invokeCallbackOnResult(callback, + SearchResultPage searchResultPage = + impl.query( + packageName, + databaseName, + queryExpression, + new SearchSpec(searchSpecBundle)); + invokeCallbackOnResult( + callback, AppSearchResult.newSuccessfulResult(searchResultPage.getBundle())); } catch (Throwable t) { invokeCallbackOnError(callback, t); @@ -245,10 +260,12 @@ public class AppSearchManagerService extends SystemService { @Override public void globalQuery( + @NonNull String packageName, @NonNull String queryExpression, @NonNull Bundle searchSpecBundle, @UserIdInt int userId, @NonNull IAppSearchResultCallback callback) { + Preconditions.checkNotNull(packageName); Preconditions.checkNotNull(queryExpression); Preconditions.checkNotNull(searchSpecBundle); Preconditions.checkNotNull(callback); @@ -256,11 +273,12 @@ public class AppSearchManagerService extends SystemService { int callingUserId = handleIncomingUser(userId, callingUid); final long callingIdentity = Binder.clearCallingIdentity(); try { + verifyCallingPackage(callingUid, packageName); AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); - SearchResultPage searchResultPage = impl.globalQuery( - queryExpression, - new SearchSpec(searchSpecBundle)); - invokeCallbackOnResult(callback, + SearchResultPage searchResultPage = + impl.globalQuery(queryExpression, new SearchSpec(searchSpecBundle)); + invokeCallbackOnResult( + callback, AppSearchResult.newSuccessfulResult(searchResultPage.getBundle())); } catch (Throwable t) { invokeCallbackOnError(callback, t); @@ -270,7 +288,9 @@ public class AppSearchManagerService extends SystemService { } @Override - public void getNextPage(long nextPageToken, @UserIdInt int userId, + public void getNextPage( + long nextPageToken, + @UserIdInt int userId, @NonNull IAppSearchResultCallback callback) { Preconditions.checkNotNull(callback); int callingUid = Binder.getCallingUid(); @@ -281,7 +301,8 @@ public class AppSearchManagerService extends SystemService { try { AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); SearchResultPage searchResultPage = impl.getNextPage(nextPageToken); - invokeCallbackOnResult(callback, + invokeCallbackOnResult( + callback, AppSearchResult.newSuccessfulResult(searchResultPage.getBundle())); } catch (Throwable t) { invokeCallbackOnError(callback, t); @@ -307,11 +328,13 @@ public class AppSearchManagerService extends SystemService { @Override public void removeByUri( + @NonNull String packageName, @NonNull String databaseName, @NonNull String namespace, @NonNull List uris, @UserIdInt int userId, @NonNull IAppSearchBatchResultCallback callback) { + Preconditions.checkNotNull(packageName); Preconditions.checkNotNull(databaseName); Preconditions.checkNotNull(uris); Preconditions.checkNotNull(callback); @@ -319,15 +342,15 @@ public class AppSearchManagerService extends SystemService { int callingUserId = handleIncomingUser(userId, callingUid); final long callingIdentity = Binder.clearCallingIdentity(); try { + verifyCallingPackage(callingUid, packageName); AppSearchBatchResult.Builder resultBuilder = new AppSearchBatchResult.Builder<>(); AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); - String packageName = convertUidToPackageName(callingUid); for (int i = 0; i < uris.size(); i++) { String uri = uris.get(i); try { impl.remove(packageName, databaseName, namespace, uri); - resultBuilder.setSuccess(uri, /*result= */null); + resultBuilder.setSuccess(uri, /*result= */ null); } catch (Throwable t) { resultBuilder.setResult(uri, throwableToFailedResult(t)); } @@ -342,11 +365,13 @@ public class AppSearchManagerService extends SystemService { @Override public void removeByQuery( + @NonNull String packageName, @NonNull String databaseName, @NonNull String queryExpression, @NonNull Bundle searchSpecBundle, @UserIdInt int userId, @NonNull IAppSearchResultCallback callback) { + Preconditions.checkNotNull(packageName); Preconditions.checkNotNull(databaseName); Preconditions.checkNotNull(queryExpression); Preconditions.checkNotNull(searchSpecBundle); @@ -355,9 +380,12 @@ public class AppSearchManagerService extends SystemService { int callingUserId = handleIncomingUser(userId, callingUid); final long callingIdentity = Binder.clearCallingIdentity(); try { + verifyCallingPackage(callingUid, packageName); AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); - String packageName = convertUidToPackageName(callingUid); - impl.removeByQuery(packageName, databaseName, queryExpression, + impl.removeByQuery( + packageName, + databaseName, + queryExpression, new SearchSpec(searchSpecBundle)); invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null)); } catch (Throwable t) { @@ -398,28 +426,22 @@ public class AppSearchManagerService extends SystemService { } } - /** - * Returns a package name for the given uid. - * - *

The current implementation returns the package name of the app with this uid in a - * format like {@code com.example.package} or {@code com.example.sharedname:5678}. - */ - @NonNull - private String convertUidToPackageName(int callingUid) { - // For regular apps, this call will return the package name. If callingUid is an - // android:sharedUserId, this value may be another type of name and have a :uid suffix. - String callingUidName = getContext().getPackageManager().getNameForUid(callingUid); - if (callingUidName == null) { - // Not sure how this is possible --- maybe app was uninstalled? - throw new IllegalStateException( - "Failed to look up package name for uid " + callingUid); + private void verifyCallingPackage(int callingUid, @NonNull String callingPackage) { + Preconditions.checkNotNull(callingPackage); + if (mPackageManagerInternal.getPackageUid( + callingPackage, /*flags=*/ 0, UserHandle.getUserId(callingUid)) + != callingUid) { + throw new SecurityException( + "Specified calling package [" + + callingPackage + + "] does not match the calling uid " + + callingUid); } - return callingUidName; } /** Invokes the {@link IAppSearchResultCallback} with the result. */ - private void invokeCallbackOnResult(IAppSearchResultCallback callback, - AppSearchResult result) { + private void invokeCallbackOnResult( + IAppSearchResultCallback callback, AppSearchResult result) { try { callback.onResult(result); } catch (RemoteException e) { @@ -428,8 +450,8 @@ public class AppSearchManagerService extends SystemService { } /** Invokes the {@link IAppSearchBatchResultCallback} with the result. */ - private void invokeCallbackOnResult(IAppSearchBatchResultCallback callback, - AppSearchBatchResult result) { + private void invokeCallbackOnResult( + IAppSearchBatchResultCallback callback, AppSearchBatchResult result) { try { callback.onResult(result); } catch (RemoteException e) { @@ -455,8 +477,8 @@ public class AppSearchManagerService extends SystemService { * *

The throwable is converted to {@link ParcelableException}. */ - private void invokeCallbackOnError(IAppSearchBatchResultCallback callback, - Throwable throwable) { + private void invokeCallbackOnError( + IAppSearchBatchResultCallback callback, Throwable throwable) { try { callback.onSystemError(new ParcelableException(throwable)); } catch (RemoteException e) { @@ -465,13 +487,18 @@ public class AppSearchManagerService extends SystemService { } } - //TODO(b/173553485) verifying that the caller has permission to access target user's data - //TODO(b/173553485) Handle ACTION_USER_REMOVED broadcast - //TODO(b/173553485) Implement SystemService.onUserStopping() + // TODO(b/173553485) verifying that the caller has permission to access target user's data + // TODO(b/173553485) Handle ACTION_USER_REMOVED broadcast + // TODO(b/173553485) Implement SystemService.onUserStopping() private static int handleIncomingUser(@UserIdInt int userId, int callingUid) { int callingPid = Binder.getCallingPid(); - return ActivityManager.handleIncomingUser(callingPid, callingUid, userId, - /*allowAll=*/ false, /*requireFull=*/ false, - /*name=*/ null, /*callerPackage=*/ null); + return ActivityManager.handleIncomingUser( + callingPid, + callingUid, + userId, + /*allowAll=*/ false, + /*requireFull=*/ false, + /*name=*/ null, + /*callerPackage=*/ null); } }