Merge "Pass package name across binder."

This commit is contained in:
Cassie Wang
2021-01-20 22:36:52 +00:00
committed by Android (Google) Code Review
6 changed files with 275 additions and 181 deletions

View File

@@ -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.
*
* <p>Databases with different names are fully separate with distinct types, namespaces,
* and data.
* <p>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}&lt;{@link AppSearchSession}&gt; 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}&lt;{@link AppSearchSession}&gt; 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 {
* <p>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}&lt;{@link GlobalSearchSession}&gt; 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}&lt;{@link GlobalSearchSession}&gt; 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:
*
* <ul>
* <li>Addition of new types
* <li>Addition of new
* {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL
* OPTIONAL} or
* {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED
* REPEATED} properties to a type
* <li>Changing the cardinality of a data type to be less restrictive (e.g. changing an
* {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL
* OPTIONAL} property into a
* {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED
* REPEATED} property.
* <li>Addition of new types
* <li>Addition of new {@link
* android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} or
* {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED
* REPEATED} properties to a type
* <li>Changing the cardinality of a data type to be less restrictive (e.g. changing an {@link
* android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL}
* property into a {@link
* android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED}
* property.
* </ul>
*
* <p>The following types of schema changes are not backwards-compatible:
*
* <ul>
* <li>Removal of an existing type
* <li>Removal of a property from a type
* <li>Changing the data type ({@code boolean}, {@code long}, etc.) of an existing property
* <li>For properties of {@code GenericDocument} type, changing the schema type of
* {@code GenericDocument}s of that property
* <li>Changing the cardinality of a data type to be more restrictive (e.g. changing an
* {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL
* OPTIONAL} property into a
* {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED
* REQUIRED} property).
* <li>Adding a
* {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED
* REQUIRED} property.
* <li>Removal of an existing type
* <li>Removal of a property from a type
* <li>Changing the data type ({@code boolean}, {@code long}, etc.) of an existing property
* <li>For properties of {@code GenericDocument} type, changing the schema type of {@code
* GenericDocument}s of that property
* <li>Changing the cardinality of a data type to be more restrictive (e.g. changing an {@link
* android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL}
* property into a {@link
* android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED}
* property).
* <li>Adding a {@link
* android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED}
* property.
* </ul>
* <p>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.
*
* <p>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.
*
* <p>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<Void> setSchema(@NonNull SetSchemaRequest request) {
@@ -229,6 +237,7 @@ public class AppSearchManager {
AndroidFuture<AppSearchResult> 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.
*
* <p>You should not call this method directly; instead, use the
* {@code AppSearch#putDocuments()} API provided by JetPack.
* <p>You should not call this method directly; instead, use the {@code
* AppSearch#putDocuments()} API provided by JetPack.
*
* <p>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<String, Void> 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<AppSearchBatchResult> 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.
*
* <p>You should not call this method directly; instead, use the
* {@code AppSearch#getDocuments()} API provided by JetPack.
* <p>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<String, GenericDocument> getByUri(
@NonNull GetByUriRequest request) {
@@ -315,7 +325,11 @@ public class AppSearchManager {
List<String> uris = new ArrayList<>(request.getUris());
AndroidFuture<AppSearchBatchResult> 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.
*
* <p>Currently we support following features in the raw query format:
*
* <ul>
* <li>AND
* <p>AND joins (e.g. “match documents that have both the terms dog and
* cat”).
* Example: hello world matches documents that have both hello and world
* <li>OR
* <p>OR joins (e.g. “match documents that have either the term dog or
* cat”).
* Example: dog OR puppy
* <li>Exclusion
* <p>Exclude a term (e.g. “match documents that do
* not have the term dog”).
* Example: -dog excludes the term dog
* <li>Grouping terms
* <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g.
* “match documents that have either dog or puppy, and either cat or kitten”).
* Example: (dog puppy) (cat kitten) two one group containing two terms.
* <li>Property restricts
* <p> Specifies which properties of a document to specifically match terms in (e.g.
* “match documents where the subject property contains important”).
* Example: subject:important matches documents with the term important in the
* subject property
* <li>Schema type restricts
* <p>This is similar to property restricts, but allows for restricts on top-level document
* fields, such as schema_type. Clients should be able to limit their query to documents of
* a certain schema_type (e.g. “match documents that are of the Email schema_type”).
* Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will match documents
* that contain the query term dog and are of either the Email schema type or the
* Video schema type.
* <li>AND
* <p>AND joins (e.g. “match documents that have both the terms dog and cat”).
* Example: hello world matches documents that have both hello and world
* <li>OR
* <p>OR joins (e.g. “match documents that have either the term dog or cat”). Example:
* dog OR puppy
* <li>Exclusion
* <p>Exclude a term (e.g. “match documents that do not have the term dog”). Example:
* -dog excludes the term dog
* <li>Grouping terms
* <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g.
* “match documents that have either dog or puppy, and either cat or kitten”).
* Example: (dog puppy) (cat kitten) two one group containing two terms.
* <li>Property restricts
* <p>Specifies which properties of a document to specifically match terms in (e.g. “match
* documents where the subject property contains important”). Example:
* subject:important matches documents with the term important in the subject property
* <li>Schema type restricts
* <p>This is similar to property restricts, but allows for restricts on top-level
* document fields, such as schema_type. Clients should be able to limit their query to
* documents of a certain schema_type (e.g. “match documents that are of the Email
* schema_type”). Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will
* match documents that contain the query term dog and are of either the Email schema
* type or the Video schema type.
* </ul>
*
* @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<List<SearchResult>> query(
@@ -416,7 +426,11 @@ public class AppSearchManager {
// them in one big list.
AndroidFuture<AppSearchResult> 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<Bundle> 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<String, Void> removeByUri(@NonNull RemoveByUriRequest request) {
List<String> uris = new ArrayList<>(request.getUris());
AndroidFuture<AppSearchBatchResult> 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> T getFutureOrThrow(@NonNull AndroidFuture<T> future) {
try {
return future.get();

View File

@@ -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<AppSearchResult<AppSearchSession>> 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));

View File

@@ -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<AppSearchResult<GlobalSearchSession>> 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);
}

View File

@@ -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}&lt;{@link Void}&gt;.
*/
void setSchema(
in String packageName,
in String databaseName,
in List<Bundle> schemaBundles,
in List<String> 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}&lt;{@link List}&lt;{@link Bundle}&gt;&gt;, 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<Bundle> 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<String> 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<String> 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}&lt;{@link Void}&gt;.
*/
void removeByQuery(
in String packageName,
in String databaseName,
in String queryExpression,
in Bundle searchSpecBundle,

View File

@@ -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));

View File

@@ -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<Bundle> schemaBundles,
@NonNull List<String> 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<AppSearchSchema> 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<AppSearchSchema> schemas = impl.getSchema(packageName, databaseName);
List<Bundle> 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<Bundle> 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<String, Void> 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<String> 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<String, Bundle> 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<String> 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<String, Void> 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.
*
* <p>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 {
*
* <p>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);
}
}