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 
24 namespace android {
25 namespace hardware {
26 
statusToString(status_t s)27 static 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 
exceptionToString(int32_t ex)62 static 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 
ok()80 Status Status::ok() {
81     return Status();
82 }
83 
fromExceptionCode(int32_t exceptionCode)84 Status Status::fromExceptionCode(int32_t exceptionCode) {
85     return Status(exceptionCode, OK);
86 }
87 
fromExceptionCode(int32_t exceptionCode,const char * message)88 Status Status::fromExceptionCode(int32_t exceptionCode,
89                                  const char *message) {
90     return Status(exceptionCode, OK, message);
91 }
92 
fromStatusT(status_t status)93 Status Status::fromStatusT(status_t status) {
94     Status ret;
95     ret.setFromStatusT(status);
96     return ret;
97 }
98 
Status(int32_t exceptionCode,int32_t errorCode)99 Status::Status(int32_t exceptionCode, int32_t errorCode)
100     : mException(exceptionCode),
101       mErrorCode(errorCode) {}
102 
Status(int32_t exceptionCode,int32_t errorCode,const char * message)103 Status::Status(int32_t exceptionCode, int32_t errorCode, const char *message)
104     : mException(exceptionCode),
105       mErrorCode(errorCode),
106       mMessage(message) {}
107 
setException(int32_t ex,const char * message)108 void 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 
setFromStatusT(status_t status)114 void Status::setFromStatusT(status_t status) {
115     mException = (status == NO_ERROR) ? EX_NONE : EX_TRANSACTION_FAILED;
116     mErrorCode = status;
117     mMessage.clear();
118 }
119 
description() const120 std::string Status::description() const {
121     std::ostringstream oss;
122     oss << (*this);
123     return oss.str();
124 }
125 
operator <<(std::ostream & stream,const Status & s)126 std::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 
139 namespace details {
assertOk() const140     void return_status::assertOk() const {
141         if (!isOk()) {
142             LOG(FATAL) << "Attempted to retrieve value from failed HIDL call: " << description();
143         }
144     }
145 
~return_status()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 
operator =(return_status && other)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