You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
273 lines
8.6 KiB
273 lines
8.6 KiB
/* |
|
* Copyright (C) 2015 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. |
|
*/ |
|
|
|
#ifndef ANDROID_HARDWARE_BINDER_STATUS_H |
|
#define ANDROID_HARDWARE_BINDER_STATUS_H |
|
|
|
#include <cstdint> |
|
#include <sstream> |
|
|
|
#include <hidl/HidlInternal.h> |
|
#include <utils/Errors.h> |
|
#include <utils/StrongPointer.h> |
|
|
|
namespace android { |
|
namespace hardware { |
|
|
|
// An object similar in function to a status_t except that it understands |
|
// how exceptions are encoded in the prefix of a Parcel. Used like: |
|
// |
|
// Parcel data; |
|
// Parcel reply; |
|
// status_t status; |
|
// binder::Status remote_exception; |
|
// if ((status = data.writeInterfaceToken(interface_descriptor)) != OK || |
|
// (status = data.writeInt32(function_input)) != OK) { |
|
// // We failed to write into the memory of our local parcel? |
|
// } |
|
// if ((status = remote()->transact(transaction, data, &reply)) != OK) { |
|
// // Something has gone wrong in the binder driver or libbinder. |
|
// } |
|
// if ((status = remote_exception.readFromParcel(reply)) != OK) { |
|
// // The remote didn't correctly write the exception header to the |
|
// // reply. |
|
// } |
|
// if (!remote_exception.isOk()) { |
|
// // The transaction went through correctly, but the remote reported an |
|
// // exception during handling. |
|
// } |
|
// |
|
class Status final { |
|
public: |
|
// Keep the exception codes in sync with android/os/Parcel.java. |
|
enum Exception { |
|
EX_NONE = 0, |
|
EX_SECURITY = -1, |
|
EX_BAD_PARCELABLE = -2, |
|
EX_ILLEGAL_ARGUMENT = -3, |
|
EX_NULL_POINTER = -4, |
|
EX_ILLEGAL_STATE = -5, |
|
EX_NETWORK_MAIN_THREAD = -6, |
|
EX_UNSUPPORTED_OPERATION = -7, |
|
|
|
// This is special and Java specific; see Parcel.java. |
|
EX_HAS_REPLY_HEADER = -128, |
|
// This is special, and indicates to C++ binder proxies that the |
|
// transaction has failed at a low level. |
|
EX_TRANSACTION_FAILED = -129, |
|
}; |
|
|
|
// A more readable alias for the default constructor. |
|
static Status ok(); |
|
// Authors should explicitly pick whether their integer is: |
|
// - an exception code (EX_* above) |
|
// - status_t |
|
// |
|
// Prefer a generic exception code when possible or a status_t |
|
// for low level transport errors. Service specific errors |
|
// should be at a higher level in HIDL. |
|
static Status fromExceptionCode(int32_t exceptionCode); |
|
static Status fromExceptionCode(int32_t exceptionCode, |
|
const char *message); |
|
static Status fromStatusT(status_t status); |
|
|
|
Status() = default; |
|
~Status() = default; |
|
|
|
// Status objects are copyable and contain just simple data. |
|
Status(const Status& status) = default; |
|
Status(Status&& status) = default; |
|
Status& operator=(const Status& status) = default; |
|
|
|
// Set one of the pre-defined exception types defined above. |
|
void setException(int32_t ex, const char *message); |
|
// Setting a |status| != OK causes generated code to return |status| |
|
// from Binder transactions, rather than writing an exception into the |
|
// reply Parcel. This is the least preferable way of reporting errors. |
|
void setFromStatusT(status_t status); |
|
|
|
// Get information about an exception. |
|
int32_t exceptionCode() const { return mException; } |
|
const char *exceptionMessage() const { return mMessage.c_str(); } |
|
status_t transactionError() const { |
|
return mException == EX_TRANSACTION_FAILED ? mErrorCode : OK; |
|
} |
|
|
|
bool isOk() const { return mException == EX_NONE; } |
|
|
|
// For debugging purposes only |
|
std::string description() const; |
|
|
|
private: |
|
Status(int32_t exceptionCode, int32_t errorCode); |
|
Status(int32_t exceptionCode, int32_t errorCode, const char *message); |
|
|
|
// If |mException| == EX_TRANSACTION_FAILED, generated code will return |
|
// |mErrorCode| as the result of the transaction rather than write an |
|
// exception to the reply parcel. |
|
// |
|
// Otherwise, we always write |mException| to the parcel. |
|
// If |mException| != EX_NONE, we write |mMessage| as well. |
|
int32_t mException = EX_NONE; |
|
int32_t mErrorCode = 0; |
|
std::string mMessage; |
|
}; // class Status |
|
|
|
// For gtest output logging |
|
std::ostream& operator<< (std::ostream& stream, const Status& s); |
|
|
|
template<typename T> class Return; |
|
|
|
namespace details { |
|
class return_status { |
|
private: |
|
Status mStatus {}; |
|
mutable bool mCheckedStatus = false; |
|
|
|
template <typename T, typename U> |
|
friend Return<U> StatusOf(const Return<T> &other); |
|
protected: |
|
void assertOk() const; |
|
public: |
|
return_status() {} |
|
return_status(Status s) : mStatus(s) {} |
|
|
|
return_status(const return_status &) = delete; |
|
return_status &operator=(const return_status &) = delete; |
|
|
|
return_status(return_status &&other) { |
|
*this = std::move(other); |
|
} |
|
return_status &operator=(return_status &&other); |
|
|
|
~return_status(); |
|
|
|
bool isOk() const { |
|
mCheckedStatus = true; |
|
return mStatus.isOk(); |
|
} |
|
|
|
// Check if underlying error is DEAD_OBJECT. |
|
// Check mCheckedStatus only if this method returns true. |
|
bool isDeadObject() const { |
|
bool dead = mStatus.transactionError() == DEAD_OBJECT; |
|
|
|
// This way, if you only check isDeadObject your process will |
|
// only be killed for more serious unchecked errors |
|
if (dead) { |
|
mCheckedStatus = true; |
|
} |
|
|
|
return dead; |
|
} |
|
|
|
// For debugging purposes only |
|
std::string description() const { |
|
// Doesn't consider checked. |
|
return mStatus.description(); |
|
} |
|
}; |
|
} // namespace details |
|
|
|
template<typename T> class Return : public details::return_status { |
|
private: |
|
T mVal {}; |
|
public: |
|
Return(T v) : details::return_status(), mVal{v} {} |
|
Return(Status s) : details::return_status(s) {} |
|
|
|
// move-able. |
|
// precondition: "this" has checked status |
|
// postcondition: other is safe to destroy after moving to *this. |
|
Return(Return &&other) = default; |
|
Return &operator=(Return &&) = default; |
|
|
|
~Return() = default; |
|
|
|
operator T() const { |
|
assertOk(); |
|
return mVal; |
|
} |
|
|
|
T withDefault(T t) { |
|
return isOk() ? mVal : t; |
|
} |
|
}; |
|
|
|
template<typename T> class Return<sp<T>> : public details::return_status { |
|
private: |
|
sp<T> mVal {}; |
|
public: |
|
Return(sp<T> v) : details::return_status(), mVal{v} {} |
|
Return(T* v) : details::return_status(), mVal{v} {} |
|
// Constructors matching a different type (that is related by inheritance) |
|
template<typename U> Return(sp<U> v) : details::return_status(), mVal{v} {} |
|
template<typename U> Return(U* v) : details::return_status(), mVal{v} {} |
|
Return(Status s) : details::return_status(s) {} |
|
|
|
// move-able. |
|
// precondition: "this" has checked status |
|
// postcondition: other is safe to destroy after moving to *this. |
|
Return(Return &&other) = default; |
|
Return &operator=(Return &&) = default; |
|
|
|
~Return() = default; |
|
|
|
operator sp<T>() const { |
|
assertOk(); |
|
return mVal; |
|
} |
|
|
|
sp<T> withDefault(sp<T> t) { |
|
return isOk() ? mVal : t; |
|
} |
|
}; |
|
|
|
|
|
template<> class Return<void> : public details::return_status { |
|
public: |
|
Return() : details::return_status() {} |
|
Return(Status s) : details::return_status(s) {} |
|
|
|
// move-able. |
|
// precondition: "this" has checked status |
|
// postcondition: other is safe to destroy after moving to *this. |
|
Return(Return &&) = default; |
|
Return &operator=(Return &&) = default; |
|
|
|
~Return() = default; |
|
}; |
|
|
|
static inline Return<void> Void() { |
|
return Return<void>(); |
|
} |
|
|
|
namespace details { |
|
// Create a Return<U> from the Status of Return<T>. The provided |
|
// Return<T> must have an error status and have it checked. |
|
template <typename T, typename U> |
|
Return<U> StatusOf(const Return<T> &other) { |
|
if (other.mStatus.isOk() || !other.mCheckedStatus) { |
|
details::logAlwaysFatal("cannot call statusOf on an OK Status or an unchecked status"); |
|
} |
|
return Return<U>{other.mStatus}; |
|
} |
|
} // namespace details |
|
|
|
} // namespace hardware |
|
} // namespace android |
|
|
|
#endif // ANDROID_HARDWARE_BINDER_STATUS_H
|
|
|