Loading Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -424,6 +424,7 @@ filegroup { ":libbluetooth-binder-aidl", ":libcamera_client_aidl", ":libcamera_client_framework_aidl", ":packagemanager_aidl", ":libupdate_engine_aidl", ":resourcemanager_aidl", ":storaged_aidl", Loading apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java +129 −125 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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)); } } /** Loading Loading @@ -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, Loading Loading @@ -709,7 +656,6 @@ public final class AppSearchSession implements Closeable { }); } }); mIsMutated = true; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading @@ -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(); Loading @@ -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, Loading @@ -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. */ Loading apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java +66 −5 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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. Loading apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl +6 −4 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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 apex/blobstore/framework/java/android/app/blob/IBlobStoreSession.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -424,6 +424,7 @@ filegroup { ":libbluetooth-binder-aidl", ":libcamera_client_aidl", ":libcamera_client_framework_aidl", ":packagemanager_aidl", ":libupdate_engine_aidl", ":resourcemanager_aidl", ":storaged_aidl", Loading
apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java +129 −125 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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)); } } /** Loading Loading @@ -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, Loading Loading @@ -709,7 +656,6 @@ public final class AppSearchSession implements Closeable { }); } }); mIsMutated = true; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading @@ -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(); Loading @@ -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, Loading @@ -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. */ Loading
apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java +66 −5 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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. Loading
apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl +6 −4 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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
apex/blobstore/framework/java/android/app/blob/IBlobStoreSession.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -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