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

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

Merge "Fix access check to check permission owner as target" into main

parents 862a2a54 c68c2333
Loading
Loading
Loading
Loading
+15 −43
Original line number Diff line number Diff line
@@ -82,7 +82,6 @@ import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
@@ -112,7 +111,6 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
    private static final String ALLOWLISTED_APP_FUNCTIONS_AGENTS =
            "allowlisted_app_functions_agents";
    private static final String NAMESPACE_MACHINE_LEARNING = "machine_learning";
    private static final String ANDROID_PACKAGE_NAME = "android";

    private final RemoteServiceCaller<IAppFunctionService> mRemoteServiceCaller;
    private final CallerValidator mCallerValidator;
@@ -133,11 +131,7 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {

    private final IBinder mPermissionOwner;

    private final Object mDeviceSettingPackagesLock = new Object();

    @Nullable
    @GuardedBy("mDeviceSettingPackagesLock")
    private Set<String> mDeviceSettingPackages;
    private final DeviceSettingHelper mDeviceSettingHelper;

    private final Object mAgentAllowlistLock = new Object();

@@ -162,7 +156,8 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
                packageManagerInternal,
                appFunctionAccessServiceInterface,
                uriGrantsManager,
                uriGrantsManagerInternal);
                uriGrantsManagerInternal,
                new DeviceSettingHelperImpl(context));
    }

    @VisibleForTesting
@@ -176,7 +171,8 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
            PackageManagerInternal packageManagerInternal,
            AppFunctionAccessServiceInterface appFunctionAccessServiceInterface,
            IUriGrantsManager uriGrantsManager,
            UriGrantsManagerInternal uriGrantsManagerInternal) {
            UriGrantsManagerInternal uriGrantsManagerInternal,
            DeviceSettingHelper deviceSettingHelper) {
        mContext = Objects.requireNonNull(context);
        mRemoteServiceCaller = Objects.requireNonNull(remoteServiceCaller);
        mCallerValidator = Objects.requireNonNull(callerValidator);
@@ -188,6 +184,7 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
        mUriGrantsManager = Objects.requireNonNull(uriGrantsManager);
        mUriGrantsManagerInternal = Objects.requireNonNull(uriGrantsManagerInternal);
        mPermissionOwner = mUriGrantsManagerInternal.newUriPermissionOwner("appfunctions");
        mDeviceSettingHelper = deviceSettingHelper;
    }

    /** Called when the user is unlocked. */
@@ -544,7 +541,8 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
        if (!accessCheckFlagsEnabled()) {
            return 0;
        }
        final String targetPermissionOwner = getPermissionOwnerPackage(targetPackageName);
        final String targetPermissionOwner =
                mDeviceSettingHelper.getPermissionOwnerPackage(targetPackageName);
        return mAppFunctionAccessService.getAccessFlags(
                agentPackageName, agentUserId, targetPermissionOwner, targetUserId);
    }
@@ -561,7 +559,8 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
        if (!accessCheckFlagsEnabled()) {
            return false;
        }
        final String targetPermissionOwner = getPermissionOwnerPackage(targetPackageName);
        final String targetPermissionOwner =
                mDeviceSettingHelper.getPermissionOwnerPackage(targetPackageName);
        return mAppFunctionAccessService.updateAccessFlags(
                agentPackageName,
                agentUserId,
@@ -576,7 +575,8 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
        if (!accessCheckFlagsEnabled()) {
            return;
        }
        final String targetPermissionOwner = getPermissionOwnerPackage(targetPackageName);
        final String targetPermissionOwner =
                mDeviceSettingHelper.getPermissionOwnerPackage(targetPackageName);
        mAppFunctionAccessService.revokeSelfAccess(targetPermissionOwner);
    }

@@ -587,7 +587,8 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
        if (!accessCheckFlagsEnabled()) {
            return ACCESS_REQUEST_STATE_UNREQUESTABLE;
        }
        final String targetPermissionOwner = getPermissionOwnerPackage(targetPackageName);
        final String targetPermissionOwner =
                mDeviceSettingHelper.getPermissionOwnerPackage(targetPackageName);
        return mAppFunctionAccessService.getAccessRequestState(
                agentPackageName, agentUserId, targetPermissionOwner, targetUserId);
    }
@@ -611,42 +612,13 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
        final int validTargetSize = validTargets.size();
        for (int i = 0; i < validTargetSize; i++) {
            final String target = validTargets.get(i);
            final String permissionOwner = getPermissionOwnerPackage(target);
            final String permissionOwner = mDeviceSettingHelper.getPermissionOwnerPackage(target);
            validPermissionOwnerTargets.add(permissionOwner);
        }

        return List.copyOf(validPermissionOwnerTargets);
    }

    /**
     * Returns the permission owner's package name.
     *
     * <p>For apps that is set as part of config_appFunctionsDeviceSettingsPackages, the access
     * permission is controlled as "android".
     */
    @NonNull
    private String getPermissionOwnerPackage(@NonNull String packageName) {
        final Set<String> deviceSettingPackages = getDeviceSettingPackages();
        if (deviceSettingPackages.contains(packageName)) {
            return ANDROID_PACKAGE_NAME;
        }
        return packageName;
    }

    @NonNull
    private Set<String> getDeviceSettingPackages() {
        synchronized (mDeviceSettingPackagesLock) {
            if (mDeviceSettingPackages != null) {
                return mDeviceSettingPackages;
            }
            final String[] deviceSettingPackages =
                    mContext.getResources()
                            .getStringArray(R.array.config_appFunctionDeviceSettingsPackages);
            mDeviceSettingPackages = new ArraySet<>(deviceSettingPackages);
            return mDeviceSettingPackages;
        }
    }

    private boolean accessCheckFlagsEnabled() {
        return android.permission.flags.Flags.appFunctionAccessApiEnabled()
                && android.permission.flags.Flags.appFunctionAccessServiceEnabled();
+10 −2
Original line number Diff line number Diff line
@@ -40,11 +40,14 @@ class CallerValidatorImpl implements CallerValidator {
    private final Context mContext;
    private final AppFunctionAccessServiceInterface mAppFunctionAccessService;

    private final DeviceSettingHelper mDeviceSettingHelper;

    CallerValidatorImpl(
            @NonNull Context context,
            @NonNull AppFunctionAccessServiceInterface appFunctionAccessService) {
        mContext = Objects.requireNonNull(context);
        mAppFunctionAccessService = Objects.requireNonNull(appFunctionAccessService);
        mDeviceSettingHelper = new DeviceSettingHelperImpl(context);
    }

    @Override
@@ -100,7 +103,7 @@ class CallerValidatorImpl implements CallerValidator {
                mAppFunctionAccessService.getAccessRequestState(
                        callerPackageName,
                        UserHandle.getUserId(callingUid),
                        targetPackageName,
                        mDeviceSettingHelper.getPermissionOwnerPackage(targetPackageName),
                        targetUser.getIdentifier());
        boolean hasAccessPermission =
                requestState == AppFunctionManager.ACCESS_REQUEST_STATE_GRANTED;
@@ -143,6 +146,11 @@ class CallerValidatorImpl implements CallerValidator {
            @NonNull String callerPackageName,
            @NonNull String targetPackageName,
            @NonNull String functionId) {
        if (callingUid == Process.ROOT_UID) {
            // Bypass any validation if calling from ROOT_ID since it is not an actual package
            // to verify.
            return AndroidFuture.completedFuture(CAN_EXECUTE_APP_FUNCTIONS_ALLOWED_HAS_PERMISSION);
        }

        if (Flags.appFunctionAccessApiEnabled() && Flags.appFunctionAccessServiceEnabled()) {
            return verifyCallerCanExecuteAppFunctionWithAccessService(
+31 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.appfunctions;

import android.annotation.NonNull;

/** Helper interface for managing DeviceSetting related functionality. */
public interface DeviceSettingHelper {
    /**
     * Returns the permission owner's package name.
     *
     * <p>For apps that is set as part of config_appFunctionsDeviceSettingsPackages, the access
     * permission is controlled as "android".
     */
    @NonNull
    String getPermissionOwnerPackage(@NonNull String packageName);
}
+66 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.appfunctions;

import android.annotation.NonNull;
import android.content.Context;
import android.util.ArraySet;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;

import java.util.Objects;
import java.util.Set;

public final class DeviceSettingHelperImpl implements DeviceSettingHelper {
    private static final String ANDROID_PACKAGE_NAME = "android";

    @NonNull private final Context mContext;

    private final Object mDeviceSettingPackagesLock = new Object();

    @GuardedBy("mDeviceSettingPackagesLock")
    private Set<String> mDeviceSettingPackages;

    public DeviceSettingHelperImpl(@NonNull Context context) {
        mContext = Objects.requireNonNull(context);
    }

    @NonNull
    @Override
    public String getPermissionOwnerPackage(@NonNull String packageName) {
        final Set<String> deviceSettingPackages = getDeviceSettingPackages();
        if (deviceSettingPackages.contains(packageName)) {
            return ANDROID_PACKAGE_NAME;
        }
        return packageName;
    }

    @NonNull
    private Set<String> getDeviceSettingPackages() {
        synchronized (mDeviceSettingPackagesLock) {
            if (mDeviceSettingPackages != null) {
                return mDeviceSettingPackages;
            }
            final String[] deviceSettingPackages =
                    mContext.getResources()
                            .getStringArray(R.array.config_appFunctionDeviceSettingsPackages);
            mDeviceSettingPackages = new ArraySet<>(deviceSettingPackages);
            return mDeviceSettingPackages;
        }
    }
}
+2 −1
Original line number Diff line number Diff line
@@ -77,7 +77,8 @@ class AppFunctionsLoggingTest {
            mock<PackageManagerInternal>(),
            mock<AppFunctionAccessServiceInterface>(),
            mock<IUriGrantsManager>(),
            mock<UriGrantsManagerInternal>()
            mock<UriGrantsManagerInternal>(),
            mock<DeviceSettingHelper>(),
        )

    private val mRequestInternal =