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

Commit 8f34e401 authored by MingWei Liao's avatar MingWei Liao Committed by Android (Google) Code Review
Browse files

Merge "Add uri granting logic for app functions" into main

parents 6bb1b7c1 1aa54016
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -127,7 +127,9 @@ public final class ExecuteAppFunctionResponse implements Parcelable {
     * @param resultDocument The return value of the executed function.
     * @param extras The additional metadata for this function execution response.
     * @param uriGrants The list of {@link AppFunctionUriGrant} to which
     *     the caller of this app function execution should have temporary access granted.
     *     the caller of this app function execution should have temporary access granted. These
     *     grants typically persist until the device reboots. Uri owner could consider clearing
     *     data associated with these URIs after a reboot.
     */
    @FlaggedApi(Flags.FLAG_APP_FUNCTION_ACCESS_API_ENABLED)
    public ExecuteAppFunctionResponse(
+22 −1
Original line number Diff line number Diff line
@@ -41,16 +41,20 @@ public class SafeOneTimeExecuteAppFunctionCallback {

    @Nullable private final CompletionCallback mCompletionCallback;

    @Nullable private final BeforeCompletionCallback mBeforeCompletionCallback;

    private final AtomicLong mExecutionStartTimeAfterBindMillis = new AtomicLong();

    public SafeOneTimeExecuteAppFunctionCallback(@NonNull IExecuteAppFunctionCallback callback) {
        this(callback, /* completionCallback= */ null);
        this(callback, /* beforeCompletionCallback= */ null, /* completionCallback= */ null);
    }

    public SafeOneTimeExecuteAppFunctionCallback(
            @NonNull IExecuteAppFunctionCallback callback,
            @Nullable BeforeCompletionCallback beforeCompletionCallback,
            @Nullable CompletionCallback completionCallback) {
        mCallback = Objects.requireNonNull(callback);
        mBeforeCompletionCallback = beforeCompletionCallback;
        mCompletionCallback = completionCallback;
    }

@@ -61,6 +65,9 @@ public class SafeOneTimeExecuteAppFunctionCallback {
            return;
        }
        try {
            if (mBeforeCompletionCallback != null) {
                mBeforeCompletionCallback.beforeOnSuccess(result);
            }
            mCallback.onSuccess(result);
            if (mCompletionCallback != null) {
                mCompletionCallback.finalizeOnSuccess(
@@ -121,4 +128,18 @@ public class SafeOneTimeExecuteAppFunctionCallback {
        /** Called after {@link IExecuteAppFunctionCallback#onError}. */
        void finalizeOnError(@NonNull AppFunctionException error, long executionStartTimeMillis);
    }

    /**
     * Provides a hook to execute additional actions before the {@link IExecuteAppFunctionCallback}
     * has been invoked.
     */
    public interface BeforeCompletionCallback {
        /**
         * Called before {@link IExecuteAppFunctionCallback#onSuccess(ExecuteAppFunctionResponse)}
         * is invoked.
         *
         * @param result The result that will be passed to the main callback.
         */
        void beforeOnSuccess(@NonNull ExecuteAppFunctionResponse result);
    }
}
+5 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.appfunctions;

import android.annotation.NonNull;
import android.app.UriGrantsManager;
import android.app.appfunctions.AppFunctionAccessServiceInterface;
import android.app.appfunctions.AppFunctionManagerConfiguration;
import android.content.Context;
@@ -24,6 +25,7 @@ import android.content.pm.PackageManagerInternal;

import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.uri.UriGrantsManagerInternal;

/** Service that manages app functions. */
public class AppFunctionManagerService extends SystemService {
@@ -34,7 +36,9 @@ public class AppFunctionManagerService extends SystemService {
        mServiceImpl =
                new AppFunctionManagerServiceImpl(
                        context, LocalServices.getService(PackageManagerInternal.class),
                        LocalServices.getService(AppFunctionAccessServiceInterface.class));
                        LocalServices.getService(AppFunctionAccessServiceInterface.class),
                        UriGrantsManager.getService(),
                        LocalServices.getService(UriGrantsManagerInternal.class));
    }

    @Override
+85 −4
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import static com.android.server.appfunctions.CallerValidator.CAN_EXECUTE_APP_FU
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.WorkerThread;
import android.app.IUriGrantsManager;
import android.app.appfunctions.AppFunctionAccessServiceInterface;
import android.app.appfunctions.AppFunctionException;
import android.app.appfunctions.AppFunctionManager;
@@ -34,6 +35,7 @@ import android.app.appfunctions.AppFunctionManagerHelper;
import android.app.appfunctions.AppFunctionManagerHelper.AppFunctionNotFoundException;
import android.app.appfunctions.AppFunctionRuntimeMetadata;
import android.app.appfunctions.AppFunctionStaticMetadataHelper;
import android.app.appfunctions.AppFunctionUriGrant;
import android.app.appfunctions.ExecuteAppFunctionAidlRequest;
import android.app.appfunctions.ExecuteAppFunctionResponse;
import android.app.appfunctions.IAppFunctionEnabledCallback;
@@ -53,6 +55,8 @@ import android.app.appsearch.observer.DocumentChangeInfo;
import android.app.appsearch.observer.ObserverCallback;
import android.app.appsearch.observer.ObserverSpec;
import android.app.appsearch.observer.SchemaChangeInfo;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
@@ -85,6 +89,7 @@ import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
import com.android.server.SystemService;
import com.android.server.SystemService.TargetUser;
import com.android.server.uri.UriGrantsManagerInternal;

import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -119,6 +124,12 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {

    private final AppFunctionAccessServiceInterface mAppFunctionAccessService;

    private final IUriGrantsManager mUriGrantsManager;

    private final UriGrantsManagerInternal mUriGrantsManagerInternal;

    private final IBinder mPermissionOwner;

    private final Object mAgentAllowlistLock = new Object();

    // The main agent allowlist, set by the updatable DeviceConfig System
@@ -127,7 +138,9 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {

    public AppFunctionManagerServiceImpl(
            @NonNull Context context, @NonNull PackageManagerInternal packageManagerInternal,
            @NonNull AppFunctionAccessServiceInterface appFunctionAccessServiceInterface) {
            @NonNull AppFunctionAccessServiceInterface appFunctionAccessServiceInterface,
            @NonNull IUriGrantsManager uriGrantsManager,
            @NonNull UriGrantsManagerInternal uriGrantsManagerInternal) {
        this(
                context,
                new RemoteServiceCallerImpl<>(
@@ -137,7 +150,9 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
                new ServiceConfigImpl(),
                new AppFunctionsLoggerWrapper(context),
                packageManagerInternal,
                appFunctionAccessServiceInterface);
                appFunctionAccessServiceInterface,
                uriGrantsManager,
                uriGrantsManagerInternal);
    }

    @VisibleForTesting
@@ -149,7 +164,9 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
            ServiceConfig serviceConfig,
            AppFunctionsLoggerWrapper loggerWrapper,
            PackageManagerInternal packageManagerInternal,
            AppFunctionAccessServiceInterface appFunctionAccessServiceInterface) {
            AppFunctionAccessServiceInterface appFunctionAccessServiceInterface,
            IUriGrantsManager uriGrantsManager,
            UriGrantsManagerInternal uriGrantsManagerInternal) {
        mContext = Objects.requireNonNull(context);
        mRemoteServiceCaller = Objects.requireNonNull(remoteServiceCaller);
        mCallerValidator = Objects.requireNonNull(callerValidator);
@@ -158,6 +175,9 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
        mLoggerWrapper = loggerWrapper;
        mPackageManagerInternal = Objects.requireNonNull(packageManagerInternal);
        mAppFunctionAccessService = Objects.requireNonNull(appFunctionAccessServiceInterface);
        mUriGrantsManager = Objects.requireNonNull(uriGrantsManager);
        mUriGrantsManagerInternal = Objects.requireNonNull(uriGrantsManagerInternal);
        mPermissionOwner = mUriGrantsManagerInternal.newUriPermissionOwner("appfunctions");
    }

    /** Called when the user is unlocked. */
@@ -563,6 +583,59 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
                && android.permission.flags.Flags.appFunctionAccessServiceEnabled();
    }

    /**
     * Grants temporary uri permission on behalf of the app that returns the response to the
     * caller that sends the request.
     *
     * <p>All {@link AppFunctionUriGrant} in {@link ExecuteAppFunctionResponse} would be granted
     * to the receiver until the system service is finished. That is usually until device reboots.
     */
    private void grantTemporaryUriPermissions(
            @NonNull ExecuteAppFunctionAidlRequest requestInternal,
            @NonNull ExecuteAppFunctionResponse response,
            int callingUid) {
        if (!accessCheckFlagsEnabled()) return;

        final int uriReceiverUserId = UserHandle.getUserId(callingUid);
        final int targetUserId = requestInternal.getUserHandle().getIdentifier();
        final String uriOwnerPackageName = requestInternal
                .getClientRequest()
                .getTargetPackageName();
        final int uriOwnerUid =
                mPackageManagerInternal.getPackageUid(
                        uriOwnerPackageName,
                        /* flags= */ 0,
                        /* userId= */ targetUserId
                );

        final long ident = Binder.clearCallingIdentity();
        try {
            final int uriGrantsSize = response.getUriGrants().size();
            for (int i = 0; i < uriGrantsSize; i++) {
                final AppFunctionUriGrant uriGrant = response.getUriGrants().get(i);
                if (!ContentResolver.SCHEME_CONTENT.equals(uriGrant.getUri().getScheme())) continue;

                final  String uriReceiverPackageName = requestInternal.getCallingPackage();
                final int uriOwnerUserid = ContentProvider.getUserIdFromUri(
                        uriGrant.getUri(),
                        UserHandle.getUserId(uriOwnerUid));
                mUriGrantsManager.grantUriPermissionFromOwner(
                        mPermissionOwner,
                        uriOwnerUid,
                        uriReceiverPackageName,
                        ContentProvider.getUriWithoutUserId(uriGrant.getUri()),
                        uriGrant.getModeFlags(),
                        uriOwnerUserid,
                        uriReceiverUserId
                );
            }
        } catch (RemoteException e) {
            Slog.e(TAG, "Granting URI permissions failed", e);
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }

    private static void reportException(
            @NonNull IAppFunctionEnabledCallback callback, @NonNull Exception exception) {
        try {
@@ -825,7 +898,9 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {

    /**
     * Returns a new {@link SafeOneTimeExecuteAppFunctionCallback} initialized with a {@link
     * SafeOneTimeExecuteAppFunctionCallback.CompletionCallback} that logs the results.
     * SafeOneTimeExecuteAppFunctionCallback.CompletionCallback} that logs the results and a
     * {@link SafeOneTimeExecuteAppFunctionCallback.BeforeCompletionCallback} that grants the
     * temporary uri permission to caller.
     */
    @VisibleForTesting
    SafeOneTimeExecuteAppFunctionCallback initializeSafeExecuteAppFunctionCallback(
@@ -834,6 +909,12 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
            int callingUid) {
        return new SafeOneTimeExecuteAppFunctionCallback(
                executeAppFunctionCallback,
                new SafeOneTimeExecuteAppFunctionCallback.BeforeCompletionCallback() {
                    @Override
                    public void beforeOnSuccess(@NonNull ExecuteAppFunctionResponse result) {
                        grantTemporaryUriPermissions(requestInternal, result, callingUid);
                    }
                },
                new SafeOneTimeExecuteAppFunctionCallback.CompletionCallback() {
                    @Override
                    public void finalizeOnSuccess(
+9 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.appfunctions

import android.app.IUriGrantsManager
import android.app.appfunctions.AppFunctionAccessServiceInterface
import android.app.appfunctions.flags.Flags
import android.content.Context
@@ -27,6 +28,7 @@ import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.modules.utils.testing.ExtendedMockitoRule
import com.android.server.LocalServices
import com.android.server.uri.UriGrantsManagerInternal
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Ignore
@@ -47,8 +49,13 @@ class AppFunctionManagerServiceImplTest {
    private val context: Context
        get() = ApplicationProvider.getApplicationContext()

    private val serviceImpl = AppFunctionManagerServiceImpl(context, mock<PackageManagerInternal>(),
        mock<AppFunctionAccessServiceInterface>())
    private val serviceImpl = AppFunctionManagerServiceImpl(
        context,
        mock<PackageManagerInternal>(),
        mock<AppFunctionAccessServiceInterface>(),
        mock<IUriGrantsManager>(),
        mock<UriGrantsManagerInternal>()
    )

    @Test
    fun testGetLockForPackage_samePackage() {
Loading