| /* | |
| * Copyright (C) 2015 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #define LOG_TAG "Value" | |
| #include <binder/Value.h> | |
| #include <limits> | |
| #include <binder/IBinder.h> | |
| #include <binder/Parcel.h> | |
| #include <binder/Map.h> | |
| #include <private/binder/ParcelValTypes.h> | |
| #include <log/log.h> | |
| #include <utils/Errors.h> | |
| using android::BAD_TYPE; | |
| using android::BAD_VALUE; | |
| using android::NO_ERROR; | |
| using android::UNEXPECTED_NULL; | |
| using android::Parcel; | |
| using android::sp; | |
| using android::status_t; | |
| using std::map; | |
| using std::set; | |
| using std::vector; | |
| using android::binder::Value; | |
| using android::IBinder; | |
| using android::os::PersistableBundle; | |
| using namespace android::binder; | |
| // ==================================================================== | |
| #define RETURN_IF_FAILED(calledOnce) \ | |
| do { \ | |
| status_t returnStatus = calledOnce; \ | |
| if (returnStatus) { \ | |
| ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \ | |
| return returnStatus; \ | |
| } \ | |
| } while(false) | |
| // ==================================================================== | |
| /* These `internal_type_ptr()` functions allow this | |
| * class to work without C++ RTTI support. This technique | |
| * only works properly when called directly from this file, | |
| * but that is OK because that is the only place we will | |
| * be calling them from. */ | |
| template<class T> const void* internal_type_ptr() | |
| { | |
| static const T *marker; | |
| return (void*)▮ | |
| } | |
| /* Allows the type to be specified by the argument | |
| * instead of inside angle brackets. */ | |
| template<class T> const void* internal_type_ptr(const T&) | |
| { | |
| return internal_type_ptr<T>(); | |
| } | |
| // ==================================================================== | |
| namespace android { | |
| namespace binder { | |
| class Value::ContentBase { | |
| public: | |
| virtual ~ContentBase() = default; | |
| virtual const void* type_ptr() const = 0; | |
| virtual ContentBase * clone() const = 0; | |
| virtual bool operator==(const ContentBase& rhs) const = 0; | |
| #ifdef LIBBINDER_VALUE_SUPPORTS_TYPE_INFO | |
| virtual const std::type_info &type() const = 0; | |
| #endif | |
| template<typename T> bool get(T* out) const; | |
| }; | |
| /* This is the actual class that holds the value. */ | |
| template<typename T> class Value::Content : public Value::ContentBase { | |
| public: | |
| Content() = default; | |
| Content(const T & value) : mValue(value) { } | |
| virtual ~Content() = default; | |
| #ifdef LIBBINDER_VALUE_SUPPORTS_TYPE_INFO | |
| virtual const std::type_info &type() const override | |
| { | |
| return typeid(T); | |
| } | |
| #endif | |
| virtual const void* type_ptr() const override | |
| { | |
| return internal_type_ptr<T>(); | |
| } | |
| virtual ContentBase * clone() const override | |
| { | |
| return new Content(mValue); | |
| }; | |
| virtual bool operator==(const ContentBase& rhs) const override | |
| { | |
| if (type_ptr() != rhs.type_ptr()) { | |
| return false; | |
| } | |
| return mValue == static_cast<const Content<T>* >(&rhs)->mValue; | |
| } | |
| T mValue; | |
| }; | |
| template<typename T> bool Value::ContentBase::get(T* out) const | |
| { | |
| if (internal_type_ptr(*out) != type_ptr()) | |
| { | |
| return false; | |
| } | |
| *out = static_cast<const Content<T>*>(this)->mValue; | |
| return true; | |
| } | |
| // ==================================================================== | |
| Value::Value() : mContent(NULL) | |
| { | |
| } | |
| Value::Value(const Value& value) | |
| : mContent(value.mContent ? value.mContent->clone() : NULL) | |
| { | |
| } | |
| Value::~Value() | |
| { | |
| delete mContent; | |
| } | |
| bool Value::operator==(const Value& rhs) const | |
| { | |
| const Value& lhs(*this); | |
| if (lhs.empty() && rhs.empty()) { | |
| return true; | |
| } | |
| if ( (lhs.mContent == NULL) | |
| || (rhs.mContent == NULL) | |
| ) { | |
| return false; | |
| } | |
| return *lhs.mContent == *rhs.mContent; | |
| } | |
| Value& Value::swap(Value &rhs) | |
| { | |
| std::swap(mContent, rhs.mContent); | |
| return *this; | |
| } | |
| Value& Value::operator=(const Value& rhs) | |
| { | |
| delete mContent; | |
| mContent = rhs.mContent | |
| ? rhs.mContent->clone() | |
| : NULL; | |
| return *this; | |
| } | |
| bool Value::empty() const | |
| { | |
| return mContent == NULL; | |
| } | |
| void Value::clear() | |
| { | |
| delete mContent; | |
| mContent = NULL; | |
| } | |
| int32_t Value::parcelType() const | |
| { | |
| const void* t_info(mContent ? mContent->type_ptr() : NULL); | |
| if (t_info == internal_type_ptr<bool>()) return VAL_BOOLEAN; | |
| if (t_info == internal_type_ptr<uint8_t>()) return VAL_BYTE; | |
| if (t_info == internal_type_ptr<int32_t>()) return VAL_INTEGER; | |
| if (t_info == internal_type_ptr<int64_t>()) return VAL_LONG; | |
| if (t_info == internal_type_ptr<double>()) return VAL_DOUBLE; | |
| if (t_info == internal_type_ptr<String16>()) return VAL_STRING; | |
| if (t_info == internal_type_ptr<vector<bool>>()) return VAL_BOOLEANARRAY; | |
| if (t_info == internal_type_ptr<vector<uint8_t>>()) return VAL_BYTEARRAY; | |
| if (t_info == internal_type_ptr<vector<int32_t>>()) return VAL_INTARRAY; | |
| if (t_info == internal_type_ptr<vector<int64_t>>()) return VAL_LONGARRAY; | |
| if (t_info == internal_type_ptr<vector<double>>()) return VAL_DOUBLEARRAY; | |
| if (t_info == internal_type_ptr<vector<String16>>()) return VAL_STRINGARRAY; | |
| if (t_info == internal_type_ptr<Map>()) return VAL_MAP; | |
| if (t_info == internal_type_ptr<PersistableBundle>()) return VAL_PERSISTABLEBUNDLE; | |
| return VAL_NULL; | |
| } | |
| #ifdef LIBBINDER_VALUE_SUPPORTS_TYPE_INFO | |
| const std::type_info& Value::type() const | |
| { | |
| return mContent != NULL | |
| ? mContent->type() | |
| : typeid(void); | |
| } | |
| #endif // ifdef LIBBINDER_VALUE_SUPPORTS_TYPE_INFO | |
| #define DEF_TYPE_ACCESSORS(T, TYPENAME) \ | |
| bool Value::is ## TYPENAME() const \ | |
| { \ | |
| return mContent \ | |
| ? internal_type_ptr<T>() == mContent->type_ptr() \ | |
| : false; \ | |
| } \ | |
| bool Value::get ## TYPENAME(T* out) const \ | |
| { \ | |
| return mContent \ | |
| ? mContent->get(out) \ | |
| : false; \ | |
| } \ | |
| void Value::put ## TYPENAME(const T& in) \ | |
| { \ | |
| *this = in; \ | |
| } \ | |
| Value& Value::operator=(const T& rhs) \ | |
| { \ | |
| delete mContent; \ | |
| mContent = new Content< T >(rhs); \ | |
| return *this; \ | |
| } \ | |
| Value::Value(const T& value) \ | |
| : mContent(new Content< T >(value)) \ | |
| { } | |
| DEF_TYPE_ACCESSORS(bool, Boolean) | |
| DEF_TYPE_ACCESSORS(int8_t, Byte) | |
| DEF_TYPE_ACCESSORS(int32_t, Int) | |
| DEF_TYPE_ACCESSORS(int64_t, Long) | |
| DEF_TYPE_ACCESSORS(double, Double) | |
| DEF_TYPE_ACCESSORS(String16, String) | |
| DEF_TYPE_ACCESSORS(std::vector<bool>, BooleanVector) | |
| DEF_TYPE_ACCESSORS(std::vector<uint8_t>, ByteVector) | |
| DEF_TYPE_ACCESSORS(std::vector<int32_t>, IntVector) | |
| DEF_TYPE_ACCESSORS(std::vector<int64_t>, LongVector) | |
| DEF_TYPE_ACCESSORS(std::vector<double>, DoubleVector) | |
| DEF_TYPE_ACCESSORS(std::vector<String16>, StringVector) | |
| DEF_TYPE_ACCESSORS(::android::binder::Map, Map) | |
| DEF_TYPE_ACCESSORS(PersistableBundle, PersistableBundle) | |
| bool Value::getString(String8* out) const | |
| { | |
| String16 val; | |
| bool ret = getString(&val); | |
| if (ret) { | |
| *out = String8(val); | |
| } | |
| return ret; | |
| } | |
| bool Value::getString(::std::string* out) const | |
| { | |
| String8 val; | |
| bool ret = getString(&val); | |
| if (ret) { | |
| *out = val.string(); | |
| } | |
| return ret; | |
| } | |
| status_t Value::writeToParcel(Parcel* parcel) const | |
| { | |
| // This implementation needs to be kept in sync with the writeValue | |
| // implementation in frameworks/base/core/java/android/os/Parcel.java | |
| #define BEGIN_HANDLE_WRITE() \ | |
| do { \ | |
| const void* t_info(mContent?mContent->type_ptr():NULL); \ | |
| if (false) { } | |
| #define HANDLE_WRITE_TYPE(T, TYPEVAL, TYPEMETHOD) \ | |
| else if (t_info == internal_type_ptr<T>()) { \ | |
| RETURN_IF_FAILED(parcel->writeInt32(TYPEVAL)); \ | |
| RETURN_IF_FAILED(parcel->TYPEMETHOD(static_cast<const Content<T>*>(mContent)->mValue)); \ | |
| } | |
| #define HANDLE_WRITE_PARCELABLE(T, TYPEVAL) \ | |
| else if (t_info == internal_type_ptr<T>()) { \ | |
| RETURN_IF_FAILED(parcel->writeInt32(TYPEVAL)); \ | |
| RETURN_IF_FAILED(static_cast<const Content<T>*>(mContent)->mValue.writeToParcel(parcel)); \ | |
| } | |
| #define END_HANDLE_WRITE() \ | |
| else { \ | |
| ALOGE("writeToParcel: Type not supported"); \ | |
| return BAD_TYPE; \ | |
| } \ | |
| } while (false); | |
| BEGIN_HANDLE_WRITE() | |
| HANDLE_WRITE_TYPE(bool, VAL_BOOLEAN, writeBool) | |
| HANDLE_WRITE_TYPE(int8_t, VAL_BYTE, writeByte) | |
| HANDLE_WRITE_TYPE(int8_t, VAL_BYTE, writeByte) | |
| HANDLE_WRITE_TYPE(int32_t, VAL_INTEGER, writeInt32) | |
| HANDLE_WRITE_TYPE(int64_t, VAL_LONG, writeInt64) | |
| HANDLE_WRITE_TYPE(double, VAL_DOUBLE, writeDouble) | |
| HANDLE_WRITE_TYPE(String16, VAL_STRING, writeString16) | |
| HANDLE_WRITE_TYPE(vector<bool>, VAL_BOOLEANARRAY, writeBoolVector) | |
| HANDLE_WRITE_TYPE(vector<uint8_t>, VAL_BYTEARRAY, writeByteVector) | |
| HANDLE_WRITE_TYPE(vector<int8_t>, VAL_BYTEARRAY, writeByteVector) | |
| HANDLE_WRITE_TYPE(vector<int32_t>, VAL_INTARRAY, writeInt32Vector) | |
| HANDLE_WRITE_TYPE(vector<int64_t>, VAL_LONGARRAY, writeInt64Vector) | |
| HANDLE_WRITE_TYPE(vector<double>, VAL_DOUBLEARRAY, writeDoubleVector) | |
| HANDLE_WRITE_TYPE(vector<String16>, VAL_STRINGARRAY, writeString16Vector) | |
| HANDLE_WRITE_PARCELABLE(PersistableBundle, VAL_PERSISTABLEBUNDLE) | |
| END_HANDLE_WRITE() | |
| return NO_ERROR; | |
| #undef BEGIN_HANDLE_WRITE | |
| #undef HANDLE_WRITE_TYPE | |
| #undef HANDLE_WRITE_PARCELABLE | |
| #undef END_HANDLE_WRITE | |
| } | |
| status_t Value::readFromParcel(const Parcel* parcel) | |
| { | |
| // This implementation needs to be kept in sync with the readValue | |
| // implementation in frameworks/base/core/java/android/os/Parcel.javai | |
| #define BEGIN_HANDLE_READ() \ | |
| switch(value_type) { \ | |
| default: \ | |
| ALOGE("readFromParcel: Parcel type %d is not supported", value_type); \ | |
| return BAD_TYPE; | |
| #define HANDLE_READ_TYPE(T, TYPEVAL, TYPEMETHOD) \ | |
| case TYPEVAL: \ | |
| mContent = new Content<T>(); \ | |
| RETURN_IF_FAILED(parcel->TYPEMETHOD(&static_cast<Content<T>*>(mContent)->mValue)); \ | |
| break; | |
| #define HANDLE_READ_PARCELABLE(T, TYPEVAL) \ | |
| case TYPEVAL: \ | |
| mContent = new Content<T>(); \ | |
| RETURN_IF_FAILED(static_cast<Content<T>*>(mContent)->mValue.readFromParcel(parcel)); \ | |
| break; | |
| #define END_HANDLE_READ() \ | |
| } | |
| int32_t value_type = VAL_NULL; | |
| delete mContent; | |
| mContent = NULL; | |
| RETURN_IF_FAILED(parcel->readInt32(&value_type)); | |
| BEGIN_HANDLE_READ() | |
| HANDLE_READ_TYPE(bool, VAL_BOOLEAN, readBool) | |
| HANDLE_READ_TYPE(int8_t, VAL_BYTE, readByte) | |
| HANDLE_READ_TYPE(int32_t, VAL_INTEGER, readInt32) | |
| HANDLE_READ_TYPE(int64_t, VAL_LONG, readInt64) | |
| HANDLE_READ_TYPE(double, VAL_DOUBLE, readDouble) | |
| HANDLE_READ_TYPE(String16, VAL_STRING, readString16) | |
| HANDLE_READ_TYPE(vector<bool>, VAL_BOOLEANARRAY, readBoolVector) | |
| HANDLE_READ_TYPE(vector<uint8_t>, VAL_BYTEARRAY, readByteVector) | |
| HANDLE_READ_TYPE(vector<int32_t>, VAL_INTARRAY, readInt32Vector) | |
| HANDLE_READ_TYPE(vector<int64_t>, VAL_LONGARRAY, readInt64Vector) | |
| HANDLE_READ_TYPE(vector<double>, VAL_DOUBLEARRAY, readDoubleVector) | |
| HANDLE_READ_TYPE(vector<String16>, VAL_STRINGARRAY, readString16Vector) | |
| HANDLE_READ_PARCELABLE(PersistableBundle, VAL_PERSISTABLEBUNDLE) | |
| END_HANDLE_READ() | |
| return NO_ERROR; | |
| #undef BEGIN_HANDLE_READ | |
| #undef HANDLE_READ_TYPE | |
| #undef HANDLE_READ_PARCELABLE | |
| #undef END_HANDLE_READ | |
| } | |
| } // namespace binder | |
| } // namespace android | |
| /* vim: set ts=4 sw=4 tw=0 et :*/ |