Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 779b7ceb authored by Alexander Dorokhine's avatar Alexander Dorokhine
Browse files

Sync platform from Jetpack.

Included changes:
* caf5d9: Add a uri prefix to visibility store documents.
* 5b26a8: Minor comment fix in AppSearchSession
* 31b691: Add package visibility APIs for schema types.
* d36a2c: Require a package name in AppSearchImpl.

Bug: 169883602
Bug: 162450968
Test: Presubmit
Change-Id: I155145e4b14a271f3012cb7b5efbbe1b7ba27a18
parent 7cb30de8
Loading
Loading
Loading
Loading
+61 −0
Original line number Diff line number Diff line
/*
 * Copyright 2020 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 android.app.appsearch;

import android.annotation.NonNull;

import java.util.Arrays;
import java.util.Objects;

/**
 * This class represents a uniquely identifiable package.
 *
 * @hide
 */
public class PackageIdentifier {
    public final String packageName;
    public final byte[] certificate;

    /**
     * Creates a unique identifier for a package.
     *
     * @param packageName Name of the package.
     * @param certificate SHA256 certificate digest of the package.
     */
    public PackageIdentifier(@NonNull String packageName, @NonNull byte[] certificate) {
        this.packageName = packageName;
        this.certificate = certificate;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || !(obj instanceof PackageIdentifier)) {
            return false;
        }
        final PackageIdentifier other = (PackageIdentifier) obj;
        return this.packageName.equals(other.packageName)
                && Arrays.equals(this.certificate, other.certificate);
    }

    @Override
    public int hashCode() {
        return Objects.hash(packageName, Arrays.hashCode(certificate));
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -46,7 +46,7 @@ public final class RemoveByUriRequest {
        return mNamespace;
    }

    /** Returns the URIs to remove from the namespace. */
    /** Returns the URIs of documents to remove from the namespace. */
    @NonNull
    public Set<String> getUris() {
        return Collections.unmodifiableSet(mUris);
+91 −18
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.app.appsearch;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.app.appsearch.exceptions.AppSearchException;
import android.util.ArrayMap;
import android.util.ArraySet;

import com.android.internal.util.Preconditions;
@@ -28,6 +29,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
@@ -38,14 +40,17 @@ import java.util.Set;
public final class SetSchemaRequest {
    private final Set<AppSearchSchema> mSchemas;
    private final Set<String> mSchemasNotPlatformSurfaceable;
    private final Map<String, Set<PackageIdentifier>> mSchemasPackageAccessible;
    private final boolean mForceOverride;

    SetSchemaRequest(
            @NonNull Set<AppSearchSchema> schemas,
            @NonNull Set<String> schemasNotPlatformSurfaceable,
            @NonNull Map<String, Set<PackageIdentifier>> schemasPackageAccessible,
            boolean forceOverride) {
        mSchemas = Preconditions.checkNotNull(schemas);
        mSchemasNotPlatformSurfaceable = Preconditions.checkNotNull(schemasNotPlatformSurfaceable);
        mSchemasPackageAccessible = Preconditions.checkNotNull(schemasPackageAccessible);
        mForceOverride = forceOverride;
    }

@@ -65,6 +70,39 @@ public final class SetSchemaRequest {
        return Collections.unmodifiableSet(mSchemasNotPlatformSurfaceable);
    }

    /**
     * Returns a mapping of schema types to the set of packages that have access to that schema
     * type. Each package is represented by a {@link PackageIdentifier}. name and byte[]
     * certificate.
     *
     * <p>This method is inefficient to call repeatedly.
     *
     * @hide
     */
    @NonNull
    public Map<String, Set<PackageIdentifier>> getSchemasPackageAccessible() {
        Map<String, Set<PackageIdentifier>> copy = new ArrayMap<>();
        for (String key : mSchemasPackageAccessible.keySet()) {
            copy.put(key, new ArraySet<>(mSchemasPackageAccessible.get(key)));
        }
        return copy;
    }

    /**
     * Returns a mapping of schema types to the set of packages that have access to that schema
     * type. Each package is represented by a {@link PackageIdentifier}. name and byte[]
     * certificate.
     *
     * <p>A more efficient version of {@code #getSchemasPackageAccessible}, but it returns a
     * modifiable map. This is not meant to be unhidden and should only be used by internal classes.
     *
     * @hide
     */
    @NonNull
    public Map<String, Set<PackageIdentifier>> getSchemasPackageAccessibleInternal() {
        return mSchemasPackageAccessible;
    }

    /** Returns whether this request will force the schema to be overridden. */
    public boolean isForceOverride() {
        return mForceOverride;
@@ -74,6 +112,8 @@ public final class SetSchemaRequest {
    public static final class Builder {
        private final Set<AppSearchSchema> mSchemas = new ArraySet<>();
        private final Set<String> mSchemasNotPlatformSurfaceable = new ArraySet<>();
        private final Map<String, Set<PackageIdentifier>> mSchemasPackageAccessible =
                new ArrayMap<>();
        private boolean mForceOverride = false;
        private boolean mBuilt = false;

@@ -102,32 +142,62 @@ public final class SetSchemaRequest {
        }

        /**
         * Sets visibility on system UI surfaces for schema types.
         * Sets visibility on system UI surfaces for the given {@code schemaType}.
         *
         * @param schemaType The schema type to set visibility on.
         * @param visible Whether the {@code schemaType} will be visible or not.
         * @hide
         */
        @NonNull
        public Builder setSchemaTypeVisibilityForSystemUi(
                boolean visible, @NonNull String... schemaTypes) {
            Preconditions.checkNotNull(schemaTypes);
            return this.setSchemaTypeVisibilityForSystemUi(visible, Arrays.asList(schemaTypes));
                @NonNull String schemaType, boolean visible) {
            Preconditions.checkNotNull(schemaType);
            Preconditions.checkState(!mBuilt, "Builder has already been used");

            if (visible) {
                mSchemasNotPlatformSurfaceable.remove(schemaType);
            } else {
                mSchemasNotPlatformSurfaceable.add(schemaType);
            }
            return this;
        }

        /**
         * Sets visibility on system UI surfaces for schema types.
         * Sets visibility for a package for the given {@code schemaType}.
         *
         * @param schemaType The schema type to set visibility on.
         * @param visible Whether the {@code schemaType} will be visible or not.
         * @param packageIdentifier Represents the package that will be granted visibility.
         * @hide
         */
        @NonNull
        public Builder setSchemaTypeVisibilityForSystemUi(
                boolean visible, @NonNull Collection<String> schemaTypes) {
        public Builder setSchemaTypeVisibilityForPackage(
                @NonNull String schemaType,
                boolean visible,
                @NonNull PackageIdentifier packageIdentifier) {
            Preconditions.checkNotNull(schemaType);
            Preconditions.checkNotNull(packageIdentifier);
            Preconditions.checkState(!mBuilt, "Builder has already been used");
            Preconditions.checkNotNull(schemaTypes);

            Set<PackageIdentifier> packageIdentifiers = mSchemasPackageAccessible.get(schemaType);
            if (visible) {
                mSchemasNotPlatformSurfaceable.removeAll(schemaTypes);
                if (packageIdentifiers == null) {
                    packageIdentifiers = new ArraySet<>();
                }
                packageIdentifiers.add(packageIdentifier);
                mSchemasPackageAccessible.put(schemaType, packageIdentifiers);
            } else {
                mSchemasNotPlatformSurfaceable.addAll(schemaTypes);
                if (packageIdentifiers == null) {
                    // Return early since there was nothing set to begin with.
                    return this;
                }
                packageIdentifiers.remove(packageIdentifier);
                if (packageIdentifiers.isEmpty()) {
                    // Remove the entire key so that we don't have empty sets as values.
                    mSchemasPackageAccessible.remove(schemaType);
                }
            }

            return this;
        }

@@ -159,21 +229,24 @@ public final class SetSchemaRequest {

            // Verify that any schema types with visibility settings refer to a real schema.
            // Create a copy because we're going to remove from the set for verification purposes.
            Set<String> schemasNotPlatformSurfaceableCopy =
                    new ArraySet<>(mSchemasNotPlatformSurfaceable);
            Set<String> referencedSchemas = new ArraySet<>(mSchemasNotPlatformSurfaceable);
            referencedSchemas.addAll(mSchemasPackageAccessible.keySet());

            for (AppSearchSchema schema : mSchemas) {
                schemasNotPlatformSurfaceableCopy.remove(schema.getSchemaType());
                referencedSchemas.remove(schema.getSchemaType());
            }
            if (!schemasNotPlatformSurfaceableCopy.isEmpty()) {
            if (!referencedSchemas.isEmpty()) {
                // We still have schema types that weren't seen in our mSchemas set. This means
                // there wasn't a corresponding AppSearchSchema.
                throw new IllegalArgumentException(
                        "Schema types "
                                + schemasNotPlatformSurfaceableCopy
                                + " referenced, but were not added.");
                        "Schema types " + referencedSchemas + " referenced, but were not added.");
            }

            return new SetSchemaRequest(mSchemas, mSchemasNotPlatformSurfaceable, mForceOverride);
            return new SetSchemaRequest(
                    mSchemas,
                    mSchemasNotPlatformSurfaceable,
                    mSchemasPackageAccessible,
                    mForceOverride);
        }
    }
}
+28 −26
Original line number Diff line number Diff line
@@ -47,7 +47,6 @@ import java.util.List;
 */
public class AppSearchManagerService extends SystemService {
    private static final String TAG = "AppSearchManagerService";
    private static final char CALLING_NAME_DATABASE_DELIMITER = '$';

    public AppSearchManagerService(Context context) {
        super(context);
@@ -78,8 +77,9 @@ public class AppSearchManagerService extends SystemService {
                    schemas.add(new AppSearchSchema(schemaBundles.get(i)));
                }
                AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
                databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
                impl.setSchema(databaseName, schemas, schemasNotPlatformSurfaceable, forceOverride);
                String packageName = convertUidToPackageName(callingUid);
                impl.setSchema(packageName, databaseName, schemas, schemasNotPlatformSurfaceable,
                        forceOverride);
                invokeCallbackOnResult(callback,
                        AppSearchResult.newSuccessfulResult(/*result=*/ null));
            } catch (Throwable t) {
@@ -100,8 +100,8 @@ public class AppSearchManagerService extends SystemService {
            final long callingIdentity = Binder.clearCallingIdentity();
            try {
                AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
                databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
                List<AppSearchSchema> schemas = impl.getSchema(databaseName);
                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());
@@ -130,13 +130,13 @@ public class AppSearchManagerService extends SystemService {
                AppSearchBatchResult.Builder<String, Void> resultBuilder =
                        new AppSearchBatchResult.Builder<>();
                AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
                databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
                String packageName = convertUidToPackageName(callingUid);
                for (int i = 0; i < documentBundles.size(); i++) {
                    GenericDocument document = new GenericDocument(documentBundles.get(i));
                    try {
                        // TODO(b/173451571): reduce burden of binder thread by enqueue request onto
                        // a separate thread.
                        impl.putDocument(databaseName, document);
                        impl.putDocument(packageName, databaseName, document);
                        resultBuilder.setSuccess(document.getUri(), /*result=*/ null);
                    } catch (Throwable t) {
                        resultBuilder.setResult(document.getUri(), throwableToFailedResult(t));
@@ -165,11 +165,12 @@ public class AppSearchManagerService extends SystemService {
                AppSearchBatchResult.Builder<String, Bundle> resultBuilder =
                        new AppSearchBatchResult.Builder<>();
                AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
                databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
                String packageName = convertUidToPackageName(callingUid);
                for (int i = 0; i < uris.size(); i++) {
                    String uri = uris.get(i);
                    try {
                        GenericDocument document = impl.getDocument(databaseName, namespace, uri);
                        GenericDocument document = impl.getDocument(packageName, databaseName,
                                namespace, uri);
                        resultBuilder.setSuccess(uri, document.getBundle());
                    } catch (Throwable t) {
                        resultBuilder.setResult(uri, throwableToFailedResult(t));
@@ -199,8 +200,9 @@ public class AppSearchManagerService extends SystemService {
            final long callingIdentity = Binder.clearCallingIdentity();
            try {
                AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
                databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
                String packageName = convertUidToPackageName(callingUid);
                SearchResultPage searchResultPage = impl.query(
                        packageName,
                        databaseName,
                        queryExpression,
                        new SearchSpec(searchSpecBundle));
@@ -283,15 +285,15 @@ public class AppSearchManagerService extends SystemService {
            int callingUid = Binder.getCallingUidOrThrow();
            int callingUserId = UserHandle.getUserId(callingUid);
            final long callingIdentity = Binder.clearCallingIdentity();
            try {
                AppSearchBatchResult.Builder<String, Void> resultBuilder =
                        new AppSearchBatchResult.Builder<>();
            try {
                AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
                databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
                String packageName = convertUidToPackageName(callingUid);
                for (int i = 0; i < uris.size(); i++) {
                    String uri = uris.get(i);
                    try {
                        impl.remove(databaseName, namespace, uri);
                        impl.remove(packageName, databaseName, namespace, uri);
                        resultBuilder.setSuccess(uri, /*result= */null);
                    } catch (Throwable t) {
                        resultBuilder.setResult(uri, throwableToFailedResult(t));
@@ -320,8 +322,8 @@ public class AppSearchManagerService extends SystemService {
            final long callingIdentity = Binder.clearCallingIdentity();
            try {
                AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
                databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
                impl.removeByQuery(databaseName, queryExpression,
                String packageName = convertUidToPackageName(callingUid);
                impl.removeByQuery(packageName, databaseName, queryExpression,
                        new SearchSpec(searchSpecBundle));
                invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
            } catch (Throwable t) {
@@ -348,13 +350,13 @@ public class AppSearchManagerService extends SystemService {
        }

        /**
         * Rewrites the database name by adding a prefix of unique name for the given uid.
         * 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 rewriteDatabaseNameWithUid(String databaseName, int callingUid) {
        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);
@@ -363,12 +365,12 @@ public class AppSearchManagerService extends SystemService {
                throw new IllegalStateException(
                        "Failed to look up package name for uid " + callingUid);
            }
            return callingUidName + CALLING_NAME_DATABASE_DELIMITER + databaseName;
            return callingUidName;
        }

        /** Invokes the {@link IAppSearchResultCallback} with the result. */
        private void invokeCallbackOnResult(IAppSearchResultCallback callback,
                AppSearchResult result) {
                AppSearchResult<?> result) {
            try {
                callback.onResult(result);
            } catch (RemoteException e) {
@@ -378,7 +380,7 @@ public class AppSearchManagerService extends SystemService {

        /** Invokes the {@link IAppSearchBatchResultCallback} with the result. */
        private void invokeCallbackOnResult(IAppSearchBatchResultCallback callback,
                AppSearchBatchResult result) {
                AppSearchBatchResult<?, ?> result) {
            try {
                callback.onResult(result);
            } catch (RemoteException e) {
@@ -400,7 +402,7 @@ public class AppSearchManagerService extends SystemService {
        }

        /**
         *  Invokes the {@link IAppSearchBatchResultCallback} with an throwable.
         * Invokes the {@link IAppSearchBatchResultCallback} with an unexpected internal throwable.
         *
         * <p>The throwable is converted to {@link ParcelableException}.
         */
+156 −128

File changed.

Preview size limit exceeded, changes collapsed.

Loading