1bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen/*
2bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen * Copyright (C) 2015 The Android Open Source Project
3bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen *
4bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen * Licensed under the Apache License, Version 2.0 (the "License");
5bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen * you may not use this file except in compliance with the License.
6bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen * You may obtain a copy of the License at
7bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen *
8bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen *      http://www.apache.org/licenses/LICENSE-2.0
9bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen *
10bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen * Unless required by applicable law or agreed to in writing, software
11bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen * distributed under the License is distributed on an "AS IS" BASIS,
12bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen * See the License for the specific language governing permissions and
14bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen * limitations under the License.
15bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen */
162be9418963c8d36bb1425093d224256e2a94b277Yifan Hong
17e780c45b31a03f318db85b9940bf20f93ac50395Steven Moreland#define LOG_TAG "HidlStatus"
182be9418963c8d36bb1425093d224256e2a94b277Yifan Hong#include <android-base/logging.h>
19bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen
20bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen#include <hidl/Status.h>
21bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen
222be9418963c8d36bb1425093d224256e2a94b277Yifan Hong#include <unordered_map>
23e780c45b31a03f318db85b9940bf20f93ac50395Steven Moreland
24bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenennamespace android {
25bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenennamespace hardware {
26bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen
272be9418963c8d36bb1425093d224256e2a94b277Yifan Hongstatic std::string statusToString(status_t s) {
282be9418963c8d36bb1425093d224256e2a94b277Yifan Hong    const std::unordered_map<status_t, std::string> statusStrings{{
292be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        #define STATUS_TO_STRING_PAIR(STATUS) {STATUS, #STATUS}
302be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        STATUS_TO_STRING_PAIR(OK),
312be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        STATUS_TO_STRING_PAIR(UNKNOWN_ERROR),
322be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        STATUS_TO_STRING_PAIR(NO_MEMORY),
332be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        STATUS_TO_STRING_PAIR(INVALID_OPERATION),
342be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        STATUS_TO_STRING_PAIR(BAD_VALUE),
352be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        STATUS_TO_STRING_PAIR(BAD_TYPE),
362be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        STATUS_TO_STRING_PAIR(NAME_NOT_FOUND),
372be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        STATUS_TO_STRING_PAIR(PERMISSION_DENIED),
382be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        STATUS_TO_STRING_PAIR(NO_INIT),
392be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        STATUS_TO_STRING_PAIR(ALREADY_EXISTS),
402be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        STATUS_TO_STRING_PAIR(DEAD_OBJECT),
412be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        STATUS_TO_STRING_PAIR(FAILED_TRANSACTION),
422be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        STATUS_TO_STRING_PAIR(BAD_INDEX),
432be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        STATUS_TO_STRING_PAIR(NOT_ENOUGH_DATA),
442be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        STATUS_TO_STRING_PAIR(WOULD_BLOCK),
452be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        STATUS_TO_STRING_PAIR(TIMED_OUT),
462be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        STATUS_TO_STRING_PAIR(UNKNOWN_TRANSACTION),
472be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        STATUS_TO_STRING_PAIR(FDS_NOT_ALLOWED),
482be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        STATUS_TO_STRING_PAIR(UNEXPECTED_NULL)
492be9418963c8d36bb1425093d224256e2a94b277Yifan Hong    }};
502be9418963c8d36bb1425093d224256e2a94b277Yifan Hong    auto it = statusStrings.find(s);
512be9418963c8d36bb1425093d224256e2a94b277Yifan Hong    if (it != statusStrings.end()) {
522be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        return it->second;
532be9418963c8d36bb1425093d224256e2a94b277Yifan Hong    }
542be9418963c8d36bb1425093d224256e2a94b277Yifan Hong    std::string str = std::to_string(s);
552be9418963c8d36bb1425093d224256e2a94b277Yifan Hong    char *err = strerror(-s);
562be9418963c8d36bb1425093d224256e2a94b277Yifan Hong    if (err != NULL) {
572be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        str.append(1, ' ').append(err);
582be9418963c8d36bb1425093d224256e2a94b277Yifan Hong    }
592be9418963c8d36bb1425093d224256e2a94b277Yifan Hong    return str;
602be9418963c8d36bb1425093d224256e2a94b277Yifan Hong}
612be9418963c8d36bb1425093d224256e2a94b277Yifan Hong
622be9418963c8d36bb1425093d224256e2a94b277Yifan Hongstatic std::string exceptionToString(int32_t ex) {
632be9418963c8d36bb1425093d224256e2a94b277Yifan Hong    const std::unordered_map<int32_t, std::string> exceptionStrings{{
642be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        #define EXCEPTION_TO_STRING_PAIR(EXCEPTION) {Status::Exception::EXCEPTION, #EXCEPTION}
652be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        EXCEPTION_TO_STRING_PAIR(EX_NONE),
662be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        EXCEPTION_TO_STRING_PAIR(EX_SECURITY),
672be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        EXCEPTION_TO_STRING_PAIR(EX_BAD_PARCELABLE),
682be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        EXCEPTION_TO_STRING_PAIR(EX_ILLEGAL_ARGUMENT),
692be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        EXCEPTION_TO_STRING_PAIR(EX_NULL_POINTER),
702be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        EXCEPTION_TO_STRING_PAIR(EX_ILLEGAL_STATE),
712be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        EXCEPTION_TO_STRING_PAIR(EX_NETWORK_MAIN_THREAD),
722be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        EXCEPTION_TO_STRING_PAIR(EX_UNSUPPORTED_OPERATION),
732be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        EXCEPTION_TO_STRING_PAIR(EX_HAS_REPLY_HEADER),
742be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        EXCEPTION_TO_STRING_PAIR(EX_TRANSACTION_FAILED)
752be9418963c8d36bb1425093d224256e2a94b277Yifan Hong    }};
762be9418963c8d36bb1425093d224256e2a94b277Yifan Hong    auto it = exceptionStrings.find(ex);
772be9418963c8d36bb1425093d224256e2a94b277Yifan Hong    return it == exceptionStrings.end() ? std::to_string(ex) : it->second;
782be9418963c8d36bb1425093d224256e2a94b277Yifan Hong}
792be9418963c8d36bb1425093d224256e2a94b277Yifan Hong
80bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn CoenenStatus Status::ok() {
81bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen    return Status();
82bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen}
83bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen
84bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn CoenenStatus Status::fromExceptionCode(int32_t exceptionCode) {
85bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen    return Status(exceptionCode, OK);
86bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen}
87bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen
88bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn CoenenStatus Status::fromExceptionCode(int32_t exceptionCode,
8943298f90efb47e1ae3589df56b12e9e53f16c53eYifan Hong                                 const char *message) {
90bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen    return Status(exceptionCode, OK, message);
91bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen}
92bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen
93bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn CoenenStatus Status::fromStatusT(status_t status) {
94bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen    Status ret;
95bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen    ret.setFromStatusT(status);
96bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen    return ret;
97bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen}
98bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen
99bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn CoenenStatus::Status(int32_t exceptionCode, int32_t errorCode)
100bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen    : mException(exceptionCode),
101bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen      mErrorCode(errorCode) {}
102bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen
10343298f90efb47e1ae3589df56b12e9e53f16c53eYifan HongStatus::Status(int32_t exceptionCode, int32_t errorCode, const char *message)
104bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen    : mException(exceptionCode),
105bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen      mErrorCode(errorCode),
106bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen      mMessage(message) {}
107bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen
10843298f90efb47e1ae3589df56b12e9e53f16c53eYifan Hongvoid Status::setException(int32_t ex, const char *message) {
109bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen    mException = ex;
110bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen    mErrorCode = NO_ERROR;  // an exception, not a transaction failure.
11143298f90efb47e1ae3589df56b12e9e53f16c53eYifan Hong    mMessage = message;
112bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen}
113bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen
114bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenenvoid Status::setFromStatusT(status_t status) {
115bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen    mException = (status == NO_ERROR) ? EX_NONE : EX_TRANSACTION_FAILED;
116bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen    mErrorCode = status;
117bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen    mMessage.clear();
118bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen}
119bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen
12043298f90efb47e1ae3589df56b12e9e53f16c53eYifan Hongstd::string Status::description() const {
12143298f90efb47e1ae3589df56b12e9e53f16c53eYifan Hong    std::ostringstream oss;
12243298f90efb47e1ae3589df56b12e9e53f16c53eYifan Hong    oss << (*this);
12343298f90efb47e1ae3589df56b12e9e53f16c53eYifan Hong    return oss.str();
12443298f90efb47e1ae3589df56b12e9e53f16c53eYifan Hong}
12543298f90efb47e1ae3589df56b12e9e53f16c53eYifan Hong
12643298f90efb47e1ae3589df56b12e9e53f16c53eYifan Hongstd::ostream& operator<< (std::ostream& stream, const Status& s) {
12743298f90efb47e1ae3589df56b12e9e53f16c53eYifan Hong    if (s.exceptionCode() == Status::EX_NONE) {
12843298f90efb47e1ae3589df56b12e9e53f16c53eYifan Hong        stream << "No error";
129bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen    } else {
1302be9418963c8d36bb1425093d224256e2a94b277Yifan Hong        stream << "Status(" << exceptionToString(s.exceptionCode()) << "): '";
13172db40f4a612d04187ae2fc1f9a3766933264bdfSteven Moreland        if (s.exceptionCode() == Status::EX_TRANSACTION_FAILED) {
1322be9418963c8d36bb1425093d224256e2a94b277Yifan Hong            stream << statusToString(s.transactionError()) << ": ";
133bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen        }
13443298f90efb47e1ae3589df56b12e9e53f16c53eYifan Hong        stream << s.exceptionMessage() << "'";
135bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen    }
136bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen    return stream;
137bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen}
138bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen
139e780c45b31a03f318db85b9940bf20f93ac50395Steven Morelandnamespace details {
140af4e43cc5b2eacbfe600f9ab0e459f09c35c0c3fYifan Hong    void return_status::assertOk() const {
141e780c45b31a03f318db85b9940bf20f93ac50395Steven Moreland        if (!isOk()) {
142e780c45b31a03f318db85b9940bf20f93ac50395Steven Moreland            LOG(FATAL) << "Attempted to retrieve value from failed HIDL call: " << description();
143e780c45b31a03f318db85b9940bf20f93ac50395Steven Moreland        }
144e780c45b31a03f318db85b9940bf20f93ac50395Steven Moreland    }
145e780c45b31a03f318db85b9940bf20f93ac50395Steven Moreland
146e780c45b31a03f318db85b9940bf20f93ac50395Steven Moreland    return_status::~return_status() {
147e780c45b31a03f318db85b9940bf20f93ac50395Steven Moreland        // mCheckedStatus must be checked before isOk since isOk modifies mCheckedStatus
148e780c45b31a03f318db85b9940bf20f93ac50395Steven Moreland        if (!mCheckedStatus && !isOk()) {
149e780c45b31a03f318db85b9940bf20f93ac50395Steven Moreland            LOG(FATAL) << "Failed HIDL return status not checked: " << description();
150e780c45b31a03f318db85b9940bf20f93ac50395Steven Moreland        }
151e780c45b31a03f318db85b9940bf20f93ac50395Steven Moreland    }
152af4e43cc5b2eacbfe600f9ab0e459f09c35c0c3fYifan Hong
153af4e43cc5b2eacbfe600f9ab0e459f09c35c0c3fYifan Hong    return_status &return_status::operator=(return_status &&other) {
154af4e43cc5b2eacbfe600f9ab0e459f09c35c0c3fYifan Hong        if (!mCheckedStatus && !isOk()) {
155af4e43cc5b2eacbfe600f9ab0e459f09c35c0c3fYifan Hong            LOG(FATAL) << "Failed HIDL return status not checked: " << description();
156af4e43cc5b2eacbfe600f9ab0e459f09c35c0c3fYifan Hong        }
157af4e43cc5b2eacbfe600f9ab0e459f09c35c0c3fYifan Hong        std::swap(mStatus, other.mStatus);
158af4e43cc5b2eacbfe600f9ab0e459f09c35c0c3fYifan Hong        std::swap(mCheckedStatus, other.mCheckedStatus);
159af4e43cc5b2eacbfe600f9ab0e459f09c35c0c3fYifan Hong        return *this;
160af4e43cc5b2eacbfe600f9ab0e459f09c35c0c3fYifan Hong    }
161af4e43cc5b2eacbfe600f9ab0e459f09c35c0c3fYifan Hong
162e780c45b31a03f318db85b9940bf20f93ac50395Steven Moreland}  // namespace details
163e780c45b31a03f318db85b9940bf20f93ac50395Steven Moreland
164bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen}  // namespace hardware
165bb5e9bb1c982a029ebc82e82f3838b6beeb2d108Martijn Coenen}  // namespace android
166