blob: 55be27bf3547d59f7d7b5cf9dc0a0210b472db74 [file] [log] [blame]
/*
* 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 <binder/Status.h>
// 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