Home | History | Annotate | Download | only in hidl
      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 #ifndef ANDROID_HARDWARE_BINDER_STATUS_H
     18 #define ANDROID_HARDWARE_BINDER_STATUS_H
     19 
     20 #include <cstdint>
     21 #include <sstream>
     22 
     23 #include <hidl/HidlInternal.h>
     24 #include <utils/Errors.h>
     25 #include <utils/StrongPointer.h>
     26 
     27 namespace android {
     28 namespace hardware {
     29 
     30 // An object similar in function to a status_t except that it understands
     31 // how exceptions are encoded in the prefix of a Parcel. Used like:
     32 //
     33 //     Parcel data;
     34 //     Parcel reply;
     35 //     status_t status;
     36 //     binder::Status remote_exception;
     37 //     if ((status = data.writeInterfaceToken(interface_descriptor)) != OK ||
     38 //         (status = data.writeInt32(function_input)) != OK) {
     39 //         // We failed to write into the memory of our local parcel?
     40 //     }
     41 //     if ((status = remote()->transact(transaction, data, &reply)) != OK) {
     42 //        // Something has gone wrong in the binder driver or libbinder.
     43 //     }
     44 //     if ((status = remote_exception.readFromParcel(reply)) != OK) {
     45 //         // The remote didn't correctly write the exception header to the
     46 //         // reply.
     47 //     }
     48 //     if (!remote_exception.isOk()) {
     49 //         // The transaction went through correctly, but the remote reported an
     50 //         // exception during handling.
     51 //     }
     52 //
     53 class Status final {
     54 public:
     55     // Keep the exception codes in sync with android/os/Parcel.java.
     56     enum Exception {
     57         EX_NONE = 0,
     58         EX_SECURITY = -1,
     59         EX_BAD_PARCELABLE = -2,
     60         EX_ILLEGAL_ARGUMENT = -3,
     61         EX_NULL_POINTER = -4,
     62         EX_ILLEGAL_STATE = -5,
     63         EX_NETWORK_MAIN_THREAD = -6,
     64         EX_UNSUPPORTED_OPERATION = -7,
     65 
     66         // This is special and Java specific; see Parcel.java.
     67         EX_HAS_REPLY_HEADER = -128,
     68         // This is special, and indicates to C++ binder proxies that the
     69         // transaction has failed at a low level.
     70         EX_TRANSACTION_FAILED = -129,
     71     };
     72 
     73     // A more readable alias for the default constructor.
     74     static Status ok();
     75     // Authors should explicitly pick whether their integer is:
     76     //  - an exception code (EX_* above)
     77     //  - status_t
     78     //
     79     // Prefer a generic exception code when possible or a status_t
     80     // for low level transport errors. Service specific errors
     81     // should be at a higher level in HIDL.
     82     static Status fromExceptionCode(int32_t exceptionCode);
     83     static Status fromExceptionCode(int32_t exceptionCode,
     84                                     const char *message);
     85     static Status fromStatusT(status_t status);
     86 
     87     Status() = default;
     88     ~Status() = default;
     89 
     90     // Status objects are copyable and contain just simple data.
     91     Status(const Status& status) = default;
     92     Status(Status&& status) = default;
     93     Status& operator=(const Status& status) = default;
     94 
     95     // Set one of the pre-defined exception types defined above.
     96     void setException(int32_t ex, const char *message);
     97     // Setting a |status| != OK causes generated code to return |status|
     98     // from Binder transactions, rather than writing an exception into the
     99     // reply Parcel.  This is the least preferable way of reporting errors.
    100     void setFromStatusT(status_t status);
    101 
    102     // Get information about an exception.
    103     int32_t exceptionCode() const  { return mException; }
    104     const char *exceptionMessage() const { return mMessage.c_str(); }
    105     status_t transactionError() const {
    106         return mException == EX_TRANSACTION_FAILED ? mErrorCode : OK;
    107     }
    108 
    109     bool isOk() const { return mException == EX_NONE; }
    110 
    111     // For debugging purposes only
    112     std::string description() const;
    113 
    114 private:
    115     Status(int32_t exceptionCode, int32_t errorCode);
    116     Status(int32_t exceptionCode, int32_t errorCode, const char *message);
    117 
    118     // If |mException| == EX_TRANSACTION_FAILED, generated code will return
    119     // |mErrorCode| as the result of the transaction rather than write an
    120     // exception to the reply parcel.
    121     //
    122     // Otherwise, we always write |mException| to the parcel.
    123     // If |mException| !=  EX_NONE, we write |mMessage| as well.
    124     int32_t mException = EX_NONE;
    125     int32_t mErrorCode = 0;
    126     std::string mMessage;
    127 };  // class Status
    128 
    129 // For gtest output logging
    130 std::ostream& operator<< (std::ostream& stream, const Status& s);
    131 
    132 template<typename T> class Return;
    133 
    134 namespace details {
    135     class return_status {
    136     private:
    137         Status mStatus {};
    138         mutable bool mCheckedStatus = false;
    139 
    140         template <typename T, typename U>
    141         friend Return<U> StatusOf(const Return<T> &other);
    142     protected:
    143         void assertOk() const;
    144     public:
    145         return_status() {}
    146         return_status(Status s) : mStatus(s) {}
    147 
    148         return_status(const return_status &) = delete;
    149         return_status &operator=(const return_status &) = delete;
    150 
    151         return_status(return_status &&other) {
    152             *this = std::move(other);
    153         }
    154         return_status &operator=(return_status &&other);
    155 
    156         ~return_status();
    157 
    158         bool isOk() const {
    159             mCheckedStatus = true;
    160             return mStatus.isOk();
    161         }
    162 
    163         // Check if underlying error is DEAD_OBJECT.
    164         // Check mCheckedStatus only if this method returns true.
    165         bool isDeadObject() const {
    166             bool dead = mStatus.transactionError() == DEAD_OBJECT;
    167 
    168             // This way, if you only check isDeadObject your process will
    169             // only be killed for more serious unchecked errors
    170             if (dead) {
    171                 mCheckedStatus = true;
    172             }
    173 
    174             return dead;
    175         }
    176 
    177         // For debugging purposes only
    178         std::string description() const {
    179             // Doesn't consider checked.
    180             return mStatus.description();
    181         }
    182     };
    183 }  // namespace details
    184 
    185 template<typename T> class Return : public details::return_status {
    186 private:
    187     T mVal {};
    188 public:
    189     Return(T v) : details::return_status(), mVal{v} {}
    190     Return(Status s) : details::return_status(s) {}
    191 
    192     // move-able.
    193     // precondition: "this" has checked status
    194     // postcondition: other is safe to destroy after moving to *this.
    195     Return(Return &&other) = default;
    196     Return &operator=(Return &&) = default;
    197 
    198     ~Return() = default;
    199 
    200     operator T() const {
    201         assertOk();
    202         return mVal;
    203     }
    204 
    205     T withDefault(T t) {
    206         return isOk() ? mVal : t;
    207     }
    208 };
    209 
    210 template<typename T> class Return<sp<T>> : public details::return_status {
    211 private:
    212     sp<T> mVal {};
    213 public:
    214     Return(sp<T> v) : details::return_status(), mVal{v} {}
    215     Return(T* v) : details::return_status(), mVal{v} {}
    216     // Constructors matching a different type (that is related by inheritance)
    217     template<typename U> Return(sp<U> v) : details::return_status(), mVal{v} {}
    218     template<typename U> Return(U* v) : details::return_status(), mVal{v} {}
    219     Return(Status s) : details::return_status(s) {}
    220 
    221     // move-able.
    222     // precondition: "this" has checked status
    223     // postcondition: other is safe to destroy after moving to *this.
    224     Return(Return &&other) = default;
    225     Return &operator=(Return &&) = default;
    226 
    227     ~Return() = default;
    228 
    229     operator sp<T>() const {
    230         assertOk();
    231         return mVal;
    232     }
    233 
    234     sp<T> withDefault(sp<T> t) {
    235         return isOk() ? mVal : t;
    236     }
    237 };
    238 
    239 
    240 template<> class Return<void> : public details::return_status {
    241 public:
    242     Return() : details::return_status() {}
    243     Return(Status s) : details::return_status(s) {}
    244 
    245     // move-able.
    246     // precondition: "this" has checked status
    247     // postcondition: other is safe to destroy after moving to *this.
    248     Return(Return &&) = default;
    249     Return &operator=(Return &&) = default;
    250 
    251     ~Return() = default;
    252 };
    253 
    254 static inline Return<void> Void() {
    255     return Return<void>();
    256 }
    257 
    258 namespace details {
    259 // Create a Return<U> from the Status of Return<T>. The provided
    260 // Return<T> must have an error status and have it checked.
    261 template <typename T, typename U>
    262 Return<U> StatusOf(const Return<T> &other) {
    263     if (other.mStatus.isOk() || !other.mCheckedStatus) {
    264         details::logAlwaysFatal("cannot call statusOf on an OK Status or an unchecked status");
    265     }
    266     return Return<U>{other.mStatus};
    267 }
    268 }  // namespace details
    269 
    270 }  // namespace hardware
    271 }  // namespace android
    272 
    273 #endif // ANDROID_HARDWARE_BINDER_STATUS_H
    274