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

Commit 379abc70 authored by MingWei Liao's avatar MingWei Liao
Browse files

Enable agent allowlist

Also fix an issue of request intent should use permission owner package
name instead of actual pacakge name.

Bug: 416661798
Test: atest
Flag: android.permission.flags.app_function_access_api_enabled
Change-Id: I91fa44d032a0d779d43d3adb23b845815280d41a
parent 73ece28f
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -792,8 +792,6 @@ package android.app.appfunctions {
    method @FlaggedApi("android.permission.flags.app_function_access_api_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_APP_FUNCTION_ACCESS) public void clearAccessHistory();
    method @FlaggedApi("android.permission.flags.app_function_access_api_enabled") @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_APP_FUNCTION_ACCESS) public java.util.List<android.content.pm.SignedPackage> getAgentAllowlist();
    method @FlaggedApi("android.permission.flags.app_function_access_api_enabled") @NonNull public java.util.Set<java.lang.String> getDeviceSettingPackages();
    method @FlaggedApi("android.permission.flags.app_function_access_api_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_APP_FUNCTION_ACCESS) public boolean isAgentAllowlistEnabled();
    method @FlaggedApi("android.permission.flags.app_function_access_api_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_APP_FUNCTION_ACCESS) public void setAgentAllowlistEnabled(boolean);
    field public static final int ACCESS_FLAG_MASK_ALL = 31; // 0x1f
    field public static final int ACCESS_FLAG_MASK_OTHER = 6; // 0x6
    field public static final int ACCESS_FLAG_MASK_USER = 24; // 0x18
+5 −39
Original line number Diff line number Diff line
@@ -107,7 +107,6 @@ import java.util.concurrent.Executor;
@SystemService(Context.APP_FUNCTION_SERVICE)
public final class AppFunctionManager {

    // TODO(b/427993624): Expose Uri once ContentProvider is added
    /**
     * The contract between the AppFunction access history provider and applications with read
     * permission. Contains definitions for the supported URIs and columns.
@@ -843,10 +842,11 @@ public final class AppFunctionManager {
     */
    @FlaggedApi(FLAG_APP_FUNCTION_ACCESS_UI_ENABLED)
    public @NonNull Intent createRequestAccessIntent(@NonNull String targetPackageName) {
        Intent intent = new Intent(ACTION_REQUEST_APP_FUNCTION_ACCESS);
        intent.putExtra(Intent.EXTRA_PACKAGE_NAME, targetPackageName);
        intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());
        return intent;
        try {
            return mService.createRequestAccessIntent(targetPackageName);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
@@ -889,40 +889,6 @@ public final class AppFunctionManager {
        }
    }

    // TODO(b/413093397): Remove once list is ready for permanent enable.
    /**
     * Gets whether or not the agent allowlist is enabled.
     *
     * @hide
     */
    @TestApi
    @RequiresPermission(MANAGE_APP_FUNCTION_ACCESS)
    @FlaggedApi(Flags.FLAG_APP_FUNCTION_ACCESS_API_ENABLED)
    public boolean isAgentAllowlistEnabled() {
        try {
            return mService.isAgentAllowlistEnabled();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Gets whether or not the agent allowlist is enabled TODO b/413093397: Remove once list is
     * ready for permanent enable
     *
     * @hide
     */
    @TestApi
    @RequiresPermission(MANAGE_APP_FUNCTION_ACCESS)
    @FlaggedApi(Flags.FLAG_APP_FUNCTION_ACCESS_API_ENABLED)
    public void setAgentAllowlistEnabled(boolean enabled) {
        try {
            mService.setAgentAllowlistEnabled(enabled);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Clear the access history data.
     *
+3 −6
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.app.appfunctions.IAppFunctionEnabledCallback;
import android.app.appfunctions.IExecuteAppFunctionCallback;
import android.os.ICancellationSignal;
import android.os.UserHandle;
import android.content.Intent;
import android.content.pm.SignedPackageParcel;

import java.util.List;
@@ -89,12 +90,8 @@ interface IAppFunctionManager {
    @EnforcePermission("MANAGE_APP_FUNCTION_ACCESS")
    List<SignedPackageParcel> getAgentAllowlist();

    @EnforcePermission("MANAGE_APP_FUNCTION_ACCESS")
    void setAgentAllowlistEnabled(boolean enabled);

    @EnforcePermission("MANAGE_APP_FUNCTION_ACCESS")
    boolean isAgentAllowlistEnabled();

    @EnforcePermission("MANAGE_APP_FUNCTION_ACCESS")
    void clearAccessHistory(int userId);

    Intent createRequestAccessIntent(in String targetPackageName);
}
+16 −39
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.appfunctions;

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

@@ -163,9 +164,6 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
    @GuardedBy("mAgentAllowlistLock")
    private ArraySet<SignedPackage> mAgentAllowlist = new ArraySet<>(sSystemAllowlist);

    @GuardedBy("mAgentAllowlistLock")
    private boolean mAgentAllowlistEnabled = false;

    private final ContentObserver mAdbAgentObserver =
            new ContentObserver(FgThread.getHandler()) {
                @Override
@@ -663,37 +661,6 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
        }
    }

    @Override
    @EnforcePermission(Manifest.permission.MANAGE_APP_FUNCTION_ACCESS)
    public void setAgentAllowlistEnabled(boolean enabled) {
        setAgentAllowlistEnabled_enforcePermission();
        if (!accessCheckFlagsEnabled()) {
            return;
        }

        synchronized (mAgentAllowlistLock) {
            if (enabled == mAgentAllowlistEnabled) {
                return;
            }

            mAgentAllowlistEnabled = enabled;
            if (enabled) {
                mAppFunctionAccessService.setAgentAllowlist(mAgentAllowlist);
            } else {
                mAppFunctionAccessService.setAgentAllowlist(null);
            }
        }
    }

    @Override
    @EnforcePermission(Manifest.permission.MANAGE_APP_FUNCTION_ACCESS)
    public boolean isAgentAllowlistEnabled() {
        isAgentAllowlistEnabled_enforcePermission();
        synchronized (mAgentAllowlistLock) {
            return mAgentAllowlistEnabled;
        }
    }

    @Override
    @EnforcePermission(Manifest.permission.MANAGE_APP_FUNCTION_ACCESS)
    public void clearAccessHistory(int userId) {
@@ -746,19 +713,17 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
            mUpdatableAgentAllowlist = newDeviceConfigAgents;
            mSecureSettingAgentAllowlist = newAdbAgents;
            mAgentAllowlist = newAgents;
            if (mAgentAllowlistEnabled) {
            mAppFunctionAccessService.setAgentAllowlist(mAgentAllowlist);
        }
    }
    }

    @Nullable
    @WorkerThread
    private List<SignedPackage> readDeviceConfigAgentAllowlist() {
        final String allowlistString =
                DeviceConfig.getString(
                        NAMESPACE_MACHINE_LEARNING, ALLOWLISTED_APP_FUNCTIONS_AGENTS, null);
        if (allowlistString != null) {
                        NAMESPACE_MACHINE_LEARNING, ALLOWLISTED_APP_FUNCTIONS_AGENTS, "");
        if (!TextUtils.isEmpty(allowlistString)) {
            try {
                List<SignedPackage> parsedAllowlist =
                        SignedPackageParser.parseList(allowlistString);
@@ -814,6 +779,18 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
        }
    }

    @Override
    @NonNull
    public Intent createRequestAccessIntent(@NonNull String targetPackageName) {
        Objects.requireNonNull(targetPackageName);
        final String permissionOwner =
                mDeviceSettingHelper.getPermissionOwnerPackage(targetPackageName);
        Intent intent = new Intent(ACTION_REQUEST_APP_FUNCTION_ACCESS);
        intent.putExtra(Intent.EXTRA_PACKAGE_NAME, permissionOwner);
        intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());
        return intent;
    }

    private boolean accessCheckFlagsEnabled() {
        return android.permission.flags.Flags.appFunctionAccessApiEnabled()
                && android.permission.flags.Flags.appFunctionAccessServiceEnabled();
+41 −23
Original line number Diff line number Diff line
@@ -35,8 +35,6 @@ import android.provider.DeviceConfig
import android.testing.TestableContext
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
import com.android.internal.R
import com.android.modules.utils.testing.ExtendedMockitoRule
import com.android.server.LocalServices
@@ -47,7 +45,6 @@ import com.google.common.truth.Truth.assertThat
import com.google.common.util.concurrent.MoreExecutors
import kotlinx.coroutines.test.runTest
import org.junit.After
import org.junit.Before
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
@@ -55,7 +52,6 @@ import org.junit.runner.RunWith
import org.mockito.kotlin.any
import org.mockito.kotlin.anyOrNull
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.clearInvocations
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
@@ -101,27 +97,8 @@ class AppFunctionManagerServiceImplTest {
            MoreExecutors.directExecutor(),
        )

    @Before
    fun setup() {
        allowlistWasEnabled = callWithShellPermissionIdentity {
            serviceImpl.isAgentAllowlistEnabled()
        }
        if (!allowlistWasEnabled) {
            runWithShellPermissionIdentity {
                serviceImpl.setAgentAllowlistEnabled(true)
                clearInvocations(appFunctionAccessService)
            }
        }
    }

    @After
    fun clearState() {
        if (!allowlistWasEnabled) {
            runWithShellPermissionIdentity {
                serviceImpl.setAgentAllowlistEnabled(false)
                clearInvocations(appFunctionAccessService)
            }
        }
        clearDeviceSettingPackages()
        clearPreloadedAllowlist()
        setDeviceConfigAllowlist(null)
@@ -414,6 +391,26 @@ class AppFunctionManagerServiceImplTest {
        assertThat(capturedSet).contains(expectedPackages)
    }

    @RequiresFlagsEnabled(
        FLAG_APP_FUNCTION_ACCESS_SERVICE_ENABLED,
        FLAG_APP_FUNCTION_ACCESS_API_ENABLED,
    )
    @Test
    fun onBootPhase_initiateAgentAllowlistToStored_whenDeviceConfigEmpty() {
        setDeviceConfigAllowlist("")
        val stored = SignedPackageParser.parseList("com.example.test2:abcdef0123456789")
        whenever(agentAllowlistStorage.readPreviousValidAllowlist()).thenReturn(stored)
        setPreloadedAllowlist(arrayOf("com.example.preload1:111111", "com.example.preload2:222222"))

        serviceImpl.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY)

        verify(appFunctionAccessService).setAgentAllowlist(agentAllowlistCaptor.capture())
        val capturedSet = agentAllowlistCaptor.firstValue
        val expectedPackages =
            SignedPackage("com.example.test2", Signature("abcdef0123456789").toByteArray())
        assertThat(capturedSet).contains(expectedPackages)
    }

    @RequiresFlagsEnabled(
        FLAG_APP_FUNCTION_ACCESS_SERVICE_ENABLED,
        FLAG_APP_FUNCTION_ACCESS_API_ENABLED,
@@ -435,6 +432,27 @@ class AppFunctionManagerServiceImplTest {
        assertThat(capturedSet).containsAtLeast(expectedPackage1, expectedPackage2)
    }

    @RequiresFlagsEnabled(
        FLAG_APP_FUNCTION_ACCESS_SERVICE_ENABLED,
        FLAG_APP_FUNCTION_ACCESS_API_ENABLED,
    )
    @Test
    fun onBootPhase_initiateAgentAllowlistToPreload_whenDeviceConfigEmptyNoStored() {
        setDeviceConfigAllowlist("")
        setPreloadedAllowlist(arrayOf("com.example.preload1:111111", "com.example.preload2:222222"))
        whenever(agentAllowlistStorage.readPreviousValidAllowlist()).thenReturn(null)

        serviceImpl.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY)

        verify(appFunctionAccessService).setAgentAllowlist(agentAllowlistCaptor.capture())
        val capturedSet = agentAllowlistCaptor.firstValue
        val expectedPackage1 =
            SignedPackage("com.example.preload1", Signature("111111").toByteArray())
        val expectedPackage2 =
            SignedPackage("com.example.preload2", Signature("222222").toByteArray())
        assertThat(capturedSet).containsAtLeast(expectedPackage1, expectedPackage2)
    }

    @RequiresFlagsEnabled(
        FLAG_APP_FUNCTION_ACCESS_SERVICE_ENABLED,
        FLAG_APP_FUNCTION_ACCESS_API_ENABLED,