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

Commit 43db210f authored by Utkarsh Nigam's avatar Utkarsh Nigam
Browse files

Handle exceptions in AppFunctionManagerServiceImpl

When an exception occurs, the service will return a failure response to the client instead of throwing an exception,

Change-Id: I2aa8d0e22b9edd0334904186dd9bb118f072f4d7
Flag: android.app.appfunctions.flags.enable_app_function_manager
Test: Verified by running locally. Will add CTS in next cl.
Bug: 360864791
parent 7cc8ea4c
Loading
Loading
Loading
Loading
+52 −1
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.os.Binder;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Slog;
import android.app.appsearch.AppSearchResult;

import com.android.internal.annotations.VisibleForTesting;
import com.android.server.appfunctions.RemoteServiceCaller.RunServiceCallCallback;
@@ -81,6 +82,17 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
        final SafeOneTimeExecuteAppFunctionCallback safeExecuteAppFunctionCallback =
                new SafeOneTimeExecuteAppFunctionCallback(executeAppFunctionCallback);

        try {
            executeAppFunctionInternal(requestInternal, safeExecuteAppFunctionCallback);
        } catch (Exception e) {
            safeExecuteAppFunctionCallback.onResult(mapExceptionToExecuteAppFunctionResponse(e));
        }
    }

    private void executeAppFunctionInternal(
            ExecuteAppFunctionAidlRequest requestInternal,
            SafeOneTimeExecuteAppFunctionCallback safeExecuteAppFunctionCallback) {

        String validatedCallingPackage;
        UserHandle targetUser;
        try {
@@ -119,7 +131,7 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
            return;
        }

        mCallerValidator
        var unused = mCallerValidator
                .verifyCallerCanExecuteAppFunction(
                        validatedCallingPackage,
                        targetPackageName,
@@ -159,6 +171,12 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
                            } finally {
                                Binder.restoreCallingIdentity(token);
                            }
                        })
                .exceptionally(
                        ex -> {
                            safeExecuteAppFunctionCallback.onResult(
                                    mapExceptionToExecuteAppFunctionResponse(ex));
                            return null;
                        });
    }

@@ -235,4 +253,37 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
                            /* extras= */ null));
        }
    }

    private ExecuteAppFunctionResponse mapExceptionToExecuteAppFunctionResponse(Throwable e) {
        if (e instanceof AppSearchException) {
            AppSearchException appSearchException = (AppSearchException) e;
            return ExecuteAppFunctionResponse.newFailure(
                    mapAppSearchResultFailureCodeToExecuteAppFunctionResponse(
                            appSearchException.getResultCode()),
                    appSearchException.getMessage(),
                    /* extras= */ null);
        }

        return ExecuteAppFunctionResponse.newFailure(
                ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR,
                e.getMessage(),
                /* extras= */ null);
    }

    private int mapAppSearchResultFailureCodeToExecuteAppFunctionResponse(int resultCode) {
        if (resultCode == AppSearchResult.RESULT_OK) {
            throw new IllegalArgumentException(
                    "This method can only be used to convert failure result codes.");
        }

        switch (resultCode) {
            case AppSearchResult.RESULT_NOT_FOUND:
                return ExecuteAppFunctionResponse.RESULT_INVALID_ARGUMENT;
            case AppSearchResult.RESULT_INVALID_ARGUMENT:
            case AppSearchResult.RESULT_INTERNAL_ERROR:
            case AppSearchResult.RESULT_SECURITY_ERROR:
                // fall-through
        }
        return ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR;
    }
}
+37 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.app.appsearch.AppSearchResult;

/** Exception to wrap failure result codes returned by AppSearch. */
public class AppSearchException extends RuntimeException {
    private final int resultCode;

    public AppSearchException(int resultCode, String message) {
        super(message);
        this.resultCode = resultCode;
    }

    /**
     * Returns the result code used to create this exception, typically one of the {@link
     * AppSearchResult} result codes.
     */
    public int getResultCode() {
        return resultCode;
    }
}
+11 −2
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.app.admin.DevicePolicyManager;
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;
@@ -38,8 +39,9 @@ import android.os.Binder;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import java.util.Objects;

import com.android.internal.infra.AndroidFuture;
import java.util.Objects;

/* Validates that caller has the correct privilege to call an AppFunctionManager Api. */
class CallerValidatorImpl implements CallerValidator {
@@ -144,7 +146,14 @@ class CallerValidatorImpl implements CallerValidator {
        if (result.isSuccess()) {
            return result.getSuccesses().get(documentId);
        }
        throw new IllegalArgumentException("No document in the result for id: " + documentId);

        AppSearchResult<GenericDocument> failedResult = result.getFailures().get(documentId);
        throw new AppSearchException(
                failedResult.getResultCode(),
                "Unable to retrieve document with id: "
                        + documentId
                        + " due to "
                        + failedResult.getErrorMessage());
    }

    private static boolean getRestrictCallersWithExecuteAppFunctionsProperty(