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

Commit 533aeaad authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 7243396 from c3f2588f to sc-release

Change-Id: I90061afd265686b56a08de109f731ca8e02ca65e
parents d1d45f85 c3f2588f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -424,6 +424,7 @@ filegroup {
        ":libbluetooth-binder-aidl",
        ":libcamera_client_aidl",
        ":libcamera_client_framework_aidl",
        ":packagemanager_aidl",
        ":libupdate_engine_aidl",
        ":resourcemanager_aidl",
        ":storaged_aidl",
+129 −125
Original line number Diff line number Diff line
@@ -32,13 +32,11 @@ import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.Preconditions;

import java.io.Closeable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.function.Consumer;

@@ -158,68 +156,16 @@ public final class AppSearchSession implements Closeable {
                    schemasPackageAccessibleBundles,
                    callbackExecutor,
                    callback);
            return;
        }

        try {
            // Migration process
            // 1. Generate the current and the final version map.
            // TODO(b/182855402) Release binder thread and move the heavy work into worker thread.
            AndroidFuture<AppSearchResult<GetSchemaResponse>> future = new AndroidFuture<>();
            getSchema(callbackExecutor, future::complete);
            AppSearchResult<GetSchemaResponse> getSchemaResult = future.get();
            if (!getSchemaResult.isSuccess()) {
                callback.accept(AppSearchResult.newFailedResult(getSchemaResult));
                return;
            }
            GetSchemaResponse getSchemaResponse = getSchemaResult.getResultValue();
            Set<AppSearchSchema> currentSchemas = getSchemaResponse.getSchemas();
            Map<String, Integer> currentVersionMap =
                    SchemaMigrationUtil.buildVersionMap(currentSchemas,
                            getSchemaResponse.getVersion());
            Map<String, Integer> finalVersionMap =
                    SchemaMigrationUtil.buildVersionMap(request.getSchemas(), request.getVersion());

            // 2. SetSchema with forceOverride=false, to retrieve the list of incompatible/deleted
            // types.
            mService.setSchema(
                    mPackageName,
                    mDatabaseName,
        } else {
            setSchemaWithMigrations(
                    request,
                    schemaBundles,
                    new ArrayList<>(request.getSchemasNotDisplayedBySystem()),
                    schemasPackageAccessibleBundles,
                    /*forceOverride=*/ false,
                    mUserId,
                    request.getVersion(),
                    new IAppSearchResultCallback.Stub() {
                        public void onResult(AppSearchResult result) {
                            callbackExecutor.execute(() -> {
                                if (result.isSuccess()) {
                                    // TODO(b/183177268): once migration is implemented, run
                                    //  it on workExecutor.
                                    try {
                                        Bundle bundle = (Bundle) result.getResultValue();
                                        SetSchemaResponse setSchemaResponse =
                                                new SetSchemaResponse(bundle);
                                        setSchemaMigration(
                                                request, setSchemaResponse, schemaBundles,
                                                schemasPackageAccessibleBundles, currentVersionMap,
                                                finalVersionMap, callback);
                                    } catch (Throwable t) {
                                        callback.accept(AppSearchResult.throwableToFailedResult(t));
                                    }
                                } else {
                                    callback.accept(result);
                                }
                            });
                    workExecutor,
                    callbackExecutor,
                    callback);
        }
                    });
        mIsMutated = true;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }  catch (Throwable t) {
            callback.accept(AppSearchResult.throwableToFailedResult(t));
        }
    }

    /**
@@ -667,7 +613,8 @@ public final class AppSearchSession implements Closeable {
     * <p>We only need one time {@link #setSchema} call for no-migration scenario by using the
     * forceoverride in the request.
     */
    private void setSchemaNoMigrations(@NonNull SetSchemaRequest request,
    private void setSchemaNoMigrations(
            @NonNull SetSchemaRequest request,
            @NonNull List<Bundle> schemaBundles,
            @NonNull Map<String, List<Bundle>> schemasPackageAccessibleBundles,
            @NonNull @CallbackExecutor Executor executor,
@@ -709,7 +656,6 @@ public final class AppSearchSession implements Closeable {
                            });
                        }
                    });
            mIsMutated = true;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -721,41 +667,88 @@ public final class AppSearchSession implements Closeable {
     * <p>First time {@link #setSchema} call with forceOverride is false gives us all incompatible
     * changes. After trigger migrations, the second time call {@link #setSchema} will actually
     * apply the changes.
     *
     * @param setSchemaResponse the result of the first setSchema call with forceOverride=false.
     */
    private void setSchemaMigration(@NonNull SetSchemaRequest request,
            @NonNull SetSchemaResponse setSchemaResponse,
    private void setSchemaWithMigrations(
            @NonNull SetSchemaRequest request,
            @NonNull List<Bundle> schemaBundles,
            @NonNull Map<String, List<Bundle>> schemasPackageAccessibleBundles,
            @NonNull Map<String, Integer> currentVersionMap, Map<String, Integer> finalVersionMap,
            @NonNull Consumer<AppSearchResult<SetSchemaResponse>> callback)
            throws AppSearchException, IOException, RemoteException, ExecutionException,
            InterruptedException {
            @NonNull Executor workExecutor,
            @NonNull @CallbackExecutor Executor callbackExecutor,
            @NonNull Consumer<AppSearchResult<SetSchemaResponse>> callback) {
        workExecutor.execute(() -> {
            try {
                // Migration process
                // 1. Generate the current and the final version map.
                AndroidFuture<AppSearchResult<GetSchemaResponse>> getSchemaFuture =
                        new AndroidFuture<>();
                getSchema(callbackExecutor, getSchemaFuture::complete);
                AppSearchResult<GetSchemaResponse> getSchemaResult = getSchemaFuture.get();
                if (!getSchemaResult.isSuccess()) {
                    callbackExecutor.execute(() ->
                            callback.accept(AppSearchResult.newFailedResult(getSchemaResult)));
                    return;
                }
                GetSchemaResponse getSchemaResponse = getSchemaResult.getResultValue();
                Set<AppSearchSchema> currentSchemas = getSchemaResponse.getSchemas();
                Map<String, Integer> currentVersionMap = SchemaMigrationUtil.buildVersionMap(
                        currentSchemas, getSchemaResponse.getVersion());
                Map<String, Integer> finalVersionMap = SchemaMigrationUtil.buildVersionMap(
                        request.getSchemas(), request.getVersion());

                // 2. SetSchema with forceOverride=false, to retrieve the list of
                // incompatible/deleted types.
                AndroidFuture<AppSearchResult<Bundle>> setSchemaFuture = new AndroidFuture<>();
                mService.setSchema(
                        mPackageName,
                        mDatabaseName,
                        schemaBundles,
                        new ArrayList<>(request.getSchemasNotDisplayedBySystem()),
                        schemasPackageAccessibleBundles,
                        /*forceOverride=*/ false,
                        mUserId,
                        request.getVersion(),
                        new IAppSearchResultCallback.Stub() {
                            public void onResult(AppSearchResult result) {
                                setSchemaFuture.complete(result);
                            }
                        });
                AppSearchResult<Bundle> setSchemaResult = setSchemaFuture.get();
                if (!setSchemaResult.isSuccess()) {
                    callbackExecutor.execute(() ->
                            callback.accept(AppSearchResult.newFailedResult(setSchemaResult)));
                    return;
                }
                SetSchemaResponse setSchemaResponse =
                        new SetSchemaResponse(setSchemaResult.getResultValue());

                // 1. If forceOverride is false, check that all incompatible types will be migrated.
                // If some aren't we must throw an error, rather than proceeding and deleting those
                // types.
                if (!request.isForceOverride()) {
            Set<String> unmigratedTypes = SchemaMigrationUtil.getUnmigratedIncompatibleTypes(
                    Set<String> unmigratedTypes =
                            SchemaMigrationUtil.getUnmigratedIncompatibleTypes(
                                    setSchemaResponse.getIncompatibleTypes(),
                                    request.getMigrators(),
                                    currentVersionMap,
                                    finalVersionMap);
            // check if there are any unmigrated types or deleted types. If there are, we will throw
            // an exception.
            // Since the force override is false, the schema will not have been set if there are any
            // incompatible or deleted types.
            checkDeletedAndIncompatible(setSchemaResponse.getDeletedTypes(),
                    unmigratedTypes);

                    // check if there are any unmigrated types or deleted types. If there are, we
                    // will throw an exception.
                    // Since the force override is false, the schema will not have been set if there
                    // are any incompatible or deleted types.
                    checkDeletedAndIncompatible(
                            setSchemaResponse.getDeletedTypes(), unmigratedTypes);
                }

                try (AppSearchMigrationHelper migrationHelper =
                     new AppSearchMigrationHelper(mService, mUserId, currentVersionMap,
                             finalVersionMap, mPackageName, mDatabaseName)) {
                             new AppSearchMigrationHelper(
                                     mService, mUserId, currentVersionMap, finalVersionMap,
                                     mPackageName, mDatabaseName)) {
                    Map<String, Migrator> migratorMap = request.getMigrators();

                    // 2. Trigger migration for all migrators.
            // TODO(b/177266929) trigger migration for all types together rather than separately.
                    // TODO(b/177266929) trigger migration for all types together rather than
                    //  separately.
                    Set<String> migratedTypes = new ArraySet<>();
                    for (Map.Entry<String, Migrator> entry : migratorMap.entrySet()) {
                        String schemaType = entry.getKey();
@@ -767,10 +760,12 @@ public final class AppSearchSession implements Closeable {
                        }
                    }

            // 3. SetSchema a second time with forceOverride=true if the first attempted failed.
                    // 3. SetSchema a second time with forceOverride=true if the first attempted
                    // failed.
                    if (!setSchemaResponse.getIncompatibleTypes().isEmpty()
                            || !setSchemaResponse.getDeletedTypes().isEmpty()) {
                AndroidFuture<AppSearchResult<SetSchemaResponse>> future = new AndroidFuture<>();
                        AndroidFuture<AppSearchResult<Bundle>> setSchema2Future =
                                new AndroidFuture<>();
                        // only trigger second setSchema() call if the first one is fail.
                        mService.setSchema(
                                mPackageName,
@@ -779,28 +774,37 @@ public final class AppSearchSession implements Closeable {
                                new ArrayList<>(request.getSchemasNotDisplayedBySystem()),
                                schemasPackageAccessibleBundles,
                                /*forceOverride=*/ true,
                        mUserId,
                                request.getVersion(),
                                mUserId,
                                new IAppSearchResultCallback.Stub() {
                                    @Override
                            public void onResult(AppSearchResult result) throws RemoteException {
                                future.complete(result);
                                    public void onResult(AppSearchResult result) {
                                        setSchema2Future.complete(result);
                                    }
                                });
                AppSearchResult<SetSchemaResponse> secondSetSchemaResult = future.get();
                if (!secondSetSchemaResult.isSuccess()) {
                    // we failed to set the schema in second time with force override = true, which
                    // is an impossible case. Since we only swallow the incompatible error in the
                    // first setSchema call, all other errors will be thrown at the first time.
                    callback.accept(secondSetSchemaResult);
                        AppSearchResult<Bundle> setSchema2Result = setSchema2Future.get();
                        if (!setSchema2Result.isSuccess()) {
                            // we failed to set the schema in second time with forceOverride = true,
                            // which is an impossible case. Since we only swallow the incompatible
                            // error in the first setSchema call, all other errors will be thrown at
                            // the first time.
                            callbackExecutor.execute(() -> callback.accept(
                                    AppSearchResult.newFailedResult(setSchemaResult)));
                            return;
                        }
                    }

                    SetSchemaResponse.Builder responseBuilder = setSchemaResponse.toBuilder()
                            .addMigratedTypes(migratedTypes);
            callback.accept(migrationHelper.putMigratedDocuments(responseBuilder));
                    AppSearchResult<SetSchemaResponse> putResult =
                            migrationHelper.putMigratedDocuments(responseBuilder);
                    callbackExecutor.execute(() -> callback.accept(putResult));
                }
            } catch (Throwable t) {
                callbackExecutor.execute(() -> callback.accept(
                        AppSearchResult.throwableToFailedResult(t)));
            }
        });
    }

    /**  Checks the setSchema() call won't delete any types or has incompatible types. */
+66 −5
Original line number Diff line number Diff line
@@ -258,7 +258,8 @@ public class BlobStoreManager {
    public @NonNull ParcelFileDescriptor openBlob(@NonNull BlobHandle blobHandle)
            throws IOException {
        try {
            return mService.openBlob(blobHandle, mContext.getOpPackageName());
            return mService.openBlob(blobHandle, mContext.getOpPackageName(),
                    mContext.getAttributionTag());
        } catch (ParcelableException e) {
            e.maybeRethrow(IOException.class);
            throw new RuntimeException(e);
@@ -315,7 +316,7 @@ public class BlobStoreManager {
            @CurrentTimeMillisLong long leaseExpiryTimeMillis) throws IOException {
        try {
            mService.acquireLease(blobHandle, descriptionResId, null, leaseExpiryTimeMillis,
                    mContext.getOpPackageName());
                    mContext.getOpPackageName(), mContext.getAttributionTag());
        } catch (ParcelableException e) {
            e.maybeRethrow(IOException.class);
            e.maybeRethrow(LimitExceededException.class);
@@ -378,7 +379,7 @@ public class BlobStoreManager {
            @CurrentTimeMillisLong long leaseExpiryTimeMillis) throws IOException {
        try {
            mService.acquireLease(blobHandle, INVALID_RES_ID, description, leaseExpiryTimeMillis,
                    mContext.getOpPackageName());
                    mContext.getOpPackageName(), mContext.getAttributionTag());
        } catch (ParcelableException e) {
            e.maybeRethrow(IOException.class);
            e.maybeRethrow(LimitExceededException.class);
@@ -497,7 +498,8 @@ public class BlobStoreManager {
     */
    public void releaseLease(@NonNull BlobHandle blobHandle) throws IOException {
        try {
            mService.releaseLease(blobHandle, mContext.getOpPackageName());
            mService.releaseLease(blobHandle, mContext.getOpPackageName(),
                    mContext.getAttributionTag());
        } catch (ParcelableException e) {
            e.maybeRethrow(IOException.class);
            throw new RuntimeException(e);
@@ -602,7 +604,8 @@ public class BlobStoreManager {
    @Nullable
    public LeaseInfo getLeaseInfo(@NonNull BlobHandle blobHandle) throws IOException {
        try {
            return mService.getLeaseInfo(blobHandle, mContext.getOpPackageName());
            return mService.getLeaseInfo(blobHandle, mContext.getOpPackageName(),
                    mContext.getAttributionTag());
        } catch (ParcelableException e) {
            e.maybeRethrow(IOException.class);
            throw new RuntimeException(e);
@@ -896,6 +899,64 @@ public class BlobStoreManager {
            }
        }

        /**
         * Allow apps with location permission to access this blob data once it is committed using
         * a {@link BlobHandle} representing the blob.
         *
         * <p> This needs to be called before committing the blob using
         * {@link #commit(Executor, Consumer)}.
         *
         * Note that if a caller allows access to the blob using this API in addition to other APIs
         * like {@link #allowPackageAccess(String, byte[])}, then apps satisfying any one of these
         * access conditions will be allowed to access the blob.
         *
         * @param permissionName the name of the location permission that needs to be granted
         *                       for the app. This can be either one of
         *                       {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or
         *                       {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
         *
         * @throws IOException when there is an I/O error while changing the access.
         * @throws SecurityException when the caller is not the owner of the session.
         * @throws IllegalStateException when the caller tries to change access for a blob which is
         *                               already committed.
         */
        public void allowPackagesWithLocationPermission(@NonNull String permissionName)
                throws IOException {
            try {
                mSession.allowPackagesWithLocationPermission(permissionName);
            } catch (ParcelableException e) {
                e.maybeRethrow(IOException.class);
                throw new RuntimeException(e);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }

        /**
         * Returns {@code true} if access has been allowed for apps with location permission by
         * using {@link #allowPackagesWithLocationPermission(String)}.
         *
         * @param permissionName the name of the location permission that needs to be granted
         *                       for the app. This can be either one of
         *                       {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or
         *                       {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
         *
         * @throws IOException when there is an I/O error while getting the access type.
         * @throws IllegalStateException when the caller tries to get access type from a session
         *                               which is closed or abandoned.
         */
        public boolean arePackagesWithLocationPermissionAllowed(@NonNull String permissionName)
                throws IOException {
            try {
                return mSession.arePackagesWithLocationPermissionAllowed(permissionName);
            } catch (ParcelableException e) {
                e.maybeRethrow(IOException.class);
                throw new RuntimeException(e);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }

        /**
         * Commit the file that was written so far to this session to the blob store maintained by
         * the system.
+6 −4
Original line number Diff line number Diff line
@@ -25,12 +25,13 @@ import android.os.RemoteCallback;
interface IBlobStoreManager {
    long createSession(in BlobHandle handle, in String packageName);
    IBlobStoreSession openSession(long sessionId, in String packageName);
    ParcelFileDescriptor openBlob(in BlobHandle handle, in String packageName);
    ParcelFileDescriptor openBlob(in BlobHandle handle, in String packageName,
           in String attributionTag);
    void abandonSession(long sessionId, in String packageName);

    void acquireLease(in BlobHandle handle, int descriptionResId, in CharSequence description,
            long leaseTimeoutMillis, in String packageName);
    void releaseLease(in BlobHandle handle, in String packageName);
            long leaseTimeoutMillis, in String packageName, in String attributionTag);
    void releaseLease(in BlobHandle handle, in String packageName, in String attributionTag);
    long getRemainingLeaseQuotaBytes(String packageName);

    void waitForIdle(in RemoteCallback callback);
@@ -39,5 +40,6 @@ interface IBlobStoreManager {
    void deleteBlob(long blobId);

    List<BlobHandle> getLeasedBlobs(in String packageName);
    LeaseInfo getLeaseInfo(in BlobHandle blobHandle, in String packageName);
    LeaseInfo getLeaseInfo(in BlobHandle blobHandle, in String packageName,
            in String attributionTag);
}
 No newline at end of file
+2 −0
Original line number Diff line number Diff line
@@ -26,10 +26,12 @@ interface IBlobStoreSession {
    void allowPackageAccess(in String packageName, in byte[] certificate);
    void allowSameSignatureAccess();
    void allowPublicAccess();
    void allowPackagesWithLocationPermission(in String permissionName);

    boolean isPackageAccessAllowed(in String packageName, in byte[] certificate);
    boolean isSameSignatureAccessAllowed();
    boolean isPublicAccessAllowed();
    boolean arePackagesWithLocationPermissionAllowed(in String permissionName);

    long getSize();
    void close();
Loading