/*
* 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;
explicit 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(nullptr)
{
}
Value::Value(const Value& value)
: mContent(value.mContent ? value.mContent->clone() : nullptr)
{
}
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 == nullptr)
|| (rhs.mContent == nullptr)
) {
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)
{
if (this != &rhs) {
delete mContent;
mContent = rhs.mContent
? rhs.mContent->clone()
: nullptr;
}
return *this;
}
bool Value::empty() const
{
return mContent == nullptr;
}
void Value::clear()
{
delete mContent;
mContent = nullptr;
}
int32_t Value::parcelType() const
{
const void* t_info(mContent ? mContent->type_ptr() : nullptr);
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 != nullptr
? 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():nullptr); \
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 = nullptr;
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 :*/