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_BINDER_STATUS_H 18 #define ANDROID_BINDER_STATUS_H 19 20 #include <cstdint> 21 #include <sstream> // historical 22 #include <ostream> 23 24 #include <binder/Common.h> 25 #include <binder/Parcel.h> 26 #include <utils/String8.h> 27 #include <string> 28 29 namespace android { 30 namespace binder { 31 32 // An object similar in function to a status_t except that it understands 33 // how exceptions are encoded in the prefix of a Parcel. Used like: 34 // 35 // Parcel data; 36 // Parcel reply; 37 // status_t status; 38 // binder::Status remote_exception; 39 // if ((status = data.writeInterfaceToken(interface_descriptor)) != OK || 40 // (status = data.writeInt32(function_input)) != OK) { 41 // // We failed to write into the memory of our local parcel? 42 // } 43 // if ((status = remote()->transact(transaction, data, &reply)) != OK) { 44 // // Something has gone wrong in the binder driver or libbinder. 45 // } 46 // if ((status = remote_exception.readFromParcel(reply)) != OK) { 47 // // The remote didn't correctly write the exception header to the 48 // // reply. 49 // } 50 // if (!remote_exception.isOk()) { 51 // // The transaction went through correctly, but the remote reported an 52 // // exception during handling. 53 // } 54 // 55 class LIBBINDER_EXPORTED Status final { 56 public: 57 // Keep the exception codes in sync with android/os/Parcel.java. 58 enum Exception { 59 EX_NONE = 0, 60 EX_SECURITY = -1, 61 EX_BAD_PARCELABLE = -2, 62 EX_ILLEGAL_ARGUMENT = -3, 63 EX_NULL_POINTER = -4, 64 EX_ILLEGAL_STATE = -5, 65 EX_NETWORK_MAIN_THREAD = -6, 66 EX_UNSUPPORTED_OPERATION = -7, 67 EX_SERVICE_SPECIFIC = -8, 68 EX_PARCELABLE = -9, 69 70 // See android/os/Parcel.java. We need to handle this in native code. 71 EX_HAS_NOTED_APPOPS_REPLY_HEADER = -127, 72 73 // This is special and Java specific; see Parcel.java. 74 EX_HAS_REPLY_HEADER = -128, 75 // This is special, and indicates to C++ binder proxies that the 76 // transaction has failed at a low level. 77 EX_TRANSACTION_FAILED = -129, 78 }; 79 80 // A more readable alias for the default constructor. 81 static Status ok(); 82 83 // Authors should explicitly pick whether their integer is: 84 // - an exception code (EX_* above) 85 // - service specific error code 86 // - status_t 87 // 88 // Prefer a generic exception code when possible, then a service specific 89 // code, and finally a status_t for low level failures or legacy support. 90 // Exception codes and service specific errors map to nicer exceptions for 91 // Java clients. 92 static Status fromExceptionCode(int32_t exceptionCode); 93 static Status fromExceptionCode(int32_t exceptionCode, 94 const String8& message); 95 static Status fromExceptionCode(int32_t exceptionCode, 96 const char* message); 97 98 // warning: this is still considered an error if it is constructed with a 99 // zero value error code. Please use Status::ok() instead and avoid zero 100 // error codes 101 static Status fromServiceSpecificError(int32_t serviceSpecificErrorCode); 102 static Status fromServiceSpecificError(int32_t serviceSpecificErrorCode, 103 const String8& message); 104 static Status fromServiceSpecificError(int32_t serviceSpecificErrorCode, 105 const char* message); 106 107 static Status fromStatusT(status_t status); 108 109 static std::string exceptionToString(status_t exceptionCode); 110 111 Status() = default; 112 ~Status() = default; 113 114 // Status objects are copyable and contain just simple data. 115 Status(const Status& status) = default; 116 Status(Status&& status) = default; 117 Status& operator=(const Status& status) = default; 118 119 // Bear in mind that if the client or service is a Java endpoint, this 120 // is not the logic which will provide/interpret the data here. 121 status_t readFromParcel(const Parcel& parcel); 122 status_t writeToParcel(Parcel* parcel) const; 123 124 // Convenience API to replace a Parcel with a status value, w/o requiring 125 // calling multiple APIs (makes generated code smaller). 126 status_t writeOverParcel(Parcel* parcel) const; 127 128 // Set one of the pre-defined exception types defined above. 129 void setException(int32_t ex, const String8& message); 130 // Set a service specific exception with error code. 131 void setServiceSpecificError(int32_t errorCode, const String8& message); 132 // Setting a |status| != OK causes generated code to return |status| 133 // from Binder transactions, rather than writing an exception into the 134 // reply Parcel. This is the least preferable way of reporting errors. 135 void setFromStatusT(status_t status); 136 137 // Get information about an exception. exceptionCode()138 int32_t exceptionCode() const { return mException; } exceptionMessage()139 const String8& exceptionMessage() const { return mMessage; } transactionError()140 status_t transactionError() const { 141 return mException == EX_TRANSACTION_FAILED ? mErrorCode : OK; 142 } serviceSpecificErrorCode()143 int32_t serviceSpecificErrorCode() const { 144 return mException == EX_SERVICE_SPECIFIC ? mErrorCode : 0; 145 } 146 isOk()147 bool isOk() const { return mException == EX_NONE; } 148 149 // For logging. 150 String8 toString8() const; 151 152 private: 153 Status(int32_t exceptionCode, int32_t errorCode); 154 Status(int32_t exceptionCode, int32_t errorCode, const String8& message); 155 156 status_t skipUnusedHeader(const Parcel& parcel); 157 158 // If |mException| == EX_TRANSACTION_FAILED, generated code will return 159 // |mErrorCode| as the result of the transaction rather than write an 160 // exception to the reply parcel. 161 // 162 // Otherwise, we always write |mException| to the parcel. 163 // If |mException| != EX_NONE, we write |mMessage| as well. 164 // If |mException| == EX_SERVICE_SPECIFIC we write |mErrorCode| as well. 165 int32_t mException = EX_NONE; 166 int32_t mErrorCode = 0; 167 String8 mMessage; 168 }; // class Status 169 170 static inline std::ostream& operator<< (std::ostream& o, const Status& s) { 171 return o << s.toString8(); 172 } 173 174 } // namespace binder 175 } // namespace android 176 177 #endif // ANDROID_BINDER_STATUS_H 178