diff options
3 files changed, 73 insertions, 81 deletions
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java index d0ee7af1bbfb..5191fb5f51cb 100644 --- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java +++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java @@ -20,6 +20,8 @@ import static android.app.appfunctions.AppFunctionRuntimeMetadata.APP_FUNCTION_R import static android.app.appfunctions.AppFunctionRuntimeMetadata.APP_FUNCTION_RUNTIME_NAMESPACE; import static com.android.server.appfunctions.AppFunctionExecutors.THREAD_POOL_EXECUTOR; +import static com.android.server.appfunctions.CallerValidator.CAN_EXECUTE_APP_FUNCTIONS_ALLOWED_HAS_PERMISSION; +import static com.android.server.appfunctions.CallerValidator.CAN_EXECUTE_APP_FUNCTIONS_DENIED; import android.annotation.NonNull; import android.annotation.Nullable; @@ -236,30 +238,42 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { requestInternal.getCallingPackage(), targetPackageName, requestInternal.getClientRequest().getFunctionIdentifier()) - .thenAccept( - canExecute -> { - if (!canExecute) { - throw new SecurityException( + .thenCompose( + canExecuteResult -> { + if (canExecuteResult == CAN_EXECUTE_APP_FUNCTIONS_DENIED) { + return AndroidFuture.failedFuture(new SecurityException( "Caller does not have permission to execute the" - + " appfunction"); + + " appfunction")); } + return isAppFunctionEnabled( + requestInternal + .getClientRequest() + .getFunctionIdentifier(), + requestInternal + .getClientRequest() + .getTargetPackageName(), + getAppSearchManagerAsUser( + requestInternal.getUserHandle()), + THREAD_POOL_EXECUTOR) + .thenApply( + isEnabled -> { + if (!isEnabled) { + throw new DisabledAppFunctionException( + "The app function is disabled"); + } + return canExecuteResult; + }); }) - .thenCompose( - isEnabled -> - isAppFunctionEnabled( - requestInternal.getClientRequest().getFunctionIdentifier(), - requestInternal.getClientRequest().getTargetPackageName(), - getAppSearchManagerAsUser(requestInternal.getUserHandle()), - THREAD_POOL_EXECUTOR)) .thenAccept( - isEnabled -> { - if (!isEnabled) { - throw new DisabledAppFunctionException( - "The app function is disabled"); + canExecuteResult -> { + int bindFlags = Context.BIND_AUTO_CREATE; + if (canExecuteResult + == CAN_EXECUTE_APP_FUNCTIONS_ALLOWED_HAS_PERMISSION) { + // If the caller doesn't have the permission, do not use + // BIND_FOREGROUND_SERVICE to avoid it raising its process state by + // calling its own AppFunctions. + bindFlags |= Context.BIND_FOREGROUND_SERVICE; } - }) - .thenAccept( - unused -> { Intent serviceIntent = mInternalServiceHelper.resolveAppFunctionService( targetPackageName, targetUser); @@ -294,8 +308,7 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { targetUser, localCancelTransport, safeExecuteAppFunctionCallback, - /* bindFlags= */ Context.BIND_AUTO_CREATE - | Context.BIND_FOREGROUND_SERVICE, + bindFlags, callerBinder, callingUid); }) diff --git a/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java b/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java index 98ef974b9443..c8038a4e56df 100644 --- a/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java +++ b/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java @@ -17,12 +17,16 @@ package com.android.server.appfunctions; import android.Manifest; +import android.annotation.IntDef; import android.annotation.NonNull; import android.os.UserHandle; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.infra.AndroidFuture; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Interface for validating that the caller has the correct privilege to call an AppFunctionManager * API. @@ -70,7 +74,8 @@ public interface CallerValidator { * @param functionId The id of the app function to execute. * @return Whether the caller can execute the specified app function. */ - AndroidFuture<Boolean> verifyCallerCanExecuteAppFunction( + @CanExecuteAppFunctionResult + AndroidFuture<Integer> verifyCallerCanExecuteAppFunction( int callingUid, int callingPid, @NonNull UserHandle targetUser, @@ -78,6 +83,31 @@ public interface CallerValidator { @NonNull String targetPackageName, @NonNull String functionId); + @IntDef( + prefix = {"CAN_EXECUTE_APP_FUNCTIONS_"}, + value = { + CAN_EXECUTE_APP_FUNCTIONS_DENIED, + CAN_EXECUTE_APP_FUNCTIONS_ALLOWED_SAME_PACKAGE, + CAN_EXECUTE_APP_FUNCTIONS_ALLOWED_HAS_PERMISSION, + }) + @Retention(RetentionPolicy.SOURCE) + @interface CanExecuteAppFunctionResult {} + + /** Callers are not allowed to execute app functions. */ + int CAN_EXECUTE_APP_FUNCTIONS_DENIED = 0; + + /** + * Callers can execute app functions because they are calling app functions from the same + * package. + */ + int CAN_EXECUTE_APP_FUNCTIONS_ALLOWED_SAME_PACKAGE = 1; + + /** + * Callers can execute app functions because they have the necessary permission. + * This case also applies when a caller with the permission invokes their own app functions. + */ + int CAN_EXECUTE_APP_FUNCTIONS_ALLOWED_HAS_PERMISSION = 2; + /** * Checks if the app function policy is allowed. * diff --git a/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java b/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java index fe163d77c4fc..3f8b2e3316dc 100644 --- a/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java +++ b/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java @@ -16,24 +16,12 @@ package com.android.server.appfunctions; -import static android.app.appfunctions.AppFunctionStaticMetadataHelper.APP_FUNCTION_STATIC_METADATA_DB; -import static android.app.appfunctions.AppFunctionStaticMetadataHelper.APP_FUNCTION_STATIC_NAMESPACE; -import static android.app.appfunctions.AppFunctionStaticMetadataHelper.getDocumentIdForAppFunction; - -import static com.android.server.appfunctions.AppFunctionExecutors.THREAD_POOL_EXECUTOR; - import android.Manifest; 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; -import android.app.appsearch.AppSearchResult; -import android.app.appsearch.GenericDocument; -import android.app.appsearch.GetByDocumentIdRequest; import android.content.Context; import android.content.pm.PackageManager; import android.os.Binder; @@ -84,64 +72,25 @@ class CallerValidatorImpl implements CallerValidator { @Override @RequiresPermission(Manifest.permission.EXECUTE_APP_FUNCTIONS) - public AndroidFuture<Boolean> verifyCallerCanExecuteAppFunction( + @CanExecuteAppFunctionResult + public AndroidFuture<Integer> verifyCallerCanExecuteAppFunction( int callingUid, int callingPid, @NonNull UserHandle targetUser, @NonNull String callerPackageName, @NonNull String targetPackageName, @NonNull String functionId) { - if (callerPackageName.equals(targetPackageName)) { - return AndroidFuture.completedFuture(true); - } - boolean hasExecutionPermission = mContext.checkPermission( - Manifest.permission.EXECUTE_APP_FUNCTIONS, callingPid, callingUid) + Manifest.permission.EXECUTE_APP_FUNCTIONS, callingPid, callingUid) == PackageManager.PERMISSION_GRANTED; - - if (!hasExecutionPermission) { - return AndroidFuture.completedFuture(false); + if (hasExecutionPermission) { + return AndroidFuture.completedFuture(CAN_EXECUTE_APP_FUNCTIONS_ALLOWED_HAS_PERMISSION); } - - FutureAppSearchSession futureAppSearchSession = - new FutureAppSearchSessionImpl( - Objects.requireNonNull( - mContext.createContextAsUser(targetUser, 0) - .getSystemService(AppSearchManager.class)), - THREAD_POOL_EXECUTOR, - new SearchContext.Builder(APP_FUNCTION_STATIC_METADATA_DB).build()); - - String documentId = getDocumentIdForAppFunction(targetPackageName, functionId); - - return futureAppSearchSession - .getByDocumentId( - new GetByDocumentIdRequest.Builder(APP_FUNCTION_STATIC_NAMESPACE) - .addIds(documentId) - .build()) - .thenApply( - batchResult -> getGenericDocumentFromBatchResult(batchResult, documentId)) - // At this point, already checked the app has the permission. - .thenApply(document -> true) - .whenComplete( - (result, throwable) -> { - futureAppSearchSession.close(); - }); - } - - private static GenericDocument getGenericDocumentFromBatchResult( - AppSearchBatchResult<String, GenericDocument> result, String documentId) { - if (result.isSuccess()) { - return result.getSuccesses().get(documentId); + if (callerPackageName.equals(targetPackageName)) { + return AndroidFuture.completedFuture(CAN_EXECUTE_APP_FUNCTIONS_ALLOWED_SAME_PACKAGE); } - - AppSearchResult<GenericDocument> failedResult = result.getFailures().get(documentId); - throw new AppSearchException( - failedResult.getResultCode(), - "Unable to retrieve document with id: " - + documentId - + " due to " - + failedResult.getErrorMessage()); + return AndroidFuture.completedFuture(CAN_EXECUTE_APP_FUNCTIONS_DENIED); } @Override |