Status.h revision 13f7f62af6b04ae4683a1e7189dbb51a9fab3648
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(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
185template<typename T> class Return : public details::return_status {
186private:
187    T mVal {};
188public:
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
210template<typename T> class Return<sp<T>> : public details::return_status {
211private:
212    sp<T> mVal {};
213public:
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
240template<> class Return<void> : public details::return_status {
241public:
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
254static inline Return<void> Void() {
255    return Return<void>();
256}
257
258namespace 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.
261template <typename T, typename U>
262Return<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