| Robert Quattlebaum | 6316f5b | 2017-01-04 13:25:14 -0800 | [diff] [blame] | 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 | #define LOG_TAG "Value" | 
 | 18 |  | 
 | 19 | #include <binder/Value.h> | 
 | 20 |  | 
 | 21 | #include <limits> | 
 | 22 |  | 
 | 23 | #include <binder/IBinder.h> | 
 | 24 | #include <binder/Parcel.h> | 
 | 25 | #include <binder/Map.h> | 
 | 26 | #include <private/binder/ParcelValTypes.h> | 
 | 27 | #include <log/log.h> | 
 | 28 | #include <utils/Errors.h> | 
 | 29 |  | 
 | 30 | using android::BAD_TYPE; | 
 | 31 | using android::BAD_VALUE; | 
 | 32 | using android::NO_ERROR; | 
 | 33 | using android::UNEXPECTED_NULL; | 
 | 34 | using android::Parcel; | 
 | 35 | using android::sp; | 
 | 36 | using android::status_t; | 
 | 37 | using std::map; | 
 | 38 | using std::set; | 
 | 39 | using std::vector; | 
 | 40 | using android::binder::Value; | 
 | 41 | using android::IBinder; | 
 | 42 | using android::os::PersistableBundle; | 
 | 43 | using namespace android::binder; | 
 | 44 |  | 
 | 45 | // ==================================================================== | 
 | 46 |  | 
 | 47 | #define RETURN_IF_FAILED(calledOnce)                                     \ | 
 | 48 |     do {                                                                 \ | 
 | 49 |         status_t returnStatus = calledOnce;                              \ | 
 | 50 |         if (returnStatus) {                                              \ | 
 | 51 |             ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \ | 
 | 52 |             return returnStatus;                                         \ | 
 | 53 |          }                                                               \ | 
 | 54 |     } while(false) | 
 | 55 |  | 
 | 56 | // ==================================================================== | 
 | 57 |  | 
 | 58 | /* These `internal_type_ptr()` functions allow this | 
 | 59 |  * class to work without C++ RTTI support. This technique | 
 | 60 |  * only works properly when called directly from this file, | 
 | 61 |  * but that is OK because that is the only place we will | 
 | 62 |  * be calling them from. */ | 
 | 63 | template<class T> const void* internal_type_ptr() | 
 | 64 | { | 
 | 65 |     static const T *marker; | 
 | 66 |     return (void*)▮ | 
 | 67 | } | 
 | 68 |  | 
 | 69 | /* Allows the type to be specified by the argument | 
 | 70 |  * instead of inside angle brackets. */ | 
 | 71 | template<class T> const void* internal_type_ptr(const T&) | 
 | 72 | { | 
 | 73 |     return internal_type_ptr<T>(); | 
 | 74 | } | 
 | 75 |  | 
 | 76 | // ==================================================================== | 
 | 77 |  | 
 | 78 | namespace android { | 
 | 79 |  | 
 | 80 | namespace binder { | 
 | 81 |  | 
 | 82 | class Value::ContentBase { | 
 | 83 | public: | 
 | 84 |     virtual ~ContentBase() = default; | 
 | 85 |     virtual const void* type_ptr() const = 0; | 
 | 86 |     virtual ContentBase * clone() const = 0; | 
 | 87 |     virtual bool operator==(const ContentBase& rhs) const = 0; | 
 | 88 |  | 
 | 89 | #ifdef LIBBINDER_VALUE_SUPPORTS_TYPE_INFO | 
 | 90 |     virtual const std::type_info &type() const = 0; | 
 | 91 | #endif | 
 | 92 |  | 
 | 93 |     template<typename T> bool get(T* out) const; | 
 | 94 | }; | 
 | 95 |  | 
 | 96 | /* This is the actual class that holds the value. */ | 
 | 97 | template<typename T> class Value::Content : public Value::ContentBase { | 
 | 98 | public: | 
 | 99 |     Content() = default; | 
 | 100 |     Content(const T & value) : mValue(value) { } | 
 | 101 |  | 
 | 102 |     virtual ~Content() = default; | 
 | 103 |  | 
 | 104 | #ifdef LIBBINDER_VALUE_SUPPORTS_TYPE_INFO | 
 | 105 |     virtual const std::type_info &type() const override | 
 | 106 |     { | 
 | 107 |         return typeid(T); | 
 | 108 |     } | 
 | 109 | #endif | 
 | 110 |  | 
 | 111 |     virtual const void* type_ptr() const override | 
 | 112 |     { | 
 | 113 |         return internal_type_ptr<T>(); | 
 | 114 |     } | 
 | 115 |  | 
 | 116 |     virtual ContentBase * clone() const override | 
 | 117 |     { | 
 | 118 |         return new Content(mValue); | 
 | 119 |     }; | 
 | 120 |  | 
 | 121 |     virtual bool operator==(const ContentBase& rhs) const override | 
 | 122 |     { | 
 | 123 |         if (type_ptr() != rhs.type_ptr()) { | 
 | 124 |             return false; | 
 | 125 |         } | 
 | 126 |         return mValue == static_cast<const Content<T>* >(&rhs)->mValue; | 
 | 127 |     } | 
 | 128 |  | 
 | 129 |     T mValue; | 
 | 130 | }; | 
 | 131 |  | 
 | 132 | template<typename T> bool Value::ContentBase::get(T* out) const | 
 | 133 | { | 
 | 134 |     if (internal_type_ptr(*out) != type_ptr()) | 
 | 135 |     { | 
 | 136 |         return false; | 
 | 137 |     } | 
 | 138 |  | 
 | 139 |     *out = static_cast<const Content<T>*>(this)->mValue; | 
 | 140 |  | 
 | 141 |     return true; | 
 | 142 | } | 
 | 143 |  | 
 | 144 | // ==================================================================== | 
 | 145 |  | 
| Yi Kong | fdd8da9 | 2018-06-07 17:52:27 -0700 | [diff] [blame] | 146 | Value::Value() : mContent(nullptr) | 
| Robert Quattlebaum | 6316f5b | 2017-01-04 13:25:14 -0800 | [diff] [blame] | 147 | { | 
 | 148 | } | 
 | 149 |  | 
 | 150 | Value::Value(const Value& value) | 
| Yi Kong | fdd8da9 | 2018-06-07 17:52:27 -0700 | [diff] [blame] | 151 |     : mContent(value.mContent ? value.mContent->clone() : nullptr) | 
| Robert Quattlebaum | 6316f5b | 2017-01-04 13:25:14 -0800 | [diff] [blame] | 152 | { | 
 | 153 | } | 
 | 154 |  | 
 | 155 | Value::~Value() | 
 | 156 | { | 
 | 157 |     delete mContent; | 
 | 158 | } | 
 | 159 |  | 
 | 160 | bool Value::operator==(const Value& rhs) const | 
 | 161 | { | 
 | 162 |     const Value& lhs(*this); | 
 | 163 |  | 
 | 164 |     if (lhs.empty() && rhs.empty()) { | 
 | 165 |         return true; | 
 | 166 |     } | 
 | 167 |  | 
| Yi Kong | fdd8da9 | 2018-06-07 17:52:27 -0700 | [diff] [blame] | 168 |     if ( (lhs.mContent == nullptr) | 
 | 169 |       || (rhs.mContent == nullptr) | 
| Robert Quattlebaum | 6316f5b | 2017-01-04 13:25:14 -0800 | [diff] [blame] | 170 |     ) { | 
 | 171 |         return false; | 
 | 172 |     } | 
 | 173 |  | 
 | 174 |     return *lhs.mContent == *rhs.mContent; | 
 | 175 | } | 
 | 176 |  | 
 | 177 | Value& Value::swap(Value &rhs) | 
 | 178 | { | 
 | 179 |     std::swap(mContent, rhs.mContent); | 
 | 180 |     return *this; | 
 | 181 | } | 
 | 182 |  | 
 | 183 | Value& Value::operator=(const Value& rhs) | 
 | 184 | { | 
| Manoj Gupta | fbac608 | 2017-08-22 15:26:11 -0700 | [diff] [blame] | 185 |     if (this != &rhs) { | 
 | 186 |         delete mContent; | 
 | 187 |         mContent = rhs.mContent | 
 | 188 |             ? rhs.mContent->clone() | 
| Yi Kong | fdd8da9 | 2018-06-07 17:52:27 -0700 | [diff] [blame] | 189 |             : nullptr; | 
| Manoj Gupta | fbac608 | 2017-08-22 15:26:11 -0700 | [diff] [blame] | 190 |     } | 
| Robert Quattlebaum | 6316f5b | 2017-01-04 13:25:14 -0800 | [diff] [blame] | 191 |     return *this; | 
 | 192 | } | 
 | 193 |  | 
 | 194 | bool Value::empty() const | 
 | 195 | { | 
| Yi Kong | fdd8da9 | 2018-06-07 17:52:27 -0700 | [diff] [blame] | 196 |     return mContent == nullptr; | 
| Robert Quattlebaum | 6316f5b | 2017-01-04 13:25:14 -0800 | [diff] [blame] | 197 | } | 
 | 198 |  | 
 | 199 | void Value::clear() | 
 | 200 | { | 
 | 201 |     delete mContent; | 
| Yi Kong | fdd8da9 | 2018-06-07 17:52:27 -0700 | [diff] [blame] | 202 |     mContent = nullptr; | 
| Robert Quattlebaum | 6316f5b | 2017-01-04 13:25:14 -0800 | [diff] [blame] | 203 | } | 
 | 204 |  | 
 | 205 | int32_t Value::parcelType() const | 
 | 206 | { | 
| Yi Kong | fdd8da9 | 2018-06-07 17:52:27 -0700 | [diff] [blame] | 207 |     const void* t_info(mContent ? mContent->type_ptr() : nullptr); | 
| Robert Quattlebaum | 6316f5b | 2017-01-04 13:25:14 -0800 | [diff] [blame] | 208 |  | 
 | 209 |     if (t_info == internal_type_ptr<bool>()) return VAL_BOOLEAN; | 
 | 210 |     if (t_info == internal_type_ptr<uint8_t>()) return VAL_BYTE; | 
 | 211 |     if (t_info == internal_type_ptr<int32_t>()) return VAL_INTEGER; | 
 | 212 |     if (t_info == internal_type_ptr<int64_t>()) return VAL_LONG; | 
 | 213 |     if (t_info == internal_type_ptr<double>()) return VAL_DOUBLE; | 
 | 214 |     if (t_info == internal_type_ptr<String16>()) return VAL_STRING; | 
 | 215 |  | 
 | 216 |     if (t_info == internal_type_ptr<vector<bool>>()) return VAL_BOOLEANARRAY; | 
 | 217 |     if (t_info == internal_type_ptr<vector<uint8_t>>()) return VAL_BYTEARRAY; | 
 | 218 |     if (t_info == internal_type_ptr<vector<int32_t>>()) return VAL_INTARRAY; | 
 | 219 |     if (t_info == internal_type_ptr<vector<int64_t>>()) return VAL_LONGARRAY; | 
 | 220 |     if (t_info == internal_type_ptr<vector<double>>()) return VAL_DOUBLEARRAY; | 
 | 221 |     if (t_info == internal_type_ptr<vector<String16>>()) return VAL_STRINGARRAY; | 
 | 222 |  | 
 | 223 |     if (t_info == internal_type_ptr<Map>()) return VAL_MAP; | 
 | 224 |     if (t_info == internal_type_ptr<PersistableBundle>()) return VAL_PERSISTABLEBUNDLE; | 
 | 225 |  | 
 | 226 |     return VAL_NULL; | 
 | 227 | } | 
 | 228 |  | 
 | 229 | #ifdef LIBBINDER_VALUE_SUPPORTS_TYPE_INFO | 
 | 230 | const std::type_info& Value::type() const | 
 | 231 | { | 
 | 232 |     return mContent != NULL | 
 | 233 |         ? mContent->type() | 
 | 234 |         : typeid(void); | 
 | 235 | } | 
 | 236 | #endif // ifdef LIBBINDER_VALUE_SUPPORTS_TYPE_INFO | 
 | 237 |  | 
 | 238 | #define DEF_TYPE_ACCESSORS(T, TYPENAME)                      \ | 
 | 239 |     bool Value::is ## TYPENAME() const                       \ | 
 | 240 |     {                                                        \ | 
 | 241 |         return mContent                                      \ | 
 | 242 |             ? internal_type_ptr<T>() == mContent->type_ptr() \ | 
 | 243 |             : false;                                         \ | 
 | 244 |     }                                                        \ | 
 | 245 |     bool Value::get ## TYPENAME(T* out) const                \ | 
 | 246 |     {                                                        \ | 
 | 247 |         return mContent                                      \ | 
 | 248 |             ? mContent->get(out)                             \ | 
 | 249 |             : false;                                         \ | 
 | 250 |     }                                                        \ | 
 | 251 |     void Value::put ## TYPENAME(const T& in)                 \ | 
 | 252 |     {                                                        \ | 
 | 253 |         *this = in;                                          \ | 
 | 254 |     }                                                        \ | 
 | 255 |     Value& Value::operator=(const T& rhs)                    \ | 
 | 256 |     {                                                        \ | 
 | 257 |         delete mContent;                                     \ | 
 | 258 |         mContent = new Content< T >(rhs);                    \ | 
 | 259 |         return *this;                                        \ | 
 | 260 |     }                                                        \ | 
 | 261 |     Value::Value(const T& value)                             \ | 
 | 262 |         : mContent(new Content< T >(value))                  \ | 
 | 263 |     { } | 
 | 264 |  | 
 | 265 | DEF_TYPE_ACCESSORS(bool, Boolean) | 
 | 266 | DEF_TYPE_ACCESSORS(int8_t, Byte) | 
 | 267 | DEF_TYPE_ACCESSORS(int32_t, Int) | 
 | 268 | DEF_TYPE_ACCESSORS(int64_t, Long) | 
 | 269 | DEF_TYPE_ACCESSORS(double, Double) | 
 | 270 | DEF_TYPE_ACCESSORS(String16, String) | 
 | 271 |  | 
 | 272 | DEF_TYPE_ACCESSORS(std::vector<bool>, BooleanVector) | 
 | 273 | DEF_TYPE_ACCESSORS(std::vector<uint8_t>, ByteVector) | 
 | 274 | DEF_TYPE_ACCESSORS(std::vector<int32_t>, IntVector) | 
 | 275 | DEF_TYPE_ACCESSORS(std::vector<int64_t>, LongVector) | 
 | 276 | DEF_TYPE_ACCESSORS(std::vector<double>, DoubleVector) | 
 | 277 | DEF_TYPE_ACCESSORS(std::vector<String16>, StringVector) | 
 | 278 |  | 
 | 279 | DEF_TYPE_ACCESSORS(::android::binder::Map, Map) | 
 | 280 | DEF_TYPE_ACCESSORS(PersistableBundle, PersistableBundle) | 
 | 281 |  | 
 | 282 | bool Value::getString(String8* out) const | 
 | 283 | { | 
 | 284 |     String16 val; | 
 | 285 |     bool ret = getString(&val); | 
 | 286 |     if (ret) { | 
 | 287 |         *out = String8(val); | 
 | 288 |     } | 
 | 289 |     return ret; | 
 | 290 | } | 
 | 291 |  | 
 | 292 | bool Value::getString(::std::string* out) const | 
 | 293 | { | 
 | 294 |     String8 val; | 
 | 295 |     bool ret = getString(&val); | 
 | 296 |     if (ret) { | 
 | 297 |         *out = val.string(); | 
 | 298 |     } | 
 | 299 |     return ret; | 
 | 300 | } | 
 | 301 |  | 
 | 302 | status_t Value::writeToParcel(Parcel* parcel) const | 
 | 303 | { | 
 | 304 |     // This implementation needs to be kept in sync with the writeValue | 
 | 305 |     // implementation in frameworks/base/core/java/android/os/Parcel.java | 
 | 306 |  | 
 | 307 | #define BEGIN_HANDLE_WRITE()                                                                      \ | 
 | 308 |     do {                                                                                          \ | 
 | 309 |         const void* t_info(mContent?mContent->type_ptr():NULL);                                   \ | 
 | 310 |         if (false) { } | 
 | 311 | #define HANDLE_WRITE_TYPE(T, TYPEVAL, TYPEMETHOD)                                                 \ | 
 | 312 |     else if (t_info == internal_type_ptr<T>()) {                                                  \ | 
 | 313 |         RETURN_IF_FAILED(parcel->writeInt32(TYPEVAL));                                            \ | 
 | 314 |         RETURN_IF_FAILED(parcel->TYPEMETHOD(static_cast<const Content<T>*>(mContent)->mValue));   \ | 
 | 315 |     } | 
 | 316 | #define HANDLE_WRITE_PARCELABLE(T, TYPEVAL)                                                       \ | 
 | 317 |     else if (t_info == internal_type_ptr<T>()) {                                                  \ | 
 | 318 |         RETURN_IF_FAILED(parcel->writeInt32(TYPEVAL));                                            \ | 
 | 319 |         RETURN_IF_FAILED(static_cast<const Content<T>*>(mContent)->mValue.writeToParcel(parcel)); \ | 
 | 320 |     } | 
 | 321 | #define END_HANDLE_WRITE()                                                                        \ | 
 | 322 |         else {                                                                                    \ | 
 | 323 |             ALOGE("writeToParcel: Type not supported");                                           \ | 
 | 324 |             return BAD_TYPE;                                                                      \ | 
 | 325 |         }                                                                                         \ | 
 | 326 |     } while (false); | 
 | 327 |  | 
 | 328 |     BEGIN_HANDLE_WRITE() | 
 | 329 |  | 
 | 330 |     HANDLE_WRITE_TYPE(bool,     VAL_BOOLEAN, writeBool) | 
 | 331 |     HANDLE_WRITE_TYPE(int8_t,   VAL_BYTE,    writeByte) | 
 | 332 |     HANDLE_WRITE_TYPE(int8_t,   VAL_BYTE,    writeByte) | 
 | 333 |     HANDLE_WRITE_TYPE(int32_t,  VAL_INTEGER, writeInt32) | 
 | 334 |     HANDLE_WRITE_TYPE(int64_t,  VAL_LONG,    writeInt64) | 
 | 335 |     HANDLE_WRITE_TYPE(double,   VAL_DOUBLE,  writeDouble) | 
 | 336 |     HANDLE_WRITE_TYPE(String16, VAL_STRING,  writeString16) | 
 | 337 |  | 
 | 338 |     HANDLE_WRITE_TYPE(vector<bool>,     VAL_BOOLEANARRAY, writeBoolVector) | 
 | 339 |     HANDLE_WRITE_TYPE(vector<uint8_t>,  VAL_BYTEARRAY,    writeByteVector) | 
 | 340 |     HANDLE_WRITE_TYPE(vector<int8_t>,   VAL_BYTEARRAY,    writeByteVector) | 
 | 341 |     HANDLE_WRITE_TYPE(vector<int32_t>,  VAL_INTARRAY,     writeInt32Vector) | 
 | 342 |     HANDLE_WRITE_TYPE(vector<int64_t>,  VAL_LONGARRAY,    writeInt64Vector) | 
 | 343 |     HANDLE_WRITE_TYPE(vector<double>,   VAL_DOUBLEARRAY,  writeDoubleVector) | 
 | 344 |     HANDLE_WRITE_TYPE(vector<String16>, VAL_STRINGARRAY,  writeString16Vector) | 
 | 345 |  | 
 | 346 |     HANDLE_WRITE_PARCELABLE(PersistableBundle, VAL_PERSISTABLEBUNDLE) | 
 | 347 |  | 
 | 348 |     END_HANDLE_WRITE() | 
 | 349 |  | 
 | 350 |     return NO_ERROR; | 
 | 351 |  | 
 | 352 | #undef BEGIN_HANDLE_WRITE | 
 | 353 | #undef HANDLE_WRITE_TYPE | 
 | 354 | #undef HANDLE_WRITE_PARCELABLE | 
 | 355 | #undef END_HANDLE_WRITE | 
 | 356 | } | 
 | 357 |  | 
 | 358 | status_t Value::readFromParcel(const Parcel* parcel) | 
 | 359 | { | 
 | 360 |     // This implementation needs to be kept in sync with the readValue | 
 | 361 |     // implementation in frameworks/base/core/java/android/os/Parcel.javai | 
 | 362 |  | 
 | 363 | #define BEGIN_HANDLE_READ()                                                                      \ | 
 | 364 |     switch(value_type) {                                                                         \ | 
 | 365 |         default:                                                                                 \ | 
 | 366 |             ALOGE("readFromParcel: Parcel type %d is not supported", value_type);                \ | 
 | 367 |             return BAD_TYPE; | 
 | 368 | #define HANDLE_READ_TYPE(T, TYPEVAL, TYPEMETHOD)                                                 \ | 
 | 369 |         case TYPEVAL:                                                                            \ | 
 | 370 |             mContent = new Content<T>();                                                         \ | 
 | 371 |             RETURN_IF_FAILED(parcel->TYPEMETHOD(&static_cast<Content<T>*>(mContent)->mValue));   \ | 
 | 372 |             break; | 
 | 373 | #define HANDLE_READ_PARCELABLE(T, TYPEVAL)                                                       \ | 
 | 374 |         case TYPEVAL:                                                                            \ | 
 | 375 |             mContent = new Content<T>();                                                         \ | 
 | 376 |             RETURN_IF_FAILED(static_cast<Content<T>*>(mContent)->mValue.readFromParcel(parcel)); \ | 
 | 377 |             break; | 
 | 378 | #define END_HANDLE_READ()                                                                        \ | 
 | 379 |     } | 
 | 380 |  | 
 | 381 |     int32_t value_type = VAL_NULL; | 
 | 382 |  | 
 | 383 |     delete mContent; | 
| Yi Kong | fdd8da9 | 2018-06-07 17:52:27 -0700 | [diff] [blame] | 384 |     mContent = nullptr; | 
| Robert Quattlebaum | 6316f5b | 2017-01-04 13:25:14 -0800 | [diff] [blame] | 385 |  | 
 | 386 |     RETURN_IF_FAILED(parcel->readInt32(&value_type)); | 
 | 387 |  | 
 | 388 |     BEGIN_HANDLE_READ() | 
 | 389 |  | 
 | 390 |     HANDLE_READ_TYPE(bool,     VAL_BOOLEAN, readBool) | 
 | 391 |     HANDLE_READ_TYPE(int8_t,   VAL_BYTE,    readByte) | 
 | 392 |     HANDLE_READ_TYPE(int32_t,  VAL_INTEGER, readInt32) | 
 | 393 |     HANDLE_READ_TYPE(int64_t,  VAL_LONG,    readInt64) | 
 | 394 |     HANDLE_READ_TYPE(double,   VAL_DOUBLE,  readDouble) | 
 | 395 |     HANDLE_READ_TYPE(String16, VAL_STRING,  readString16) | 
 | 396 |  | 
 | 397 |     HANDLE_READ_TYPE(vector<bool>,     VAL_BOOLEANARRAY, readBoolVector) | 
 | 398 |     HANDLE_READ_TYPE(vector<uint8_t>,  VAL_BYTEARRAY,    readByteVector) | 
 | 399 |     HANDLE_READ_TYPE(vector<int32_t>,  VAL_INTARRAY,     readInt32Vector) | 
 | 400 |     HANDLE_READ_TYPE(vector<int64_t>,  VAL_LONGARRAY,    readInt64Vector) | 
 | 401 |     HANDLE_READ_TYPE(vector<double>,   VAL_DOUBLEARRAY,  readDoubleVector) | 
 | 402 |     HANDLE_READ_TYPE(vector<String16>, VAL_STRINGARRAY,  readString16Vector) | 
 | 403 |  | 
 | 404 |     HANDLE_READ_PARCELABLE(PersistableBundle, VAL_PERSISTABLEBUNDLE) | 
 | 405 |  | 
 | 406 |     END_HANDLE_READ() | 
 | 407 |  | 
 | 408 |     return NO_ERROR; | 
 | 409 |  | 
 | 410 | #undef BEGIN_HANDLE_READ | 
 | 411 | #undef HANDLE_READ_TYPE | 
 | 412 | #undef HANDLE_READ_PARCELABLE | 
 | 413 | #undef END_HANDLE_READ | 
 | 414 | } | 
 | 415 |  | 
 | 416 | }  // namespace binder | 
 | 417 |  | 
 | 418 | }  // namespace android | 
 | 419 |  | 
 | 420 | /* vim: set ts=4 sw=4 tw=0 et :*/ |