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.
1077 lines
32 KiB
1077 lines
32 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 <hidl/HidlInternal.h>
|
|
#include <map>
|
|
#include <sstream>
|
|
#include <stddef.h>
|
|
#include <tuple>
|
|
#include <type_traits>
|
|
#include <vector>
|
|
|
|
// no requirements on types not used in scatter/gather
|
|
// no requirements on other libraries
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wpadded"
|
|
#include <cutils/native_handle.h>
|
|
#include <hidl/Status.h>
|
|
#include <utils/Errors.h>
|
|
#include <utils/RefBase.h>
|
|
#include <utils/StrongPointer.h>
|
|
#pragma clang diagnostic pop
|
|
|
|
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 memory
|
|
} // 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;
|
|
|
|
// offsetof(hidl_handle, mHandle) exposed since mHandle is private.
|
|
static const size_t kOffsetOfNativeHandle;
|
|
|
|
private:
|
|
void freeHandle();
|
|
|
|
details::hidl_pointer<const native_handle_t> mHandle;
|
|
bool mOwnsHandle;
|
|
uint8_t mPad[7];
|
|
};
|
|
|
|
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.
|
|
//
|
|
// size == strlen(data)
|
|
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 *
|
|
uint8_t mPad[3];
|
|
|
|
// 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 &&);
|
|
};
|
|
|
|
// Use NOLINT to suppress missing parentheses warnings around OP.
|
|
#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; /* NOLINT */ \
|
|
} \
|
|
inline bool operator OP(const hidl_string& hs, const char* s) { \
|
|
return strcmp(hs.c_str(), s) OP 0; /* NOLINT */ \
|
|
} \
|
|
inline bool operator OP(const char* s, const hidl_string& hs) { \
|
|
return strcmp(s, hs.c_str()) OP 0; /* NOLINT */ \
|
|
}
|
|
|
|
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 whose handle has the same lifetime
|
|
* as the handle moved into it.
|
|
*/
|
|
hidl_memory(const hidl_string& name, hidl_handle&& handle, size_t size)
|
|
: mHandle(std::move(handle)), mSize(size), mName(name) {}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
// @return true if it's valid
|
|
inline bool valid() const { return handle() != nullptr; }
|
|
|
|
// 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;
|
|
uint64_t mSize;
|
|
hidl_string mName;
|
|
};
|
|
|
|
// HidlMemory is a wrapper class to support sp<> for hidl_memory. It also
|
|
// provides factory methods to create an instance from hidl_memory or
|
|
// from a opened file descriptor. The number of factory methods can be increase
|
|
// to support other type of hidl_memory without break the ABI.
|
|
class HidlMemory : public virtual hidl_memory, public virtual ::android::RefBase {
|
|
public:
|
|
static sp<HidlMemory> getInstance(const hidl_memory& mem);
|
|
|
|
static sp<HidlMemory> getInstance(hidl_memory&& mem);
|
|
|
|
static sp<HidlMemory> getInstance(const hidl_string& name, hidl_handle&& handle, uint64_t size);
|
|
// @param fd, shall be opened and points to the resource.
|
|
// @note this method takes the ownership of the fd and will close it in
|
|
// destructor
|
|
// @return nullptr in failure with the fd closed
|
|
static sp<HidlMemory> getInstance(const hidl_string& name, int fd, uint64_t size);
|
|
|
|
virtual ~HidlMemory();
|
|
|
|
protected:
|
|
HidlMemory();
|
|
HidlMemory(const hidl_string& name, hidl_handle&& handle, size_t size);
|
|
};
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
template<typename T>
|
|
struct hidl_vec {
|
|
using value_type = T;
|
|
|
|
hidl_vec() : mBuffer(nullptr), mSize(0), mOwnsBuffer(false) {
|
|
static_assert(hidl_vec<T>::kOffsetOfBuffer == 0, "wrong offset");
|
|
|
|
memset(mPad, 0, sizeof(mPad));
|
|
}
|
|
|
|
hidl_vec(size_t size) : hidl_vec() { resize(size); }
|
|
|
|
hidl_vec(const hidl_vec<T> &other) : hidl_vec() {
|
|
*this = other;
|
|
}
|
|
|
|
hidl_vec(hidl_vec<T> &&other) noexcept : hidl_vec() {
|
|
*this = std::move(other);
|
|
}
|
|
|
|
hidl_vec(const std::initializer_list<T> list) : hidl_vec() { *this = list; }
|
|
|
|
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) : hidl_vec() {
|
|
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]();
|
|
mOwnsBuffer = true;
|
|
|
|
size_t idx = 0;
|
|
for (; first != last; ++first) {
|
|
mBuffer[idx++] = static_cast<T>(*first);
|
|
}
|
|
}
|
|
|
|
~hidl_vec() {
|
|
if (mOwnsBuffer) {
|
|
delete[] mBuffer;
|
|
}
|
|
mBuffer = nullptr;
|
|
}
|
|
|
|
// 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 && mBuffer != nullptr) {
|
|
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;
|
|
}
|
|
|
|
hidl_vec& operator=(const std::initializer_list<T> list) {
|
|
if (list.size() > UINT32_MAX) {
|
|
details::logAlwaysFatal("hidl_vec can't hold more than 2^32 elements.");
|
|
}
|
|
if (mOwnsBuffer) {
|
|
delete[] mBuffer;
|
|
}
|
|
mSize = static_cast<uint32_t>(list.size());
|
|
mBuffer = new T[mSize]();
|
|
mOwnsBuffer = true;
|
|
|
|
size_t idx = 0;
|
|
for (auto it = list.begin(); it != list.end(); ++it) {
|
|
mBuffer[idx++] = *it;
|
|
}
|
|
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];
|
|
}
|
|
|
|
// Copies over old elements fitting in new size. Value initializes the rest.
|
|
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] = std::move(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; }
|
|
iterator find(const T& v) { return std::find(begin(), end(), v); }
|
|
const_iterator find(const T& v) const { return std::find(begin(), end(), v); }
|
|
bool contains(const T& v) const { return find(v) != end(); }
|
|
|
|
private:
|
|
details::hidl_pointer<T> mBuffer;
|
|
uint32_t mSize;
|
|
bool mOwnsBuffer;
|
|
uint8_t mPad[3];
|
|
|
|
// 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 = nullptr;
|
|
}
|
|
}
|
|
};
|
|
|
|
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;
|
|
hidl_array(const hidl_array&) noexcept = default;
|
|
hidl_array(hidl_array&&) noexcept = 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;
|
|
}
|
|
|
|
hidl_array& operator=(const hidl_array&) noexcept = default;
|
|
hidl_array& operator=(hidl_array&&) noexcept = default;
|
|
|
|
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 value_type = T;
|
|
using std_array_type = typename details::std_array<T, SIZE1>::type;
|
|
|
|
hidl_array() = default;
|
|
hidl_array(const hidl_array&) noexcept = default;
|
|
hidl_array(hidl_array&&) noexcept = 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()) {}
|
|
|
|
hidl_array& operator=(const hidl_array&) noexcept = default;
|
|
hidl_array& operator=(hidl_array&&) noexcept = default;
|
|
|
|
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) {
|
|
static_assert(sizeof(*this) == 4, "wrong size");
|
|
}
|
|
|
|
bool operator==(const hidl_version& other) const {
|
|
return (mMajor == other.get_major() && mMinor == other.get_minor());
|
|
}
|
|
|
|
bool operator!=(const hidl_version& other) const {
|
|
return !(*this == other);
|
|
}
|
|
|
|
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 details {
|
|
// Never instantiated. Used as a placeholder for template variables.
|
|
template <typename T>
|
|
struct hidl_invalid_type;
|
|
|
|
// HIDL generates specializations of this for enums. See hidl_enum_range.
|
|
template <typename T, typename = std::enable_if_t<std::is_enum<T>::value>>
|
|
constexpr hidl_invalid_type<T> hidl_enum_values;
|
|
} // namespace details
|
|
|
|
/**
|
|
* Every HIDL generated enum supports this function.
|
|
* E.x.: for(const auto v : hidl_enum_range<Enum>) { ... }
|
|
*/
|
|
template <typename T, typename = std::enable_if_t<std::is_enum<T>::value>>
|
|
struct hidl_enum_range {
|
|
// Container-like associated type.
|
|
using value_type = T;
|
|
|
|
constexpr auto begin() const { return std::begin(details::hidl_enum_values<T>); }
|
|
constexpr auto cbegin() const { return begin(); }
|
|
constexpr auto rbegin() const { return std::rbegin(details::hidl_enum_values<T>); }
|
|
constexpr auto crbegin() const { return rbegin(); }
|
|
constexpr auto end() const { return std::end(details::hidl_enum_values<T>); }
|
|
constexpr auto cend() const { return end(); }
|
|
constexpr auto rend() const { return std::rend(details::hidl_enum_values<T>); }
|
|
constexpr auto crend() const { return rend(); }
|
|
};
|
|
|
|
template <typename T, typename = std::enable_if_t<std::is_enum<T>::value>>
|
|
struct hidl_enum_iterator {
|
|
static_assert(!std::is_enum<T>::value,
|
|
"b/78573628: hidl_enum_iterator was renamed to hidl_enum_range because it is not "
|
|
"actually an iterator. Please use that type instead.");
|
|
};
|
|
|
|
/**
|
|
* Bitfields in HIDL are the underlying type of the enumeration.
|
|
*/
|
|
template <typename Enum>
|
|
using hidl_bitfield = typename std::underlying_type<Enum>::type;
|
|
|
|
} // namespace hardware
|
|
} // namespace android
|
|
|
|
|
|
#endif // ANDROID_HIDL_SUPPORT_H
|