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

Commit ab93aff6 authored by Tony Mak's avatar Tony Mak
Browse files

Add shell commands to grant and revoke access

Bug: 422963542

Flag: android.permission.flags.app_function_access_service_enabled
Test: Run the command

Change-Id: I60c312314b913b88f926b71052b36672119e5da5
parent 57740db5
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -26,26 +26,26 @@ import java.util.List;
 */
public interface AppFunctionAccessServiceInterface {

    /** check access */
    /** @see AppFunctionManager#checkAppFunctionAccess(String, String)  */
    boolean checkAppFunctionAccess(@NonNull String agentPackageName, int agentUserId,
            @NonNull String targetPackageName, int targetUserId);

    /** check access, but also informs if access is invalid */
    /** @see AppFunctionManager#getAppFunctionAccessRequestState(String, String)  */
    @AppFunctionManager.AppFunctionAccessState
    int getAppFunctionAccessRequestState(@NonNull String agentPackageName, int agentUserId,
            @NonNull String targetPackageName, int targetUserId);

    /** get flags for a given target and agent */
    /** @see AppFunctionManager#getAppFunctionAccessFlags(String, String)  */
    @AppFunctionManager.AppFunctionAccessFlags
    int getAppFunctionAccessFlags(@NonNull String agentPackageName, int agentUserId,
            @NonNull String targetPackageName, int targetUserId);

    /** update flags for a given target and agent */
    /** @see AppFunctionManager#updateAppFunctionAccessFlags(String, String, int, int)  */
    boolean updateAppFunctionAccessFlags(@NonNull String agentPackageName, int agentUserId,
            @NonNull String targetPackageName, int targetUserId,
            @AppFunctionManager.AppFunctionAccessFlags int flagMask,
            @AppFunctionManager.AppFunctionAccessFlags int flags) throws IllegalArgumentException;

    /** update the agent allowlist */
    /** Set the agent allowlist */
    void setAgentAllowlist(@NonNull List<SignedPackage> agentAllowlist);
}
+34 −0
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import android.app.appfunctions.IExecuteAppFunctionCallback;
import android.os.ICancellationSignal;

import android.os.UserHandle;

import java.util.List;
/**
 * Defines the interface for apps to interact with the app function execution service
 * {@code AppFunctionManagerService} running in the system server process.
@@ -50,4 +52,36 @@ interface IAppFunctionManager {
        int enabledState,
        in IAppFunctionEnabledCallback callback
    );

    boolean checkAppFunctionAccess(
        in String agentPackageName,
        int agentUserId,
        in String targetPackageName,
        int targetUserId
    );

    int getAppFunctionAccessRequestState(
        in String agentPackageName,
        int agentUserId,
        in String targetPackageName,
        int targetUserId
    );

    int getAppFunctionAccessFlags(
        in String agentPackageName,
        int agentUserId,
        in String targetPackageName,
        int targetUserId
    );

    void updateAppFunctionAccessFlags(
        in String agentPackageName,
        int agentUserId,
        in String targetPackageName,
        int targetUserId,
        int flagMask,
        int flags
    );

    void revokeSelfAppFunctionAccess(in String targetPackageName);
}
+57 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.appfunctions;

import static android.app.appfunctions.AppFunctionManager.ACCESS_REQUEST_STATE_UNREQUESTABLE;
import static android.app.appfunctions.AppFunctionRuntimeMetadata.APP_FUNCTION_RUNTIME_METADATA_DB;
import static android.app.appfunctions.AppFunctionRuntimeMetadata.APP_FUNCTION_RUNTIME_NAMESPACE;

@@ -412,6 +413,62 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
                });
    }

    @Override
    public boolean checkAppFunctionAccess(String agentPackageName, int agentUserId,
            String targetPackageName, int targetUserId) throws RemoteException {
        if (!accessCheckFlagsEnabled()) {
            return false;
        }
        return mAppFunctionAccessService.checkAppFunctionAccess(agentPackageName, agentUserId,
                targetPackageName, targetUserId);
    }

    @Override
    public int getAppFunctionAccessFlags(String agentPackageName, int agentUserId,
            String targetPackageName, int targetUserId) throws RemoteException {
        if (!accessCheckFlagsEnabled()) {
            return 0;
        }
        return mAppFunctionAccessService.getAppFunctionAccessFlags(agentPackageName, agentUserId,
                targetPackageName, targetUserId);
    }

    @Override
    public void updateAppFunctionAccessFlags(String agentPackageName, int agentUserId,
            String targetPackageName, int targetUserId, int flagMask, int flags)
            throws RemoteException {
        if (!accessCheckFlagsEnabled()) {
            return;
        }
        mAppFunctionAccessService.updateAppFunctionAccessFlags(agentPackageName, agentUserId,
                targetPackageName, targetUserId, flagMask, flags);
    }

    @Override
    public void revokeSelfAppFunctionAccess(String targetPackageName) {
        if (!accessCheckFlagsEnabled()) {
            return;
        }
        // TODO: Call mAppFunctionAccessService.revokeSelfAppFunctionAccess(targetPackageName)
        // when ag/33428645 is in.
    }

    @Override
    public int getAppFunctionAccessRequestState(String agentPackageName, int agentUserId,
            String targetPackageName, int targetUserId) throws RemoteException {
        if (!accessCheckFlagsEnabled()) {
            return ACCESS_REQUEST_STATE_UNREQUESTABLE;
        }

        return mAppFunctionAccessService.getAppFunctionAccessRequestState(agentPackageName,
                agentUserId, targetPackageName, targetUserId);
    }

    private boolean accessCheckFlagsEnabled() {
        return android.permission.flags.Flags.appFunctionAccessApiEnabled()
                && android.permission.flags.Flags.appFunctionAccessServiceEnabled();
    }

    private static void reportException(
            @NonNull IAppFunctionEnabledCallback callback, @NonNull Exception exception) {
        try {
+127 −1
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@

package com.android.server.appfunctions;

import static android.app.appfunctions.AppFunctionManager.ACCESS_FLAG_MASK_OTHER;
import static android.app.appfunctions.AppFunctionManager.ACCESS_FLAG_OTHER_DENIED;
import static android.app.appfunctions.AppFunctionManager.ACCESS_FLAG_OTHER_GRANTED;

import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.appfunctions.AppFunctionException;
@@ -48,7 +52,8 @@ import java.util.concurrent.TimeUnit;
/** Shell command implementation for the {@link AppFunctionManagerService}. */
public class AppFunctionManagerServiceShellCommand extends ShellCommand {

    @NonNull private final IAppFunctionManager mService;
    @NonNull
    private final IAppFunctionManager mService;

    AppFunctionManagerServiceShellCommand(@NonNull IAppFunctionManager service) {
        mService = Objects.requireNonNull(service);
@@ -85,6 +90,38 @@ public class AppFunctionManagerServiceShellCommand extends ShellCommand {
        pw.println(
                "    --user <USER_ID> (optional): The user ID under which to set the function state"
                        + ". Defaults to the current user.");

        pw.println();
        pw.println(
                "  grant-app-function-access --agent-package <AGENT_PACKAGE_NAME> "
                        + "--target-package <TARGET_PACKAGE_NAME> [--agent-user <USER_ID>] "
                        + "[--target-user <USER_ID>]");
        pw.println("    Grants an agent package access to an app's functions.");
        pw.println("    --agent-package <AGENT_PACKAGE_NAME>: The agent package to grant access.");
        pw.println("    --target-package <TARGET_PACKAGE_NAME>: The target package.");
        pw.println(
                "    --agent-user <USER_ID> (optional): The user ID for the agent package. "
                        + "Defaults to the current user.");
        pw.println(
                "    --target-user <USER_ID> (optional): The user ID for the target package. "
                        + "Defaults to the current user.");
        pw.println();
        pw.println(
                "  revoke-app-function-access --agent-package <AGENT_PACKAGE_NAME> "
                        + "--target-package <TARGET_PACKAGE_NAME> [--agent-user <USER_ID>] "
                        + "[--target-user <USER_ID>]");
        pw.println("    Revokes an agent package's access to an app's functions.");
        pw.println(
                "    --agent-package <AGENT_PACKAGE_NAME>: The agent package to revoke access "
                        + "from.");
        pw.println("    --target-package <TARGET_PACKAGE_NAME>: The target package.");
        pw.println(
                "    --agent-user <USER_ID> (optional): The user ID for the agent package. "
                        + "Defaults to the current user.");
        pw.println(
                "    --target-user <USER_ID> (optional): The user ID for the target package. "
                        + "Defaults to the current user.");

        pw.println();
    }

@@ -100,6 +137,10 @@ public class AppFunctionManagerServiceShellCommand extends ShellCommand {
                    return runExecuteAppFunction();
                case "set-enabled":
                    return runSetAppFunctionEnabled();
                case "grant-app-function-access":
                    return runGrantAppFunctionAccess();
                case "revoke-app-function-access":
                    return runRevokeAppFunctionAccess();
                default:
                    return handleDefaultCommands(cmd);
            }
@@ -371,6 +412,91 @@ public class AppFunctionManagerServiceShellCommand extends ShellCommand {
        return builder.build();
    }

    private int runGrantAppFunctionAccess() throws Exception {
        final PrintWriter pw = getOutPrintWriter();
        String agentPackage = null;
        String targetPackage = null;
        int agentUserId = ActivityManager.getCurrentUser();
        int targetUserId = ActivityManager.getCurrentUser();
        String opt;

        while ((opt = getNextOption()) != null) {
            switch (opt) {
                case "--agent-package":
                    agentPackage = getNextArgRequired();
                    break;
                case "--target-package":
                    targetPackage = getNextArgRequired();
                    break;
                case "--agent-user":
                    agentUserId = UserHandle.parseUserArg(getNextArgRequired());
                    break;
                case "--target-user":
                    targetUserId = UserHandle.parseUserArg(getNextArgRequired());
                    break;
                default:
                    pw.println("Unknown option: " + opt);
                    return -1;
            }
        }

        if (agentPackage == null) {
            pw.println("Error: --agent-package must be specified.");
            return -1;
        }
        if (targetPackage == null) {
            pw.println("Error: --target-package must be specified.");
            return -1;
        }

        mService.updateAppFunctionAccessFlags(agentPackage, agentUserId, targetPackage,
                targetUserId, ACCESS_FLAG_MASK_OTHER, ACCESS_FLAG_OTHER_GRANTED);
        pw.println("Access granted successfully.");
        return 0;
    }

    private int runRevokeAppFunctionAccess() throws Exception {
        final PrintWriter pw = getOutPrintWriter();
        String agentPackage = null;
        String targetPackage = null;
        int agentUserId = ActivityManager.getCurrentUser();
        int targetUserId = ActivityManager.getCurrentUser();
        String opt;

        while ((opt = getNextOption()) != null) {
            switch (opt) {
                case "--agent-package":
                    agentPackage = getNextArgRequired();
                    break;
                case "--target-package":
                    targetPackage = getNextArgRequired();
                    break;
                case "--agent-user":
                    agentUserId = UserHandle.parseUserArg(getNextArgRequired());
                    break;
                case "--target-user":
                    targetUserId = UserHandle.parseUserArg(getNextArgRequired());
                    break;
                default:
                    pw.println("Unknown option: " + opt);
                    return -1;
            }
        }

        if (agentPackage == null) {
            pw.println("Error: --agent-package must be specified.");
            return -1;
        }
        if (targetPackage == null) {
            pw.println("Error: --target-package must be specified.");
            return -1;
        }
        mService.updateAppFunctionAccessFlags(agentPackage, agentUserId, targetPackage,
                targetUserId, ACCESS_FLAG_MASK_OTHER, ACCESS_FLAG_OTHER_DENIED);
        pw.println("Access revoked successfully.");
        return 0;
    }

    private static String getCallingPackage() {
        return switch (Binder.getCallingUid()) {
            case Process.ROOT_UID -> "root";