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
27namespace android {
28namespace 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//
53class Status final {
54public:
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
114private:
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
130std::ostream& operator<< (std::ostream& stream, const Status& s);
131
132template<typename T> class Return;
133
134namespace 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(const 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 isOkUnchecked() const {
159            // someone else will have to check
160            return mStatus.isOk();
161        }
162
163        bool isOk() const {
164            mCheckedStatus = true;
165            return mStatus.isOk();
166        }
167
168        // Check if underlying error is DEAD_OBJECT.
169        // Check mCheckedStatus only if this method returns true.
170        bool isDeadObject() const {
171            bool dead = mStatus.transactionError() == DEAD_OBJECT;
172
173            // This way, if you only check isDeadObject your process will
174            // only be killed for more serious unchecked errors
175            if (dead) {
176                mCheckedStatus = true;
177            }
178
179            return dead;
180        }
181
182        // For debugging purposes only
183        std::string description() const {
184            // Doesn't consider checked.
185            return mStatus.description();
186        }
187    };
188}  // namespace details
189
190template<typename T> class Return : public details::return_status {
191private:
192    T mVal {};
193public:
194    Return(T v) : details::return_status(), mVal{v} {}
195    Return(Status s) : details::return_status(s) {}
196
197    // move-able.
198    // precondition: "this" has checked status
199    // postcondition: other is safe to destroy after moving to *this.
200    Return(Return &&other) = default;
201    Return &operator=(Return &&) = default;
202
203    ~Return() = default;
204
205    operator T() const {
206        assertOk();
207        return mVal;
208    }
209
210    T withDefault(T t) {
211        return isOk() ? mVal : t;
212    }
213};
214
215template<typename T> class Return<sp<T>> : public details::return_status {
216private:
217    sp<T> mVal {};
218public:
219    Return(sp<T> v) : details::return_status(), mVal{v} {}
220    Return(T* v) : details::return_status(), mVal{v} {}
221    // Constructors matching a different type (that is related by inheritance)
222    template<typename U> Return(sp<U> v) : details::return_status(), mVal{v} {}
223    template<typename U> Return(U* v) : details::return_status(), mVal{v} {}
224    Return(Status s) : details::return_status(s) {}
225
226    // move-able.
227    // precondition: "this" has checked status
228    // postcondition: other is safe to destroy after moving to *this.
229    Return(Return &&other) = default;
230    Return &operator=(Return &&) = default;
231
232    ~Return() = default;
233
234    operator sp<T>() const {
235        assertOk();
236        return mVal;
237    }
238
239    sp<T> withDefault(sp<T> t) {
240        return isOk() ? mVal : t;
241    }
242};
243
244
245template<> class Return<void> : public details::return_status {
246public:
247    Return() : details::return_status() {}
248    Return(const Status& s) : details::return_status(s) {}
249
250    // move-able.
251    // precondition: "this" has checked status
252    // postcondition: other is safe to destroy after moving to *this.
253    Return(Return &&) = default;
254    Return &operator=(Return &&) = default;
255
256    ~Return() = default;
257};
258
259static inline Return<void> Void() {
260    return Return<void>();
261}
262
263namespace details {
264// Create a Return<U> from the Status of Return<T>. The provided
265// Return<T> must have an error status and have it checked.
266template <typename T, typename U>
267Return<U> StatusOf(const Return<T> &other) {
268    if (other.mStatus.isOk() || !other.mCheckedStatus) {
269        details::logAlwaysFatal("cannot call statusOf on an OK Status or an unchecked status");
270    }
271    return Return<U>{other.mStatus};
272}
273}  // namespace details
274
275}  // namespace hardware
276}  // namespace android
277
278#endif // ANDROID_HARDWARE_BINDER_STATUS_H
279