1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "HidlStatus"
18#include <android-base/logging.h>
19
20#include <hidl/Status.h>
21
22#include <unordered_map>
23
24namespace android {
25namespace hardware {
26
27static std::string statusToString(status_t s) {
28    const std::unordered_map<status_t, std::string> statusStrings{{
29        #define STATUS_TO_STRING_PAIR(STATUS) {STATUS, #STATUS}
30        STATUS_TO_STRING_PAIR(OK),
31        STATUS_TO_STRING_PAIR(UNKNOWN_ERROR),
32        STATUS_TO_STRING_PAIR(NO_MEMORY),
33        STATUS_TO_STRING_PAIR(INVALID_OPERATION),
34        STATUS_TO_STRING_PAIR(BAD_VALUE),
35        STATUS_TO_STRING_PAIR(BAD_TYPE),
36        STATUS_TO_STRING_PAIR(NAME_NOT_FOUND),
37        STATUS_TO_STRING_PAIR(PERMISSION_DENIED),
38        STATUS_TO_STRING_PAIR(NO_INIT),
39        STATUS_TO_STRING_PAIR(ALREADY_EXISTS),
40        STATUS_TO_STRING_PAIR(DEAD_OBJECT),
41        STATUS_TO_STRING_PAIR(FAILED_TRANSACTION),
42        STATUS_TO_STRING_PAIR(BAD_INDEX),
43        STATUS_TO_STRING_PAIR(NOT_ENOUGH_DATA),
44        STATUS_TO_STRING_PAIR(WOULD_BLOCK),
45        STATUS_TO_STRING_PAIR(TIMED_OUT),
46        STATUS_TO_STRING_PAIR(UNKNOWN_TRANSACTION),
47        STATUS_TO_STRING_PAIR(FDS_NOT_ALLOWED),
48        STATUS_TO_STRING_PAIR(UNEXPECTED_NULL)
49    }};
50    auto it = statusStrings.find(s);
51    if (it != statusStrings.end()) {
52        return it->second;
53    }
54    std::string str = std::to_string(s);
55    char *err = strerror(-s);
56    if (err != NULL) {
57        str.append(1, ' ').append(err);
58    }
59    return str;
60}
61
62static std::string exceptionToString(int32_t ex) {
63    const std::unordered_map<int32_t, std::string> exceptionStrings{{
64        #define EXCEPTION_TO_STRING_PAIR(EXCEPTION) {Status::Exception::EXCEPTION, #EXCEPTION}
65        EXCEPTION_TO_STRING_PAIR(EX_NONE),
66        EXCEPTION_TO_STRING_PAIR(EX_SECURITY),
67        EXCEPTION_TO_STRING_PAIR(EX_BAD_PARCELABLE),
68        EXCEPTION_TO_STRING_PAIR(EX_ILLEGAL_ARGUMENT),
69        EXCEPTION_TO_STRING_PAIR(EX_NULL_POINTER),
70        EXCEPTION_TO_STRING_PAIR(EX_ILLEGAL_STATE),
71        EXCEPTION_TO_STRING_PAIR(EX_NETWORK_MAIN_THREAD),
72        EXCEPTION_TO_STRING_PAIR(EX_UNSUPPORTED_OPERATION),
73        EXCEPTION_TO_STRING_PAIR(EX_HAS_REPLY_HEADER),
74        EXCEPTION_TO_STRING_PAIR(EX_TRANSACTION_FAILED)
75    }};
76    auto it = exceptionStrings.find(ex);
77    return it == exceptionStrings.end() ? std::to_string(ex) : it->second;
78}
79
80Status Status::ok() {
81    return Status();
82}
83
84Status Status::fromExceptionCode(int32_t exceptionCode) {
85    return Status(exceptionCode, OK);
86}
87
88Status Status::fromExceptionCode(int32_t exceptionCode,
89                                 const char *message) {
90    return Status(exceptionCode, OK, message);
91}
92
93Status Status::fromStatusT(status_t status) {
94    Status ret;
95    ret.setFromStatusT(status);
96    return ret;
97}
98
99Status::Status(int32_t exceptionCode, int32_t errorCode)
100    : mException(exceptionCode),
101      mErrorCode(errorCode) {}
102
103Status::Status(int32_t exceptionCode, int32_t errorCode, const char *message)
104    : mException(exceptionCode),
105      mErrorCode(errorCode),
106      mMessage(message) {}
107
108void Status::setException(int32_t ex, const char *message) {
109    mException = ex;
110    mErrorCode = NO_ERROR;  // an exception, not a transaction failure.
111    mMessage = message;
112}
113
114void Status::setFromStatusT(status_t status) {
115    mException = (status == NO_ERROR) ? EX_NONE : EX_TRANSACTION_FAILED;
116    mErrorCode = status;
117    mMessage.clear();
118}
119
120std::string Status::description() const {
121    std::ostringstream oss;
122    oss << (*this);
123    return oss.str();
124}
125
126std::ostream& operator<< (std::ostream& stream, const Status& s) {
127    if (s.exceptionCode() == Status::EX_NONE) {
128        stream << "No error";
129    } else {
130        stream << "Status(" << exceptionToString(s.exceptionCode()) << "): '";
131        if (s.exceptionCode() == Status::EX_TRANSACTION_FAILED) {
132            stream << statusToString(s.transactionError()) << ": ";
133        }
134        stream << s.exceptionMessage() << "'";
135    }
136    return stream;
137}
138
139namespace details {
140    void return_status::assertOk() const {
141        if (!isOk()) {
142            LOG(FATAL) << "Attempted to retrieve value from failed HIDL call: " << description();
143        }
144    }
145
146    return_status::~return_status() {
147        // mCheckedStatus must be checked before isOk since isOk modifies mCheckedStatus
148        if (!mCheckedStatus && !isOk()) {
149            LOG(FATAL) << "Failed HIDL return status not checked: " << description();
150        }
151    }
152
153    return_status &return_status::operator=(return_status &&other) {
154        if (!mCheckedStatus && !isOk()) {
155            LOG(FATAL) << "Failed HIDL return status not checked: " << description();
156        }
157        std::swap(mStatus, other.mStatus);
158        std::swap(mCheckedStatus, other.mCheckedStatus);
159        return *this;
160    }
161
162}  // namespace details
163
164}  // namespace hardware
165}  // namespace android
166