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