You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
952 lines
28 KiB
952 lines
28 KiB
/* |
|
* Copyright (C) 2016 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. |
|
*/ |
|
|
|
#ifndef ANDROID_HIDL_SUPPORT_H |
|
#define ANDROID_HIDL_SUPPORT_H |
|
|
|
#include <algorithm> |
|
#include <array> |
|
#include <iterator> |
|
#include <cutils/native_handle.h> |
|
#include <hidl/HidlInternal.h> |
|
#include <hidl/Status.h> |
|
#include <map> |
|
#include <sstream> |
|
#include <stddef.h> |
|
#include <tuple> |
|
#include <type_traits> |
|
#include <utils/Errors.h> |
|
#include <utils/RefBase.h> |
|
#include <utils/StrongPointer.h> |
|
#include <vector> |
|
|
|
namespace android { |
|
|
|
// this file is included by all hidl interface, so we must forward declare the |
|
// IMemory and IBase types. |
|
namespace hidl { |
|
namespace memory { |
|
namespace V1_0 { |
|
struct IMemory; |
|
}; // namespace V1_0 |
|
}; // namespace manager |
|
}; // namespace hidl |
|
|
|
namespace hidl { |
|
namespace base { |
|
namespace V1_0 { |
|
struct IBase; |
|
}; // namespace V1_0 |
|
}; // namespace base |
|
}; // namespace hidl |
|
|
|
namespace hardware { |
|
|
|
namespace details { |
|
// Return true on userdebug / eng builds and false on user builds. |
|
bool debuggable(); |
|
} // namespace details |
|
|
|
// hidl_death_recipient is a callback interfaced that can be used with |
|
// linkToDeath() / unlinkToDeath() |
|
struct hidl_death_recipient : public virtual RefBase { |
|
virtual void serviceDied(uint64_t cookie, |
|
const ::android::wp<::android::hidl::base::V1_0::IBase>& who) = 0; |
|
}; |
|
|
|
// hidl_handle wraps a pointer to a native_handle_t in a hidl_pointer, |
|
// so that it can safely be transferred between 32-bit and 64-bit processes. |
|
// The ownership semantics for this are: |
|
// 1) The conversion constructor and assignment operator taking a const native_handle_t* |
|
// do not take ownership of the handle; this is because these operations are usually |
|
// just done for IPC, and cloning by default is a waste of resources. If you want |
|
// a hidl_handle to take ownership, call setTo(handle, true /*shouldOwn*/); |
|
// 2) The copy constructor/assignment operator taking a hidl_handle *DO* take ownership; |
|
// that is because it's not intuitive that this class encapsulates a native_handle_t |
|
// which needs cloning to be valid; in particular, this allows constructs like this: |
|
// hidl_handle copy; |
|
// foo->someHidlCall([&](auto incoming_handle) { |
|
// copy = incoming_handle; |
|
// }); |
|
// // copy and its enclosed file descriptors will remain valid here. |
|
// 3) The move constructor does what you would expect; it only owns the handle if the |
|
// original did. |
|
struct hidl_handle { |
|
hidl_handle(); |
|
~hidl_handle(); |
|
|
|
hidl_handle(const native_handle_t *handle); |
|
|
|
// copy constructor. |
|
hidl_handle(const hidl_handle &other); |
|
|
|
// move constructor. |
|
hidl_handle(hidl_handle &&other) noexcept; |
|
|
|
// assignment operators |
|
hidl_handle &operator=(const hidl_handle &other); |
|
|
|
hidl_handle &operator=(const native_handle_t *native_handle); |
|
|
|
hidl_handle &operator=(hidl_handle &&other) noexcept; |
|
|
|
void setTo(native_handle_t* handle, bool shouldOwn = false); |
|
|
|
const native_handle_t* operator->() const; |
|
|
|
// implicit conversion to const native_handle_t* |
|
operator const native_handle_t *() const; |
|
|
|
// explicit conversion |
|
const native_handle_t *getNativeHandle() const; |
|
private: |
|
void freeHandle(); |
|
|
|
details::hidl_pointer<const native_handle_t> mHandle __attribute__ ((aligned(8))); |
|
bool mOwnsHandle __attribute ((aligned(8))); |
|
}; |
|
|
|
struct hidl_string { |
|
hidl_string(); |
|
~hidl_string(); |
|
|
|
// copy constructor. |
|
hidl_string(const hidl_string &); |
|
// copy from a C-style string. nullptr will create an empty string |
|
hidl_string(const char *); |
|
// copy the first length characters from a C-style string. |
|
hidl_string(const char *, size_t length); |
|
// copy from an std::string. |
|
hidl_string(const std::string &); |
|
|
|
// move constructor. |
|
hidl_string(hidl_string &&) noexcept; |
|
|
|
const char *c_str() const; |
|
size_t size() const; |
|
bool empty() const; |
|
|
|
// copy assignment operator. |
|
hidl_string &operator=(const hidl_string &); |
|
// copy from a C-style string. |
|
hidl_string &operator=(const char *s); |
|
// copy from an std::string. |
|
hidl_string &operator=(const std::string &); |
|
// move assignment operator. |
|
hidl_string &operator=(hidl_string &&other) noexcept; |
|
// cast to std::string. |
|
operator std::string() const; |
|
|
|
void clear(); |
|
|
|
// Reference an external char array. Ownership is _not_ transferred. |
|
// Caller is responsible for ensuring that underlying memory is valid |
|
// for the lifetime of this hidl_string. |
|
void setToExternal(const char *data, size_t size); |
|
|
|
// offsetof(hidl_string, mBuffer) exposed since mBuffer is private. |
|
static const size_t kOffsetOfBuffer; |
|
|
|
private: |
|
details::hidl_pointer<const char> mBuffer; |
|
uint32_t mSize; // NOT including the terminating '\0'. |
|
bool mOwnsBuffer; // if true then mBuffer is a mutable char * |
|
|
|
// copy from data with size. Assume that my memory is freed |
|
// (through clear(), for example) |
|
void copyFrom(const char *data, size_t size); |
|
// move from another hidl_string |
|
void moveFrom(hidl_string &&); |
|
}; |
|
|
|
#define HIDL_STRING_OPERATOR(OP) \ |
|
inline bool operator OP(const hidl_string &hs1, const hidl_string &hs2) { \ |
|
return strcmp(hs1.c_str(), hs2.c_str()) OP 0; \ |
|
} \ |
|
inline bool operator OP(const hidl_string &hs, const char *s) { \ |
|
return strcmp(hs.c_str(), s) OP 0; \ |
|
} \ |
|
inline bool operator OP(const char *s, const hidl_string &hs) { \ |
|
return strcmp(hs.c_str(), s) OP 0; \ |
|
} |
|
|
|
HIDL_STRING_OPERATOR(==) |
|
HIDL_STRING_OPERATOR(!=) |
|
HIDL_STRING_OPERATOR(<) |
|
HIDL_STRING_OPERATOR(<=) |
|
HIDL_STRING_OPERATOR(>) |
|
HIDL_STRING_OPERATOR(>=) |
|
|
|
#undef HIDL_STRING_OPERATOR |
|
|
|
// Send our content to the output stream |
|
std::ostream& operator<<(std::ostream& os, const hidl_string& str); |
|
|
|
|
|
// hidl_memory is a structure that can be used to transfer |
|
// pieces of shared memory between processes. The assumption |
|
// of this object is that the memory remains accessible as |
|
// long as the file descriptors in the enclosed mHandle |
|
// - as well as all of its cross-process dups() - remain opened. |
|
struct hidl_memory { |
|
|
|
hidl_memory() : mHandle(nullptr), mSize(0), mName("") { |
|
} |
|
|
|
/** |
|
* Creates a hidl_memory object, but doesn't take ownership of |
|
* the passed in native_handle_t; callers are responsible for |
|
* making sure the handle remains valid while this object is |
|
* used. |
|
*/ |
|
hidl_memory(const hidl_string &name, const native_handle_t *handle, size_t size) |
|
: mHandle(handle), |
|
mSize(size), |
|
mName(name) |
|
{} |
|
|
|
// copy constructor |
|
hidl_memory(const hidl_memory& other) { |
|
*this = other; |
|
} |
|
|
|
// copy assignment |
|
hidl_memory &operator=(const hidl_memory &other) { |
|
if (this != &other) { |
|
mHandle = other.mHandle; |
|
mSize = other.mSize; |
|
mName = other.mName; |
|
} |
|
|
|
return *this; |
|
} |
|
|
|
// move constructor |
|
hidl_memory(hidl_memory&& other) noexcept { |
|
*this = std::move(other); |
|
} |
|
|
|
// move assignment |
|
hidl_memory &operator=(hidl_memory &&other) noexcept { |
|
if (this != &other) { |
|
mHandle = std::move(other.mHandle); |
|
mSize = other.mSize; |
|
mName = std::move(other.mName); |
|
other.mSize = 0; |
|
} |
|
|
|
return *this; |
|
} |
|
|
|
|
|
~hidl_memory() { |
|
} |
|
|
|
const native_handle_t* handle() const { |
|
return mHandle; |
|
} |
|
|
|
const hidl_string &name() const { |
|
return mName; |
|
} |
|
|
|
uint64_t size() const { |
|
return mSize; |
|
} |
|
|
|
// offsetof(hidl_memory, mHandle) exposed since mHandle is private. |
|
static const size_t kOffsetOfHandle; |
|
// offsetof(hidl_memory, mName) exposed since mHandle is private. |
|
static const size_t kOffsetOfName; |
|
|
|
private: |
|
hidl_handle mHandle __attribute__ ((aligned(8))); |
|
uint64_t mSize __attribute__ ((aligned(8))); |
|
hidl_string mName __attribute__ ((aligned(8))); |
|
}; |
|
|
|
//////////////////////////////////////////////////////////////////////////////// |
|
|
|
template<typename T> |
|
struct hidl_vec { |
|
hidl_vec() |
|
: mBuffer(NULL), |
|
mSize(0), |
|
mOwnsBuffer(true) { |
|
static_assert(hidl_vec<T>::kOffsetOfBuffer == 0, "wrong offset"); |
|
} |
|
|
|
hidl_vec(const hidl_vec<T> &other) : hidl_vec() { |
|
*this = other; |
|
} |
|
|
|
hidl_vec(hidl_vec<T> &&other) noexcept |
|
: mOwnsBuffer(false) { |
|
*this = std::move(other); |
|
} |
|
|
|
hidl_vec(const std::initializer_list<T> list) |
|
: mOwnsBuffer(true) { |
|
if (list.size() > UINT32_MAX) { |
|
details::logAlwaysFatal("hidl_vec can't hold more than 2^32 elements."); |
|
} |
|
mSize = static_cast<uint32_t>(list.size()); |
|
mBuffer = new T[mSize]; |
|
|
|
size_t idx = 0; |
|
for (auto it = list.begin(); it != list.end(); ++it) { |
|
mBuffer[idx++] = *it; |
|
} |
|
} |
|
|
|
hidl_vec(const std::vector<T> &other) : hidl_vec() { |
|
*this = other; |
|
} |
|
|
|
template <typename InputIterator, |
|
typename = typename std::enable_if<std::is_convertible< |
|
typename std::iterator_traits<InputIterator>::iterator_category, |
|
std::input_iterator_tag>::value>::type> |
|
hidl_vec(InputIterator first, InputIterator last) : mOwnsBuffer(true) { |
|
auto size = std::distance(first, last); |
|
if (size > static_cast<int64_t>(UINT32_MAX)) { |
|
details::logAlwaysFatal("hidl_vec can't hold more than 2^32 elements."); |
|
} |
|
if (size < 0) { |
|
details::logAlwaysFatal("size can't be negative."); |
|
} |
|
mSize = static_cast<uint32_t>(size); |
|
mBuffer = new T[mSize]; |
|
|
|
size_t idx = 0; |
|
for (; first != last; ++first) { |
|
mBuffer[idx++] = static_cast<T>(*first); |
|
} |
|
} |
|
|
|
~hidl_vec() { |
|
if (mOwnsBuffer) { |
|
delete[] mBuffer; |
|
} |
|
mBuffer = NULL; |
|
} |
|
|
|
// Reference an existing array, optionally taking ownership. It is the |
|
// caller's responsibility to ensure that the underlying memory stays |
|
// valid for the lifetime of this hidl_vec. |
|
void setToExternal(T *data, size_t size, bool shouldOwn = false) { |
|
if (mOwnsBuffer) { |
|
delete [] mBuffer; |
|
} |
|
mBuffer = data; |
|
if (size > UINT32_MAX) { |
|
details::logAlwaysFatal("external vector size exceeds 2^32 elements."); |
|
} |
|
mSize = static_cast<uint32_t>(size); |
|
mOwnsBuffer = shouldOwn; |
|
} |
|
|
|
T *data() { |
|
return mBuffer; |
|
} |
|
|
|
const T *data() const { |
|
return mBuffer; |
|
} |
|
|
|
T *releaseData() { |
|
if (!mOwnsBuffer && mSize > 0) { |
|
resize(mSize); |
|
} |
|
mOwnsBuffer = false; |
|
return mBuffer; |
|
} |
|
|
|
hidl_vec &operator=(hidl_vec &&other) noexcept { |
|
if (mOwnsBuffer) { |
|
delete[] mBuffer; |
|
} |
|
mBuffer = other.mBuffer; |
|
mSize = other.mSize; |
|
mOwnsBuffer = other.mOwnsBuffer; |
|
other.mOwnsBuffer = false; |
|
return *this; |
|
} |
|
|
|
hidl_vec &operator=(const hidl_vec &other) { |
|
if (this != &other) { |
|
if (mOwnsBuffer) { |
|
delete[] mBuffer; |
|
} |
|
copyFrom(other, other.mSize); |
|
} |
|
|
|
return *this; |
|
} |
|
|
|
// copy from an std::vector. |
|
hidl_vec &operator=(const std::vector<T> &other) { |
|
if (mOwnsBuffer) { |
|
delete[] mBuffer; |
|
} |
|
copyFrom(other, other.size()); |
|
return *this; |
|
} |
|
|
|
// cast to an std::vector. |
|
operator std::vector<T>() const { |
|
std::vector<T> v(mSize); |
|
for (size_t i = 0; i < mSize; ++i) { |
|
v[i] = mBuffer[i]; |
|
} |
|
return v; |
|
} |
|
|
|
// equality check, assuming that T::operator== is defined. |
|
bool operator==(const hidl_vec &other) const { |
|
if (mSize != other.size()) { |
|
return false; |
|
} |
|
for (size_t i = 0; i < mSize; ++i) { |
|
if (!(mBuffer[i] == other.mBuffer[i])) { |
|
return false; |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
// inequality check, assuming that T::operator== is defined. |
|
inline bool operator!=(const hidl_vec &other) const { |
|
return !((*this) == other); |
|
} |
|
|
|
size_t size() const { |
|
return mSize; |
|
} |
|
|
|
T &operator[](size_t index) { |
|
return mBuffer[index]; |
|
} |
|
|
|
const T &operator[](size_t index) const { |
|
return mBuffer[index]; |
|
} |
|
|
|
void resize(size_t size) { |
|
if (size > UINT32_MAX) { |
|
details::logAlwaysFatal("hidl_vec can't hold more than 2^32 elements."); |
|
} |
|
T *newBuffer = new T[size]; |
|
|
|
for (size_t i = 0; i < std::min(static_cast<uint32_t>(size), mSize); ++i) { |
|
newBuffer[i] = mBuffer[i]; |
|
} |
|
|
|
if (mOwnsBuffer) { |
|
delete[] mBuffer; |
|
} |
|
mBuffer = newBuffer; |
|
|
|
mSize = static_cast<uint32_t>(size); |
|
mOwnsBuffer = true; |
|
} |
|
|
|
// offsetof(hidl_string, mBuffer) exposed since mBuffer is private. |
|
static const size_t kOffsetOfBuffer; |
|
|
|
private: |
|
// Define std interator interface for walking the array contents |
|
template<bool is_const> |
|
class iter : public std::iterator< |
|
std::random_access_iterator_tag, /* Category */ |
|
T, |
|
ptrdiff_t, /* Distance */ |
|
typename std::conditional<is_const, const T *, T *>::type /* Pointer */, |
|
typename std::conditional<is_const, const T &, T &>::type /* Reference */> |
|
{ |
|
using traits = std::iterator_traits<iter>; |
|
using ptr_type = typename traits::pointer; |
|
using ref_type = typename traits::reference; |
|
using diff_type = typename traits::difference_type; |
|
public: |
|
iter(ptr_type ptr) : mPtr(ptr) { } |
|
inline iter &operator++() { mPtr++; return *this; } |
|
inline iter operator++(int) { iter i = *this; mPtr++; return i; } |
|
inline iter &operator--() { mPtr--; return *this; } |
|
inline iter operator--(int) { iter i = *this; mPtr--; return i; } |
|
inline friend iter operator+(diff_type n, const iter &it) { return it.mPtr + n; } |
|
inline iter operator+(diff_type n) const { return mPtr + n; } |
|
inline iter operator-(diff_type n) const { return mPtr - n; } |
|
inline diff_type operator-(const iter &other) const { return mPtr - other.mPtr; } |
|
inline iter &operator+=(diff_type n) { mPtr += n; return *this; } |
|
inline iter &operator-=(diff_type n) { mPtr -= n; return *this; } |
|
inline ref_type operator*() const { return *mPtr; } |
|
inline ptr_type operator->() const { return mPtr; } |
|
inline bool operator==(const iter &rhs) const { return mPtr == rhs.mPtr; } |
|
inline bool operator!=(const iter &rhs) const { return mPtr != rhs.mPtr; } |
|
inline bool operator< (const iter &rhs) const { return mPtr < rhs.mPtr; } |
|
inline bool operator> (const iter &rhs) const { return mPtr > rhs.mPtr; } |
|
inline bool operator<=(const iter &rhs) const { return mPtr <= rhs.mPtr; } |
|
inline bool operator>=(const iter &rhs) const { return mPtr >= rhs.mPtr; } |
|
inline ref_type operator[](size_t n) const { return mPtr[n]; } |
|
private: |
|
ptr_type mPtr; |
|
}; |
|
public: |
|
using iterator = iter<false /* is_const */>; |
|
using const_iterator = iter<true /* is_const */>; |
|
|
|
iterator begin() { return data(); } |
|
iterator end() { return data()+mSize; } |
|
const_iterator begin() const { return data(); } |
|
const_iterator end() const { return data()+mSize; } |
|
|
|
private: |
|
details::hidl_pointer<T> mBuffer; |
|
uint32_t mSize; |
|
bool mOwnsBuffer; |
|
|
|
// copy from an array-like object, assuming my resources are freed. |
|
template <typename Array> |
|
void copyFrom(const Array &data, size_t size) { |
|
mSize = static_cast<uint32_t>(size); |
|
mOwnsBuffer = true; |
|
if (mSize > 0) { |
|
mBuffer = new T[size]; |
|
for (size_t i = 0; i < size; ++i) { |
|
mBuffer[i] = data[i]; |
|
} |
|
} else { |
|
mBuffer = NULL; |
|
} |
|
} |
|
}; |
|
|
|
template <typename T> |
|
const size_t hidl_vec<T>::kOffsetOfBuffer = offsetof(hidl_vec<T>, mBuffer); |
|
|
|
//////////////////////////////////////////////////////////////////////////////// |
|
|
|
namespace details { |
|
|
|
template<size_t SIZE1, size_t... SIZES> |
|
struct product { |
|
static constexpr size_t value = SIZE1 * product<SIZES...>::value; |
|
}; |
|
|
|
template<size_t SIZE1> |
|
struct product<SIZE1> { |
|
static constexpr size_t value = SIZE1; |
|
}; |
|
|
|
template<typename T, size_t SIZE1, size_t... SIZES> |
|
struct std_array { |
|
using type = std::array<typename std_array<T, SIZES...>::type, SIZE1>; |
|
}; |
|
|
|
template<typename T, size_t SIZE1> |
|
struct std_array<T, SIZE1> { |
|
using type = std::array<T, SIZE1>; |
|
}; |
|
|
|
template<typename T, size_t SIZE1, size_t... SIZES> |
|
struct accessor { |
|
|
|
using std_array_type = typename std_array<T, SIZE1, SIZES...>::type; |
|
|
|
explicit accessor(T *base) |
|
: mBase(base) { |
|
} |
|
|
|
accessor<T, SIZES...> operator[](size_t index) { |
|
return accessor<T, SIZES...>( |
|
&mBase[index * product<SIZES...>::value]); |
|
} |
|
|
|
accessor &operator=(const std_array_type &other) { |
|
for (size_t i = 0; i < SIZE1; ++i) { |
|
(*this)[i] = other[i]; |
|
} |
|
return *this; |
|
} |
|
|
|
private: |
|
T *mBase; |
|
}; |
|
|
|
template<typename T, size_t SIZE1> |
|
struct accessor<T, SIZE1> { |
|
|
|
using std_array_type = typename std_array<T, SIZE1>::type; |
|
|
|
explicit accessor(T *base) |
|
: mBase(base) { |
|
} |
|
|
|
T &operator[](size_t index) { |
|
return mBase[index]; |
|
} |
|
|
|
accessor &operator=(const std_array_type &other) { |
|
for (size_t i = 0; i < SIZE1; ++i) { |
|
(*this)[i] = other[i]; |
|
} |
|
return *this; |
|
} |
|
|
|
private: |
|
T *mBase; |
|
}; |
|
|
|
template<typename T, size_t SIZE1, size_t... SIZES> |
|
struct const_accessor { |
|
|
|
using std_array_type = typename std_array<T, SIZE1, SIZES...>::type; |
|
|
|
explicit const_accessor(const T *base) |
|
: mBase(base) { |
|
} |
|
|
|
const_accessor<T, SIZES...> operator[](size_t index) const { |
|
return const_accessor<T, SIZES...>( |
|
&mBase[index * product<SIZES...>::value]); |
|
} |
|
|
|
operator std_array_type() { |
|
std_array_type array; |
|
for (size_t i = 0; i < SIZE1; ++i) { |
|
array[i] = (*this)[i]; |
|
} |
|
return array; |
|
} |
|
|
|
private: |
|
const T *mBase; |
|
}; |
|
|
|
template<typename T, size_t SIZE1> |
|
struct const_accessor<T, SIZE1> { |
|
|
|
using std_array_type = typename std_array<T, SIZE1>::type; |
|
|
|
explicit const_accessor(const T *base) |
|
: mBase(base) { |
|
} |
|
|
|
const T &operator[](size_t index) const { |
|
return mBase[index]; |
|
} |
|
|
|
operator std_array_type() { |
|
std_array_type array; |
|
for (size_t i = 0; i < SIZE1; ++i) { |
|
array[i] = (*this)[i]; |
|
} |
|
return array; |
|
} |
|
|
|
private: |
|
const T *mBase; |
|
}; |
|
|
|
} // namespace details |
|
|
|
//////////////////////////////////////////////////////////////////////////////// |
|
|
|
// A multidimensional array of T's. Assumes that T::operator=(const T &) is defined. |
|
template<typename T, size_t SIZE1, size_t... SIZES> |
|
struct hidl_array { |
|
|
|
using std_array_type = typename details::std_array<T, SIZE1, SIZES...>::type; |
|
|
|
hidl_array() = default; |
|
|
|
// Copies the data from source, using T::operator=(const T &). |
|
hidl_array(const T *source) { |
|
for (size_t i = 0; i < elementCount(); ++i) { |
|
mBuffer[i] = source[i]; |
|
} |
|
} |
|
|
|
// Copies the data from the given std::array, using T::operator=(const T &). |
|
hidl_array(const std_array_type &array) { |
|
details::accessor<T, SIZE1, SIZES...> modifier(mBuffer); |
|
modifier = array; |
|
} |
|
|
|
T *data() { return mBuffer; } |
|
const T *data() const { return mBuffer; } |
|
|
|
details::accessor<T, SIZES...> operator[](size_t index) { |
|
return details::accessor<T, SIZES...>( |
|
&mBuffer[index * details::product<SIZES...>::value]); |
|
} |
|
|
|
details::const_accessor<T, SIZES...> operator[](size_t index) const { |
|
return details::const_accessor<T, SIZES...>( |
|
&mBuffer[index * details::product<SIZES...>::value]); |
|
} |
|
|
|
// equality check, assuming that T::operator== is defined. |
|
bool operator==(const hidl_array &other) const { |
|
for (size_t i = 0; i < elementCount(); ++i) { |
|
if (!(mBuffer[i] == other.mBuffer[i])) { |
|
return false; |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
inline bool operator!=(const hidl_array &other) const { |
|
return !((*this) == other); |
|
} |
|
|
|
using size_tuple_type = std::tuple<decltype(SIZE1), decltype(SIZES)...>; |
|
|
|
static constexpr size_tuple_type size() { |
|
return std::make_tuple(SIZE1, SIZES...); |
|
} |
|
|
|
static constexpr size_t elementCount() { |
|
return details::product<SIZE1, SIZES...>::value; |
|
} |
|
|
|
operator std_array_type() const { |
|
return details::const_accessor<T, SIZE1, SIZES...>(mBuffer); |
|
} |
|
|
|
private: |
|
T mBuffer[elementCount()]; |
|
}; |
|
|
|
// An array of T's. Assumes that T::operator=(const T &) is defined. |
|
template<typename T, size_t SIZE1> |
|
struct hidl_array<T, SIZE1> { |
|
|
|
using std_array_type = typename details::std_array<T, SIZE1>::type; |
|
|
|
hidl_array() = default; |
|
|
|
// Copies the data from source, using T::operator=(const T &). |
|
hidl_array(const T *source) { |
|
for (size_t i = 0; i < elementCount(); ++i) { |
|
mBuffer[i] = source[i]; |
|
} |
|
} |
|
|
|
// Copies the data from the given std::array, using T::operator=(const T &). |
|
hidl_array(const std_array_type &array) : hidl_array(array.data()) {} |
|
|
|
T *data() { return mBuffer; } |
|
const T *data() const { return mBuffer; } |
|
|
|
T &operator[](size_t index) { |
|
return mBuffer[index]; |
|
} |
|
|
|
const T &operator[](size_t index) const { |
|
return mBuffer[index]; |
|
} |
|
|
|
// equality check, assuming that T::operator== is defined. |
|
bool operator==(const hidl_array &other) const { |
|
for (size_t i = 0; i < elementCount(); ++i) { |
|
if (!(mBuffer[i] == other.mBuffer[i])) { |
|
return false; |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
inline bool operator!=(const hidl_array &other) const { |
|
return !((*this) == other); |
|
} |
|
|
|
static constexpr size_t size() { return SIZE1; } |
|
static constexpr size_t elementCount() { return SIZE1; } |
|
|
|
// Copies the data to an std::array, using T::operator=(T). |
|
operator std_array_type() const { |
|
std_array_type array; |
|
for (size_t i = 0; i < SIZE1; ++i) { |
|
array[i] = mBuffer[i]; |
|
} |
|
return array; |
|
} |
|
|
|
private: |
|
T mBuffer[SIZE1]; |
|
}; |
|
|
|
// ---------------------------------------------------------------------- |
|
// Version functions |
|
struct hidl_version { |
|
public: |
|
constexpr hidl_version(uint16_t major, uint16_t minor) : mMajor(major), mMinor(minor) {} |
|
|
|
bool operator==(const hidl_version& other) const { |
|
return (mMajor == other.get_major() && mMinor == other.get_minor()); |
|
} |
|
|
|
bool operator<(const hidl_version& other) const { |
|
return (mMajor < other.get_major() || |
|
(mMajor == other.get_major() && mMinor < other.get_minor())); |
|
} |
|
|
|
bool operator>(const hidl_version& other) const { |
|
return other < *this; |
|
} |
|
|
|
bool operator<=(const hidl_version& other) const { |
|
return !(*this > other); |
|
} |
|
|
|
bool operator>=(const hidl_version& other) const { |
|
return !(*this < other); |
|
} |
|
|
|
constexpr uint16_t get_major() const { return mMajor; } |
|
constexpr uint16_t get_minor() const { return mMinor; } |
|
|
|
private: |
|
uint16_t mMajor; |
|
uint16_t mMinor; |
|
}; |
|
|
|
inline android::hardware::hidl_version make_hidl_version(uint16_t major, uint16_t minor) { |
|
return hidl_version(major,minor); |
|
} |
|
|
|
///////////////////// toString functions |
|
|
|
std::string toString(const void *t); |
|
|
|
// toString alias for numeric types |
|
template<typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type> |
|
inline std::string toString(T t) { |
|
return std::to_string(t); |
|
} |
|
|
|
namespace details { |
|
|
|
template<typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type> |
|
inline std::string toHexString(T t, bool prefix = true) { |
|
std::ostringstream os; |
|
if (prefix) { os << std::showbase; } |
|
os << std::hex << t; |
|
return os.str(); |
|
} |
|
|
|
template<> |
|
inline std::string toHexString(uint8_t t, bool prefix) { |
|
return toHexString(static_cast<int32_t>(t), prefix); |
|
} |
|
|
|
template<> |
|
inline std::string toHexString(int8_t t, bool prefix) { |
|
return toHexString(static_cast<int32_t>(t), prefix); |
|
} |
|
|
|
template<typename Array> |
|
std::string arrayToString(const Array &a, size_t size); |
|
|
|
template<size_t SIZE1> |
|
std::string arraySizeToString() { |
|
return std::string{"["} + toString(SIZE1) + "]"; |
|
} |
|
|
|
template<size_t SIZE1, size_t SIZE2, size_t... SIZES> |
|
std::string arraySizeToString() { |
|
return std::string{"["} + toString(SIZE1) + "]" + arraySizeToString<SIZE2, SIZES...>(); |
|
} |
|
|
|
template<typename T, size_t SIZE1> |
|
std::string toString(details::const_accessor<T, SIZE1> a) { |
|
return arrayToString(a, SIZE1); |
|
} |
|
|
|
template<typename Array> |
|
std::string arrayToString(const Array &a, size_t size) { |
|
using android::hardware::toString; |
|
std::string os; |
|
os += "{"; |
|
for (size_t i = 0; i < size; ++i) { |
|
if (i > 0) { |
|
os += ", "; |
|
} |
|
os += toString(a[i]); |
|
} |
|
os += "}"; |
|
return os; |
|
} |
|
|
|
template<typename T, size_t SIZE1, size_t SIZE2, size_t... SIZES> |
|
std::string toString(details::const_accessor<T, SIZE1, SIZE2, SIZES...> a) { |
|
return arrayToString(a, SIZE1); |
|
} |
|
|
|
} //namespace details |
|
|
|
inline std::string toString(const void *t) { |
|
return details::toHexString(reinterpret_cast<uintptr_t>(t)); |
|
} |
|
|
|
// debug string dump. There will be quotes around the string! |
|
inline std::string toString(const hidl_string &hs) { |
|
return std::string{"\""} + hs.c_str() + "\""; |
|
} |
|
|
|
// debug string dump |
|
inline std::string toString(const hidl_handle &hs) { |
|
return toString(hs.getNativeHandle()); |
|
} |
|
|
|
inline std::string toString(const hidl_memory &mem) { |
|
return std::string{"memory {.name = "} + toString(mem.name()) + ", .size = " |
|
+ toString(mem.size()) |
|
+ ", .handle = " + toString(mem.handle()) + "}"; |
|
} |
|
|
|
inline std::string toString(const sp<hidl_death_recipient> &dr) { |
|
return std::string{"death_recipient@"} + toString(dr.get()); |
|
} |
|
|
|
// debug string dump, assuming that toString(T) is defined. |
|
template<typename T> |
|
std::string toString(const hidl_vec<T> &a) { |
|
std::string os; |
|
os += "[" + toString(a.size()) + "]"; |
|
os += details::arrayToString(a, a.size()); |
|
return os; |
|
} |
|
|
|
template<typename T, size_t SIZE1> |
|
std::string toString(const hidl_array<T, SIZE1> &a) { |
|
return details::arraySizeToString<SIZE1>() |
|
+ details::toString(details::const_accessor<T, SIZE1>(a.data())); |
|
} |
|
|
|
template<typename T, size_t SIZE1, size_t SIZE2, size_t... SIZES> |
|
std::string toString(const hidl_array<T, SIZE1, SIZE2, SIZES...> &a) { |
|
return details::arraySizeToString<SIZE1, SIZE2, SIZES...>() |
|
+ details::toString(details::const_accessor<T, SIZE1, SIZE2, SIZES...>(a.data())); |
|
} |
|
|
|
} // namespace hardware |
|
} // namespace android |
|
|
|
|
|
#endif // ANDROID_HIDL_SUPPORT_H
|
|
|