diff options
author | 2024-11-27 14:05:57 +0000 | |
---|---|---|
committer | 2024-12-04 17:35:00 +0000 | |
commit | 6e256ccab44f5e3a6b544adb87650e709ada561f (patch) | |
tree | 91f5dc78adae3163597b355e3fd1871ffe568200 | |
parent | 7a4b6865f49ce4297d4d5c24a3bac3f29716afde (diff) |
Respect enterprise policy in AppFunctions
Flag: android.app.appfunctions.flags.enable_app_function_manager
Test: atest CtsAppFunctionTestCases -c
Bug: 380442826
Change-Id: I277df0eade4787f906d426cfa5572f441747ad39
7 files changed, 63 insertions, 28 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 0fe8717e8954..f0763733f36b 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -8878,6 +8878,7 @@ package android.app.appfunctions { field public static final int ERROR_CATEGORY_UNKNOWN = 0; // 0x0 field public static final int ERROR_DENIED = 1000; // 0x3e8 field public static final int ERROR_DISABLED = 1002; // 0x3ea + field public static final int ERROR_ENTERPRISE_POLICY_DISALLOWED = 2002; // 0x7d2 field public static final int ERROR_FUNCTION_NOT_FOUND = 1003; // 0x3eb field public static final int ERROR_INVALID_ARGUMENT = 1001; // 0x3e9 field public static final int ERROR_SYSTEM_ERROR = 2000; // 0x7d0 diff --git a/core/java/android/app/appfunctions/AppFunctionException.java b/core/java/android/app/appfunctions/AppFunctionException.java index c8d80d3afe43..d8179c7540d9 100644 --- a/core/java/android/app/appfunctions/AppFunctionException.java +++ b/core/java/android/app/appfunctions/AppFunctionException.java @@ -32,8 +32,8 @@ import java.util.Objects; /** * Represents an app function related error. * - * <p>This exception may include an {@link AppFunctionException#getExtras() Bundle} - * containing additional error-specific metadata. + * <p>This exception may include an {@link AppFunctionException#getExtras() Bundle} containing + * additional error-specific metadata. * * <p>The AppFunction SDK can expose structured APIs by packing and unpacking this Bundle. */ @@ -85,6 +85,13 @@ public final class AppFunctionException extends Exception implements Parcelable public static final int ERROR_CANCELLED = 2001; /** + * The operation was disallowed by enterprise policy. + * + * <p>This error is in the {@link #ERROR_CATEGORY_SYSTEM} category. + */ + public static final int ERROR_ENTERPRISE_POLICY_DISALLOWED = 2002; + + /** * An unknown error occurred while processing the call in the AppFunctionService. * * <p>This error is thrown when the service is connected in the remote application but an @@ -231,7 +238,8 @@ public final class AppFunctionException extends Exception implements Parcelable ERROR_SYSTEM_ERROR, ERROR_INVALID_ARGUMENT, ERROR_DISABLED, - ERROR_CANCELLED + ERROR_CANCELLED, + ERROR_ENTERPRISE_POLICY_DISALLOWED }) @Retention(RetentionPolicy.SOURCE) public @interface ErrorCode {} diff --git a/libs/appfunctions/api/current.txt b/libs/appfunctions/api/current.txt index de402095e195..139ccfd22b0e 100644 --- a/libs/appfunctions/api/current.txt +++ b/libs/appfunctions/api/current.txt @@ -16,6 +16,7 @@ package com.android.extensions.appfunctions { field public static final int ERROR_CATEGORY_UNKNOWN = 0; // 0x0 field public static final int ERROR_DENIED = 1000; // 0x3e8 field public static final int ERROR_DISABLED = 1002; // 0x3ea + field public static final int ERROR_ENTERPRISE_POLICY_DISALLOWED = 2002; // 0x7d2 field public static final int ERROR_FUNCTION_NOT_FOUND = 1003; // 0x3eb field public static final int ERROR_INVALID_ARGUMENT = 1001; // 0x3e9 field public static final int ERROR_SYSTEM_ERROR = 2000; // 0x7d0 diff --git a/libs/appfunctions/java/com/android/extensions/appfunctions/AppFunctionException.java b/libs/appfunctions/java/com/android/extensions/appfunctions/AppFunctionException.java index 2540236f2ce5..0c521690b165 100644 --- a/libs/appfunctions/java/com/android/extensions/appfunctions/AppFunctionException.java +++ b/libs/appfunctions/java/com/android/extensions/appfunctions/AppFunctionException.java @@ -71,6 +71,13 @@ public final class AppFunctionException extends Exception { public static final int ERROR_CANCELLED = 2001; /** + * The operation was disallowed by enterprise policy. + * + * <p>This error is in the {@link #ERROR_CATEGORY_SYSTEM} category. + */ + public static final int ERROR_ENTERPRISE_POLICY_DISALLOWED = 2002; + + /** * An unknown error occurred while processing the call in the AppFunctionService. * * <p>This error is thrown when the service is connected in the remote application but an @@ -189,7 +196,8 @@ public final class AppFunctionException extends Exception { ERROR_SYSTEM_ERROR, ERROR_INVALID_ARGUMENT, ERROR_DISABLED, - ERROR_CANCELLED + ERROR_CANCELLED, + ERROR_ENTERPRISE_POLICY_DISALLOWED }) @Retention(RetentionPolicy.SOURCE) public @interface ErrorCode {} diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java index f13e22950e2d..c17c34061d1b 100644 --- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java +++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java @@ -24,12 +24,12 @@ import static com.android.server.appfunctions.AppFunctionExecutors.THREAD_POOL_E import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.WorkerThread; +import android.app.appfunctions.AppFunctionException; import android.app.appfunctions.AppFunctionManager; import android.app.appfunctions.AppFunctionManagerHelper; import android.app.appfunctions.AppFunctionRuntimeMetadata; import android.app.appfunctions.AppFunctionStaticMetadataHelper; import android.app.appfunctions.ExecuteAppFunctionAidlRequest; -import android.app.appfunctions.AppFunctionException; import android.app.appfunctions.IAppFunctionEnabledCallback; import android.app.appfunctions.IAppFunctionManager; import android.app.appfunctions.IAppFunctionService; @@ -158,8 +158,7 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { } catch (SecurityException exception) { safeExecuteAppFunctionCallback.onError( new AppFunctionException( - AppFunctionException.ERROR_DENIED, - exception.getMessage())); + AppFunctionException.ERROR_DENIED, exception.getMessage())); return null; } @@ -195,12 +194,12 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { @NonNull SafeOneTimeExecuteAppFunctionCallback safeExecuteAppFunctionCallback, @NonNull IBinder callerBinder) { UserHandle targetUser = requestInternal.getUserHandle(); - // TODO(b/354956319): Add and honor the new enterprise policies. - if (mCallerValidator.isUserOrganizationManaged(targetUser)) { + UserHandle callingUser = UserHandle.getUserHandleForUid(callingUid); + if (!mCallerValidator.verifyEnterprisePolicyIsAllowed(callingUser, targetUser)) { safeExecuteAppFunctionCallback.onError( - new AppFunctionException(AppFunctionException.ERROR_SYSTEM_ERROR, - "Cannot run on a device with a device owner or from the managed" - + " profile.")); + new AppFunctionException( + AppFunctionException.ERROR_ENTERPRISE_POLICY_DISALLOWED, + "Cannot run on a user with a restricted enterprise policy")); return; } @@ -442,7 +441,8 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { if (!bindServiceResult) { Slog.e(TAG, "Failed to bind to the AppFunctionService"); safeExecuteAppFunctionCallback.onError( - new AppFunctionException(AppFunctionException.ERROR_SYSTEM_ERROR, + new AppFunctionException( + AppFunctionException.ERROR_SYSTEM_ERROR, "Failed to bind the AppFunctionService.")); } } @@ -495,8 +495,7 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { return; } FutureGlobalSearchSession futureGlobalSearchSession = - new FutureGlobalSearchSession( - perUserAppSearchManager, AppFunctionExecutors.THREAD_POOL_EXECUTOR); + new FutureGlobalSearchSession(perUserAppSearchManager, THREAD_POOL_EXECUTOR); AppFunctionMetadataObserver appFunctionMetadataObserver = new AppFunctionMetadataObserver( user.getUserHandle(), diff --git a/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java b/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java index 5393b939b5ed..61917676e88d 100644 --- a/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java +++ b/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java @@ -81,10 +81,12 @@ public interface CallerValidator { @NonNull String functionId); /** - * Checks if the user is organization managed. + * Checks if the app function policy is allowed. * + * @param callingUser The current calling user. * @param targetUser The user which the caller is requesting to execute as. - * @return Whether the user is organization managed. + * @return Whether the app function policy is allowed. */ - boolean isUserOrganizationManaged(@NonNull UserHandle targetUser); + boolean verifyEnterprisePolicyIsAllowed( + @NonNull UserHandle callingUser, @NonNull UserHandle targetUser); } diff --git a/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java b/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java index e85a70d5845a..69481c32baf0 100644 --- a/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java +++ b/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java @@ -28,6 +28,7 @@ import android.annotation.BinderThread; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.app.admin.DevicePolicyManager; +import android.app.admin.DevicePolicyManager.AppFunctionsPolicy; import android.app.appsearch.AppSearchBatchResult; import android.app.appsearch.AppSearchManager; import android.app.appsearch.AppSearchManager.SearchContext; @@ -39,7 +40,6 @@ import android.content.pm.PackageManager; import android.os.Binder; import android.os.Process; import android.os.UserHandle; -import android.os.UserManager; import com.android.internal.infra.AndroidFuture; @@ -124,8 +124,7 @@ class CallerValidatorImpl implements CallerValidator { FutureAppSearchSession futureAppSearchSession = new FutureAppSearchSessionImpl( Objects.requireNonNull( - mContext - .createContextAsUser(targetUser, 0) + mContext.createContextAsUser(targetUser, 0) .getSystemService(AppSearchManager.class)), THREAD_POOL_EXECUTOR, new SearchContext.Builder(APP_FUNCTION_STATIC_METADATA_DB).build()); @@ -168,13 +167,16 @@ class CallerValidatorImpl implements CallerValidator { } @Override - public boolean isUserOrganizationManaged(@NonNull UserHandle targetUser) { - if (Objects.requireNonNull(mContext.getSystemService(DevicePolicyManager.class)) - .isDeviceManaged()) { - return true; - } - return Objects.requireNonNull(mContext.getSystemService(UserManager.class)) - .isManagedProfile(targetUser.getIdentifier()); + public boolean verifyEnterprisePolicyIsAllowed( + @NonNull UserHandle callingUser, @NonNull UserHandle targetUser) { + @AppFunctionsPolicy + int callingUserPolicy = getDevicePolicyManagerAsUser(callingUser).getAppFunctionsPolicy(); + @AppFunctionsPolicy + int targetUserPolicy = getDevicePolicyManagerAsUser(targetUser).getAppFunctionsPolicy(); + boolean isSameUser = callingUser.equals(targetUser); + + return isAppFunctionPolicyAllowed(targetUserPolicy, isSameUser) + && isAppFunctionPolicyAllowed(callingUserPolicy, isSameUser); } /** @@ -264,4 +266,18 @@ class CallerValidatorImpl implements CallerValidator { return Process.INVALID_UID; } } + + private boolean isAppFunctionPolicyAllowed( + @AppFunctionsPolicy int userPolicy, boolean isSameUser) { + return switch (userPolicy) { + case DevicePolicyManager.APP_FUNCTIONS_NOT_CONTROLLED_BY_POLICY -> true; + case DevicePolicyManager.APP_FUNCTIONS_DISABLED_CROSS_PROFILE -> isSameUser; + default -> false; + }; + } + + private DevicePolicyManager getDevicePolicyManagerAsUser(@NonNull UserHandle targetUser) { + return mContext.createContextAsUser(targetUser, /* flags= */ 0) + .getSystemService(DevicePolicyManager.class); + } } |