/* * Copyright (C) 2022 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. */ #pragma once #include // Extracted from frameworks/av/media/libaudioclient/include/media/AidlConversionUtil.h namespace android::gui::aidl_utils { /** * Return the equivalent Android status_t from a binder exception code. * * Generally one should use statusTFromBinderStatus() instead. * * Exception codes can be generated from a remote Java service exception, translate * them for use on the Native side. * * Note: for EX_TRANSACTION_FAILED and EX_SERVICE_SPECIFIC a more detailed error code * can be found from transactionError() or serviceSpecificErrorCode(). */ static inline status_t statusTFromExceptionCode(int32_t exceptionCode) { using namespace ::android::binder; switch (exceptionCode) { case Status::EX_NONE: return OK; case Status::EX_SECURITY: // Java SecurityException, rethrows locally in Java return PERMISSION_DENIED; case Status::EX_BAD_PARCELABLE: // Java BadParcelableException, rethrows in Java case Status::EX_ILLEGAL_ARGUMENT: // Java IllegalArgumentException, rethrows in Java case Status::EX_NULL_POINTER: // Java NullPointerException, rethrows in Java return BAD_VALUE; case Status::EX_ILLEGAL_STATE: // Java IllegalStateException, rethrows in Java case Status::EX_UNSUPPORTED_OPERATION: // Java UnsupportedOperationException, rethrows return INVALID_OPERATION; case Status::EX_HAS_REPLY_HEADER: // Native strictmode violation case Status::EX_PARCELABLE: // Java bootclass loader (not standard exception), rethrows case Status::EX_NETWORK_MAIN_THREAD: // Java NetworkOnMainThreadException, rethrows case Status::EX_TRANSACTION_FAILED: // Native - see error code case Status::EX_SERVICE_SPECIFIC: // Java ServiceSpecificException, // rethrows in Java with integer error code return UNKNOWN_ERROR; } return UNKNOWN_ERROR; } /** * Return the equivalent Android status_t from a binder status. * * Used to handle errors from a AIDL method declaration * * [oneway] void method(type0 param0, ...) * * or the following (where return_type is not a status_t) * * return_type method(type0 param0, ...) */ static inline status_t statusTFromBinderStatus(const ::android::binder::Status &status) { return status.isOk() ? OK // check OK, : status.serviceSpecificErrorCode() // service-side error, not standard Java exception // (fromServiceSpecificError) ?: status.transactionError() // a native binder transaction error (fromStatusT) ?: statusTFromExceptionCode(status.exceptionCode()); // a service-side error with a // standard Java exception (fromExceptionCode) } /** * Return a binder::Status from native service status. * * This is used for methods not returning an explicit status_t, * where Java callers expect an exception, not an integer return value. */ static inline ::android::binder::Status binderStatusFromStatusT( status_t status, const char *optionalMessage = nullptr) { const char *const emptyIfNull = optionalMessage == nullptr ? "" : optionalMessage; // From binder::Status instructions: // Prefer a generic exception code when possible, then a service specific // code, and finally a status_t for low level failures or legacy support. // Exception codes and service specific errors map to nicer exceptions for // Java clients. using namespace ::android::binder; switch (status) { case OK: return Status::ok(); case PERMISSION_DENIED: // throw SecurityException on Java side return Status::fromExceptionCode(Status::EX_SECURITY, emptyIfNull); case BAD_VALUE: // throw IllegalArgumentException on Java side return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, emptyIfNull); case INVALID_OPERATION: // throw IllegalStateException on Java side return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, emptyIfNull); } // A service specific error will not show on status.transactionError() so // be sure to use statusTFromBinderStatus() for reliable error handling. // throw a ServiceSpecificException. return Status::fromServiceSpecificError(status, emptyIfNull); } } // namespace android::gui::aidl_utils