Loading services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java +15 −43 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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(); Loading @@ -162,7 +156,8 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { packageManagerInternal, appFunctionAccessServiceInterface, uriGrantsManager, uriGrantsManagerInternal); uriGrantsManagerInternal, new DeviceSettingHelperImpl(context)); } @VisibleForTesting Loading @@ -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); Loading @@ -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. */ Loading Loading @@ -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); } Loading @@ -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, Loading @@ -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); } Loading @@ -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); } Loading @@ -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(); Loading services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java +10 −2 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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( Loading services/appfunctions/java/com/android/server/appfunctions/DeviceSettingHelper.java 0 → 100644 +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); } services/appfunctions/java/com/android/server/appfunctions/DeviceSettingHelperImpl.java 0 → 100644 +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; } } } services/tests/appfunctions/src/com/android/server/appfunctions/AppFunctionsLoggingTest.kt +2 −1 Original line number Diff line number Diff line Loading @@ -77,7 +77,8 @@ class AppFunctionsLoggingTest { mock<PackageManagerInternal>(), mock<AppFunctionAccessServiceInterface>(), mock<IUriGrantsManager>(), mock<UriGrantsManagerInternal>() mock<UriGrantsManagerInternal>(), mock<DeviceSettingHelper>(), ) private val mRequestInternal = Loading Loading
services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java +15 −43 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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(); Loading @@ -162,7 +156,8 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { packageManagerInternal, appFunctionAccessServiceInterface, uriGrantsManager, uriGrantsManagerInternal); uriGrantsManagerInternal, new DeviceSettingHelperImpl(context)); } @VisibleForTesting Loading @@ -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); Loading @@ -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. */ Loading Loading @@ -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); } Loading @@ -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, Loading @@ -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); } Loading @@ -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); } Loading @@ -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(); Loading
services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java +10 −2 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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( Loading
services/appfunctions/java/com/android/server/appfunctions/DeviceSettingHelper.java 0 → 100644 +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); }
services/appfunctions/java/com/android/server/appfunctions/DeviceSettingHelperImpl.java 0 → 100644 +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; } } }
services/tests/appfunctions/src/com/android/server/appfunctions/AppFunctionsLoggingTest.kt +2 −1 Original line number Diff line number Diff line Loading @@ -77,7 +77,8 @@ class AppFunctionsLoggingTest { mock<PackageManagerInternal>(), mock<AppFunctionAccessServiceInterface>(), mock<IUriGrantsManager>(), mock<UriGrantsManagerInternal>() mock<UriGrantsManagerInternal>(), mock<DeviceSettingHelper>(), ) private val mRequestInternal = Loading