upload android base code part6

This commit is contained in:
August 2018-08-08 17:48:24 +08:00
parent 421e214c7d
commit 4e516ec6ed
35396 changed files with 9188716 additions and 0 deletions

View file

@ -0,0 +1,53 @@
// 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.
cc_library_shared {
name: "libhidlbase",
vendor_available: true,
vndk: {
enabled: true,
support_system_process: true,
},
cflags: libhidl_flags,
shared_libs: [
"libbase",
"libcutils",
"liblog",
"libutils",
],
export_shared_lib_headers: [
"libutils",
"libcutils", // for native_handle.h
],
local_include_dirs: ["include"],
export_include_dirs: ["include"],
clang: true,
sanitize: {
misc_undefined: ["integer"],
},
srcs: [
"HidlInternal.cpp",
"HidlSupport.cpp",
"Status.cpp",
"TaskRunner.cpp",
],
product_variables: {
debuggable: {
cflags: ["-DLIBHIDL_TARGET_DEBUGGABLE"],
},
},
}

View file

@ -0,0 +1,162 @@
/*
* 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.
*/
#define LOG_TAG "HidlInternal"
#include <hidl/HidlInternal.h>
#include <android-base/logging.h>
#include <cutils/properties.h>
#ifdef LIBHIDL_TARGET_DEBUGGABLE
#include <dirent.h>
#include <dlfcn.h>
#include <regex>
#endif
namespace android {
namespace hardware {
namespace details {
void logAlwaysFatal(const char *message) {
LOG(FATAL) << message;
}
// ----------------------------------------------------------------------
// HidlInstrumentor implementation.
HidlInstrumentor::HidlInstrumentor(const std::string& package, const std::string& interface)
: mEnableInstrumentation(false),
mInstrumentationLibPackage(package),
mInterfaceName(interface) {
configureInstrumentation(false);
}
HidlInstrumentor:: ~HidlInstrumentor() {}
void HidlInstrumentor::configureInstrumentation(bool log) {
bool enableInstrumentation = property_get_bool(
"hal.instrumentation.enable",
false);
if (enableInstrumentation != mEnableInstrumentation) {
mEnableInstrumentation = enableInstrumentation;
if (mEnableInstrumentation) {
if (log) {
LOG(INFO) << "Enable instrumentation.";
}
registerInstrumentationCallbacks (&mInstrumentationCallbacks);
} else {
if (log) {
LOG(INFO) << "Disable instrumentation.";
}
mInstrumentationCallbacks.clear();
}
}
}
void HidlInstrumentor::registerInstrumentationCallbacks(
std::vector<InstrumentationCallback> *instrumentationCallbacks) {
#ifdef LIBHIDL_TARGET_DEBUGGABLE
std::vector<std::string> instrumentationLibPaths;
char instrumentationLibPath[PROPERTY_VALUE_MAX];
if (property_get("hal.instrumentation.lib.path",
instrumentationLibPath,
"") > 0) {
instrumentationLibPaths.push_back(instrumentationLibPath);
} else {
instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_SYSTEM);
instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_VNDK_SP);
instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_VENDOR);
instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_ODM);
}
for (auto path : instrumentationLibPaths) {
DIR *dir = opendir(path.c_str());
if (dir == 0) {
LOG(WARNING) << path << " does not exist. ";
return;
}
struct dirent *file;
while ((file = readdir(dir)) != NULL) {
if (!isInstrumentationLib(file))
continue;
void *handle = dlopen((path + file->d_name).c_str(), RTLD_NOW);
char *error;
if (handle == nullptr) {
LOG(WARNING) << "couldn't load file: " << file->d_name
<< " error: " << dlerror();
continue;
}
dlerror(); /* Clear any existing error */
using cbFun = void (*)(
const InstrumentationEvent,
const char *,
const char *,
const char *,
const char *,
std::vector<void *> *);
std::string package = mInstrumentationLibPackage;
for (size_t i = 0; i < package.size(); i++) {
if (package[i] == '.') {
package[i] = '_';
continue;
}
if (package[i] == '@') {
package[i] = '_';
package.insert(i + 1, "V");
continue;
}
}
auto cb = (cbFun)dlsym(handle, ("HIDL_INSTRUMENTATION_FUNCTION_"
+ package + "_" + mInterfaceName).c_str());
if ((error = dlerror()) != NULL) {
LOG(WARNING)
<< "couldn't find symbol: HIDL_INSTRUMENTATION_FUNCTION_"
<< package << "_" << mInterfaceName << ", error: " << error;
continue;
}
instrumentationCallbacks->push_back(cb);
LOG(INFO) << "Register instrumentation callback from "
<< file->d_name;
}
closedir(dir);
}
#else
// No-op for user builds.
(void) instrumentationCallbacks;
return;
#endif
}
bool HidlInstrumentor::isInstrumentationLib(const dirent *file) {
#ifdef LIBHIDL_TARGET_DEBUGGABLE
if (file->d_type != DT_REG) return false;
std::cmatch cm;
std::regex e("^" + mInstrumentationLibPackage + "(.*).profiler.so$");
if (std::regex_match(file->d_name, cm, e)) return true;
#else
(void) file;
#endif
return false;
}
} // namespace details
} // namespace hardware
} // namespace android

View file

@ -0,0 +1,279 @@
/*
* 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.
*/
#define LOG_TAG "HidlSupport"
#include <hidl/HidlSupport.h>
#include <unordered_map>
#include <android-base/logging.h>
#include <android-base/parseint.h>
namespace android {
namespace hardware {
namespace details {
bool debuggable() {
#ifdef LIBHIDL_TARGET_DEBUGGABLE
return true;
#else
return false;
#endif
}
} // namespace details
hidl_handle::hidl_handle() {
mHandle = nullptr;
mOwnsHandle = false;
}
hidl_handle::~hidl_handle() {
freeHandle();
}
hidl_handle::hidl_handle(const native_handle_t *handle) {
mHandle = handle;
mOwnsHandle = false;
}
// copy constructor.
hidl_handle::hidl_handle(const hidl_handle &other) {
mOwnsHandle = false;
*this = other;
}
// move constructor.
hidl_handle::hidl_handle(hidl_handle &&other) {
mOwnsHandle = false;
*this = std::move(other);
}
// assignment operators
hidl_handle &hidl_handle::operator=(const hidl_handle &other) {
if (this == &other) {
return *this;
}
freeHandle();
if (other.mHandle != nullptr) {
mHandle = native_handle_clone(other.mHandle);
if (mHandle == nullptr) {
PLOG(FATAL) << "Failed to clone native_handle in hidl_handle";
}
mOwnsHandle = true;
} else {
mHandle = nullptr;
mOwnsHandle = false;
}
return *this;
}
hidl_handle &hidl_handle::operator=(const native_handle_t *native_handle) {
freeHandle();
mHandle = native_handle;
mOwnsHandle = false;
return *this;
}
hidl_handle &hidl_handle::operator=(hidl_handle &&other) {
if (this != &other) {
freeHandle();
mHandle = other.mHandle;
mOwnsHandle = other.mOwnsHandle;
other.mHandle = nullptr;
other.mOwnsHandle = false;
}
return *this;
}
void hidl_handle::setTo(native_handle_t* handle, bool shouldOwn) {
freeHandle();
mHandle = handle;
mOwnsHandle = shouldOwn;
}
const native_handle_t* hidl_handle::operator->() const {
return mHandle;
}
// implicit conversion to const native_handle_t*
hidl_handle::operator const native_handle_t *() const {
return mHandle;
}
// explicit conversion
const native_handle_t *hidl_handle::getNativeHandle() const {
return mHandle;
}
void hidl_handle::freeHandle() {
if (mOwnsHandle && mHandle != nullptr) {
// This can only be true if:
// 1. Somebody called setTo() with shouldOwn=true, so we know the handle
// wasn't const to begin with.
// 2. Copy/assignment from another hidl_handle, in which case we have
// cloned the handle.
// 3. Move constructor from another hidl_handle, in which case the original
// hidl_handle must have been non-const as well.
native_handle_t *handle = const_cast<native_handle_t*>(
static_cast<const native_handle_t*>(mHandle));
native_handle_close(handle);
native_handle_delete(handle);
mHandle = nullptr;
}
}
static const char *const kEmptyString = "";
hidl_string::hidl_string()
: mBuffer(kEmptyString),
mSize(0),
mOwnsBuffer(false) {
}
hidl_string::~hidl_string() {
clear();
}
hidl_string::hidl_string(const char *s) : hidl_string() {
if (s == nullptr) {
return;
}
copyFrom(s, strlen(s));
}
hidl_string::hidl_string(const char *s, size_t length) : hidl_string() {
copyFrom(s, length);
}
hidl_string::hidl_string(const hidl_string &other): hidl_string() {
copyFrom(other.c_str(), other.size());
}
hidl_string::hidl_string(const std::string &s) : hidl_string() {
copyFrom(s.c_str(), s.size());
}
hidl_string::hidl_string(hidl_string &&other): hidl_string() {
moveFrom(std::forward<hidl_string>(other));
}
hidl_string &hidl_string::operator=(hidl_string &&other) {
if (this != &other) {
clear();
moveFrom(std::forward<hidl_string>(other));
}
return *this;
}
hidl_string &hidl_string::operator=(const hidl_string &other) {
if (this != &other) {
clear();
copyFrom(other.c_str(), other.size());
}
return *this;
}
hidl_string &hidl_string::operator=(const char *s) {
clear();
if (s == nullptr) {
return *this;
}
copyFrom(s, strlen(s));
return *this;
}
hidl_string &hidl_string::operator=(const std::string &s) {
clear();
copyFrom(s.c_str(), s.size());
return *this;
}
hidl_string::operator std::string() const {
return std::string(mBuffer, mSize);
}
std::ostream& operator<<(std::ostream& os, const hidl_string& str) {
os << str.c_str();
return os;
}
void hidl_string::copyFrom(const char *data, size_t size) {
// assume my resources are freed.
if (size > UINT32_MAX) {
LOG(FATAL) << "string size can't exceed 2^32 bytes: " << size;
}
char *buf = (char *)malloc(size + 1);
memcpy(buf, data, size);
buf[size] = '\0';
mBuffer = buf;
mSize = static_cast<uint32_t>(size);
mOwnsBuffer = true;
}
void hidl_string::moveFrom(hidl_string &&other) {
// assume my resources are freed.
mBuffer = std::move(other.mBuffer);
mSize = other.mSize;
mOwnsBuffer = other.mOwnsBuffer;
other.mOwnsBuffer = false;
other.clear();
}
void hidl_string::clear() {
if (mOwnsBuffer && (mBuffer != kEmptyString)) {
free(const_cast<char *>(static_cast<const char *>(mBuffer)));
}
mBuffer = kEmptyString;
mSize = 0;
mOwnsBuffer = false;
}
void hidl_string::setToExternal(const char *data, size_t size) {
if (size > UINT32_MAX) {
LOG(FATAL) << "string size can't exceed 2^32 bytes: " << size;
}
clear();
mBuffer = data;
mSize = static_cast<uint32_t>(size);
mOwnsBuffer = false;
}
const char *hidl_string::c_str() const {
return mBuffer;
}
size_t hidl_string::size() const {
return mSize;
}
bool hidl_string::empty() const {
return mSize == 0;
}
} // namespace hardware
} // namespace android

View file

@ -0,0 +1,165 @@
/*
* 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 "HidlStatus"
#include <android-base/logging.h>
#include <hidl/Status.h>
#include <unordered_map>
namespace android {
namespace hardware {
static std::string statusToString(status_t s) {
const std::unordered_map<status_t, std::string> statusStrings{{
#define STATUS_TO_STRING_PAIR(STATUS) {STATUS, #STATUS}
STATUS_TO_STRING_PAIR(OK),
STATUS_TO_STRING_PAIR(UNKNOWN_ERROR),
STATUS_TO_STRING_PAIR(NO_MEMORY),
STATUS_TO_STRING_PAIR(INVALID_OPERATION),
STATUS_TO_STRING_PAIR(BAD_VALUE),
STATUS_TO_STRING_PAIR(BAD_TYPE),
STATUS_TO_STRING_PAIR(NAME_NOT_FOUND),
STATUS_TO_STRING_PAIR(PERMISSION_DENIED),
STATUS_TO_STRING_PAIR(NO_INIT),
STATUS_TO_STRING_PAIR(ALREADY_EXISTS),
STATUS_TO_STRING_PAIR(DEAD_OBJECT),
STATUS_TO_STRING_PAIR(FAILED_TRANSACTION),
STATUS_TO_STRING_PAIR(BAD_INDEX),
STATUS_TO_STRING_PAIR(NOT_ENOUGH_DATA),
STATUS_TO_STRING_PAIR(WOULD_BLOCK),
STATUS_TO_STRING_PAIR(TIMED_OUT),
STATUS_TO_STRING_PAIR(UNKNOWN_TRANSACTION),
STATUS_TO_STRING_PAIR(FDS_NOT_ALLOWED),
STATUS_TO_STRING_PAIR(UNEXPECTED_NULL)
}};
auto it = statusStrings.find(s);
if (it != statusStrings.end()) {
return it->second;
}
std::string str = std::to_string(s);
char *err = strerror(-s);
if (err != NULL) {
str.append(1, ' ').append(err);
}
return str;
}
static std::string exceptionToString(int32_t ex) {
const std::unordered_map<int32_t, std::string> exceptionStrings{{
#define EXCEPTION_TO_STRING_PAIR(EXCEPTION) {Status::Exception::EXCEPTION, #EXCEPTION}
EXCEPTION_TO_STRING_PAIR(EX_NONE),
EXCEPTION_TO_STRING_PAIR(EX_SECURITY),
EXCEPTION_TO_STRING_PAIR(EX_BAD_PARCELABLE),
EXCEPTION_TO_STRING_PAIR(EX_ILLEGAL_ARGUMENT),
EXCEPTION_TO_STRING_PAIR(EX_NULL_POINTER),
EXCEPTION_TO_STRING_PAIR(EX_ILLEGAL_STATE),
EXCEPTION_TO_STRING_PAIR(EX_NETWORK_MAIN_THREAD),
EXCEPTION_TO_STRING_PAIR(EX_UNSUPPORTED_OPERATION),
EXCEPTION_TO_STRING_PAIR(EX_HAS_REPLY_HEADER),
EXCEPTION_TO_STRING_PAIR(EX_TRANSACTION_FAILED)
}};
auto it = exceptionStrings.find(ex);
return it == exceptionStrings.end() ? std::to_string(ex) : it->second;
}
Status Status::ok() {
return Status();
}
Status Status::fromExceptionCode(int32_t exceptionCode) {
return Status(exceptionCode, OK);
}
Status Status::fromExceptionCode(int32_t exceptionCode,
const char *message) {
return Status(exceptionCode, OK, message);
}
Status Status::fromStatusT(status_t status) {
Status ret;
ret.setFromStatusT(status);
return ret;
}
Status::Status(int32_t exceptionCode, int32_t errorCode)
: mException(exceptionCode),
mErrorCode(errorCode) {}
Status::Status(int32_t exceptionCode, int32_t errorCode, const char *message)
: mException(exceptionCode),
mErrorCode(errorCode),
mMessage(message) {}
void Status::setException(int32_t ex, const char *message) {
mException = ex;
mErrorCode = NO_ERROR; // an exception, not a transaction failure.
mMessage = message;
}
void Status::setFromStatusT(status_t status) {
mException = (status == NO_ERROR) ? EX_NONE : EX_TRANSACTION_FAILED;
mErrorCode = status;
mMessage.clear();
}
std::string Status::description() const {
std::ostringstream oss;
oss << (*this);
return oss.str();
}
std::ostream& operator<< (std::ostream& stream, const Status& s) {
if (s.exceptionCode() == Status::EX_NONE) {
stream << "No error";
} else {
stream << "Status(" << exceptionToString(s.exceptionCode()) << "): '";
if (s.exceptionCode() == Status::EX_TRANSACTION_FAILED) {
stream << statusToString(s.transactionError()) << ": ";
}
stream << s.exceptionMessage() << "'";
}
return stream;
}
namespace details {
void return_status::assertOk() const {
if (!isOk()) {
LOG(FATAL) << "Attempted to retrieve value from failed HIDL call: " << description();
}
}
return_status::~return_status() {
// mCheckedStatus must be checked before isOk since isOk modifies mCheckedStatus
if (!mCheckedStatus && !isOk()) {
LOG(FATAL) << "Failed HIDL return status not checked: " << description();
}
}
return_status &return_status::operator=(return_status &&other) {
if (!mCheckedStatus && !isOk()) {
LOG(FATAL) << "Failed HIDL return status not checked: " << description();
}
std::swap(mStatus, other.mStatus);
std::swap(mCheckedStatus, other.mCheckedStatus);
return *this;
}
} // namespace details
} // namespace hardware
} // namespace android

View file

@ -0,0 +1,53 @@
/*
* 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.
*/
#include <hidl/TaskRunner.h>
#include <thread>
namespace android {
namespace hardware {
namespace details {
TaskRunner::TaskRunner() {
}
void TaskRunner::start(size_t limit) {
mQueue = std::make_shared<SynchronizedQueue<Task>>(limit);
// Allow the thread to continue running in background;
// TaskRunner do not care about the std::thread object.
std::thread{[q = mQueue] {
Task nextTask;
while (!!(nextTask = q->wait_pop())) {
nextTask();
}
}}.detach();
}
TaskRunner::~TaskRunner() {
if (mQueue) {
mQueue->push(nullptr);
}
}
bool TaskRunner::push(const Task &t) {
return (mQueue != nullptr) && (!!t) && this->mQueue->push(t);
}
} // namespace details
} // namespace hardware
} // namespace android

View file

@ -0,0 +1,191 @@
/*
* 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_INTERNAL_H
#define ANDROID_HIDL_INTERNAL_H
#include <cstdint>
#include <dirent.h>
#include <functional>
#include <string>
#include <vector>
#include <utility>
namespace android {
namespace hardware {
namespace details {
//Templated classes can use the below method
//to avoid creating dependencies on liblog.
void logAlwaysFatal(const char *message);
// HIDL client/server code should *NOT* use this class.
//
// hidl_pointer wraps a pointer without taking ownership,
// and stores it in a union with a uint64_t. This ensures
// that we always have enough space to store a pointer,
// regardless of whether we're running in a 32-bit or 64-bit
// process.
template<typename T>
struct hidl_pointer {
hidl_pointer()
: _pad(0) {
}
hidl_pointer(T* ptr) : hidl_pointer() { mPointer = ptr; }
hidl_pointer(const hidl_pointer<T>& other) : hidl_pointer() { mPointer = other.mPointer; }
hidl_pointer(hidl_pointer<T>&& other) : hidl_pointer() { *this = std::move(other); }
hidl_pointer &operator=(const hidl_pointer<T>& other) {
mPointer = other.mPointer;
return *this;
}
hidl_pointer &operator=(hidl_pointer<T>&& other) {
mPointer = other.mPointer;
other.mPointer = nullptr;
return *this;
}
hidl_pointer &operator=(T* ptr) {
mPointer = ptr;
return *this;
}
operator T*() const {
return mPointer;
}
explicit operator void*() const { // requires explicit cast to avoid ambiguity
return mPointer;
}
T& operator*() const {
return *mPointer;
}
T* operator->() const {
return mPointer;
}
T &operator[](size_t index) {
return mPointer[index];
}
const T &operator[](size_t index) const {
return mPointer[index];
}
private:
union {
T* mPointer;
uint64_t _pad;
};
};
#define HAL_LIBRARY_PATH_SYSTEM_64BIT "/system/lib64/hw/"
#define HAL_LIBRARY_PATH_VNDK_SP_64BIT "/system/lib64/vndk-sp/hw/"
#define HAL_LIBRARY_PATH_VENDOR_64BIT "/vendor/lib64/hw/"
#define HAL_LIBRARY_PATH_ODM_64BIT "/odm/lib64/hw/"
#define HAL_LIBRARY_PATH_SYSTEM_32BIT "/system/lib/hw/"
#define HAL_LIBRARY_PATH_VNDK_SP_32BIT "/system/lib/vndk-sp/hw/"
#define HAL_LIBRARY_PATH_VENDOR_32BIT "/vendor/lib/hw/"
#define HAL_LIBRARY_PATH_ODM_32BIT "/odm/lib/hw/"
#if defined(__LP64__)
#define HAL_LIBRARY_PATH_SYSTEM HAL_LIBRARY_PATH_SYSTEM_64BIT
#define HAL_LIBRARY_PATH_VNDK_SP HAL_LIBRARY_PATH_VNDK_SP_64BIT
#define HAL_LIBRARY_PATH_VENDOR HAL_LIBRARY_PATH_VENDOR_64BIT
#define HAL_LIBRARY_PATH_ODM HAL_LIBRARY_PATH_ODM_64BIT
#else
#define HAL_LIBRARY_PATH_SYSTEM HAL_LIBRARY_PATH_SYSTEM_32BIT
#define HAL_LIBRARY_PATH_VNDK_SP HAL_LIBRARY_PATH_VNDK_SP_32BIT
#define HAL_LIBRARY_PATH_VENDOR HAL_LIBRARY_PATH_VENDOR_32BIT
#define HAL_LIBRARY_PATH_ODM HAL_LIBRARY_PATH_ODM_32BIT
#endif
// ----------------------------------------------------------------------
// Class that provides Hidl instrumentation utilities.
struct HidlInstrumentor {
// Event that triggers the instrumentation. e.g. enter of an API call on
// the server/client side, exit of an API call on the server/client side
// etc.
enum InstrumentationEvent {
SERVER_API_ENTRY = 0,
SERVER_API_EXIT,
CLIENT_API_ENTRY,
CLIENT_API_EXIT,
SYNC_CALLBACK_ENTRY,
SYNC_CALLBACK_EXIT,
ASYNC_CALLBACK_ENTRY,
ASYNC_CALLBACK_EXIT,
PASSTHROUGH_ENTRY,
PASSTHROUGH_EXIT,
};
// Signature of the instrumentation callback function.
using InstrumentationCallback = std::function<void(
const InstrumentationEvent event,
const char *package,
const char *version,
const char *interface,
const char *method,
std::vector<void *> *args)>;
explicit HidlInstrumentor(
const std::string &package,
const std::string &insterface);
virtual ~HidlInstrumentor();
public:
const std::vector<InstrumentationCallback>& getInstrumentationCallbacks() {
return mInstrumentationCallbacks;
}
bool isInstrumentationEnabled() { return mEnableInstrumentation; }
protected:
// Set mEnableInstrumentation based on system property
// hal.instrumentation.enable, register/de-register instrumentation
// callbacks if mEnableInstrumentation is true/false.
void configureInstrumentation(bool log=true);
// Function that lookup and dynamically loads the hidl instrumentation
// libraries and registers the instrumentation callback functions.
//
// The instrumentation libraries should be stored under any of the following
// directories: HAL_LIBRARY_PATH_SYSTEM, HAL_LIBRARY_PATH_VNDK_SP,
// HAL_LIBRARY_PATH_VENDOR and HAL_LIBRARY_PATH_ODM.
// The name of instrumentation libraries should follow pattern:
// ^profilerPrefix(.*).profiler.so$
//
// Each instrumentation library is expected to implement the instrumentation
// function called HIDL_INSTRUMENTATION_FUNCTION.
//
// A no-op for user build.
void registerInstrumentationCallbacks(
std::vector<InstrumentationCallback> *instrumentationCallbacks);
// Utility function to determine whether a give file is a instrumentation
// library (i.e. the file name follow the expected pattern).
bool isInstrumentationLib(const dirent *file);
// A list of registered instrumentation callbacks.
std::vector<InstrumentationCallback> mInstrumentationCallbacks;
// Flag whether to enable instrumentation.
bool mEnableInstrumentation;
// Prefix to lookup the instrumentation libraries.
std::string mInstrumentationLibPackage;
// Used for dlsym to load the profiling method for given interface.
std::string mInterfaceName;
};
} // namespace details
} // namespace hardware
} // namespace android
#endif // ANDROID_HIDL_INTERNAL_H

View file

@ -0,0 +1,952 @@
/*
* 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

View file

@ -0,0 +1,281 @@
/*
* 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 _FMSGQ_DESCRIPTOR_H
#define _FMSGQ_DESCRIPTOR_H
#include <unistd.h>
#include <cutils/native_handle.h>
#include <hidl/HidlInternal.h>
#include <hidl/HidlSupport.h>
namespace android {
namespace hardware {
typedef uint64_t RingBufferPosition;
struct GrantorDescriptor {
uint32_t flags __attribute__ ((aligned(4)));
uint32_t fdIndex __attribute__ ((aligned(4)));
uint32_t offset __attribute__ ((aligned(4)));
uint64_t extent __attribute__ ((aligned(8)));
};
static_assert(offsetof(GrantorDescriptor, flags) == 0, "wrong offset");
static_assert(offsetof(GrantorDescriptor, fdIndex) == 4, "wrong offset");
static_assert(offsetof(GrantorDescriptor, offset) == 8, "wrong offset");
static_assert(offsetof(GrantorDescriptor, extent) == 16, "wrong offset");
static_assert(sizeof(GrantorDescriptor) == 24, "wrong size");
static_assert(__alignof(GrantorDescriptor) == 8, "wrong alignment");
enum MQFlavor : uint32_t {
/*
* kSynchronizedReadWrite represents the wait-free synchronized flavor of the
* FMQ. It is intended to be have a single reader and single writer.
* Attempts to overflow/underflow returns a failure.
*/
kSynchronizedReadWrite = 0x01,
/*
* kUnsynchronizedWrite represents the flavor of FMQ where writes always
* succeed. This flavor allows one writer and many readers. A read operation
* can detect an overwrite and reset the read counter.
*/
kUnsynchronizedWrite = 0x02
};
template <typename T, MQFlavor flavor>
struct MQDescriptor {
MQDescriptor(
const std::vector<GrantorDescriptor>& grantors,
native_handle_t* nHandle, size_t size);
MQDescriptor(size_t bufferSize, native_handle_t* nHandle,
size_t messageSize, bool configureEventFlag = false);
MQDescriptor();
~MQDescriptor();
explicit MQDescriptor(const MQDescriptor &other);
MQDescriptor &operator=(const MQDescriptor &other) = delete;
size_t getSize() const;
size_t getQuantum() const;
int32_t getFlags() const;
bool isHandleValid() const { return mHandle != nullptr; }
size_t countGrantors() const { return mGrantors.size(); }
inline const ::android::hardware::hidl_vec<GrantorDescriptor> &grantors() const {
return mGrantors;
}
inline ::android::hardware::hidl_vec<GrantorDescriptor> &grantors() {
return mGrantors;
}
inline const ::native_handle_t *handle() const {
return mHandle;
}
inline ::native_handle_t *handle() {
return mHandle;
}
static const size_t kOffsetOfGrantors;
static const size_t kOffsetOfHandle;
enum GrantorType : int { READPTRPOS = 0, WRITEPTRPOS, DATAPTRPOS, EVFLAGWORDPOS };
/*
* There should at least be GrantorDescriptors for the read counter, write
* counter and data buffer. A GrantorDescriptor for an EventFlag word is
* not required if there is no need for blocking FMQ operations.
*/
static constexpr int32_t kMinGrantorCount = DATAPTRPOS + 1;
/*
* Minimum number of GrantorDescriptors required if EventFlag support is
* needed for blocking FMQ operations.
*/
static constexpr int32_t kMinGrantorCountForEvFlagSupport = EVFLAGWORDPOS + 1;
//TODO(b/34160777) Identify a better solution that supports remoting.
static inline size_t alignToWordBoundary(size_t length) {
constexpr size_t kAlignmentSize = 64;
if (kAlignmentSize % __WORDSIZE != 0) {
details::logAlwaysFatal("Incompatible word size");
}
/*
* Check if alignment to word boundary would cause an overflow.
*/
if (length > SIZE_MAX - kAlignmentSize/8 + 1) {
details::logAlwaysFatal("Queue size too large");
}
return (length + kAlignmentSize/8 - 1) & ~(kAlignmentSize/8 - 1U);
}
static inline size_t isAlignedToWordBoundary(size_t offset) {
constexpr size_t kAlignmentSize = 64;
return (offset & (kAlignmentSize/8 - 1)) == 0;
}
private:
::android::hardware::hidl_vec<GrantorDescriptor> mGrantors;
::android::hardware::details::hidl_pointer<native_handle_t> mHandle;
uint32_t mQuantum;
uint32_t mFlags;
};
template<typename T, MQFlavor flavor>
const size_t MQDescriptor<T, flavor>::kOffsetOfGrantors = offsetof(MQDescriptor, mGrantors);
template<typename T, MQFlavor flavor>
const size_t MQDescriptor<T, flavor>::kOffsetOfHandle = offsetof(MQDescriptor, mHandle);
/*
* MQDescriptorSync will describe the wait-free synchronized
* flavor of FMQ.
*/
template<typename T>
using MQDescriptorSync = MQDescriptor<T, kSynchronizedReadWrite>;
/*
* MQDescriptorUnsync will describe the unsynchronized write
* flavor of FMQ.
*/
template<typename T>
using MQDescriptorUnsync = MQDescriptor<T, kUnsynchronizedWrite>;
template<typename T, MQFlavor flavor>
MQDescriptor<T, flavor>::MQDescriptor(
const std::vector<GrantorDescriptor>& grantors,
native_handle_t* nhandle,
size_t size)
: mHandle(nhandle),
mQuantum(size),
mFlags(flavor) {
mGrantors.resize(grantors.size());
for (size_t i = 0; i < grantors.size(); ++i) {
if (isAlignedToWordBoundary(grantors[i].offset) == false) {
details::logAlwaysFatal("Grantor offsets need to be aligned");
}
mGrantors[i] = grantors[i];
}
}
template<typename T, MQFlavor flavor>
MQDescriptor<T, flavor>::MQDescriptor(size_t bufferSize, native_handle_t *nHandle,
size_t messageSize, bool configureEventFlag)
: mHandle(nHandle), mQuantum(messageSize), mFlags(flavor) {
/*
* If configureEventFlag is true, allocate an additional spot in mGrantor
* for containing the fd and offset for mmapping the EventFlag word.
*/
mGrantors.resize(configureEventFlag? kMinGrantorCountForEvFlagSupport : kMinGrantorCount);
size_t memSize[] = {
sizeof(RingBufferPosition), /* memory to be allocated for read pointer counter */
sizeof(RingBufferPosition), /* memory to be allocated for write pointer counter */
bufferSize, /* memory to be allocated for data buffer */
sizeof(std::atomic<uint32_t>)/* memory to be allocated for EventFlag word */
};
/*
* Create a default grantor descriptor for read, write pointers and
* the data buffer. fdIndex parameter is set to 0 by default and
* the offset for each grantor is contiguous.
*/
for (size_t grantorPos = 0, offset = 0;
grantorPos < mGrantors.size();
offset += memSize[grantorPos++]) {
mGrantors[grantorPos] = {
0 /* grantor flags */,
0 /* fdIndex */,
static_cast<uint32_t>(alignToWordBoundary(offset)),
memSize[grantorPos]
};
}
}
template<typename T, MQFlavor flavor>
MQDescriptor<T, flavor>::MQDescriptor(const MQDescriptor<T, flavor> &other)
: mGrantors(other.mGrantors),
mHandle(nullptr),
mQuantum(other.mQuantum),
mFlags(other.mFlags) {
if (other.mHandle != nullptr) {
mHandle = native_handle_create(
other.mHandle->numFds, other.mHandle->numInts);
for (int i = 0; i < other.mHandle->numFds; ++i) {
mHandle->data[i] = dup(other.mHandle->data[i]);
}
memcpy(&mHandle->data[other.mHandle->numFds],
&other.mHandle->data[other.mHandle->numFds],
other.mHandle->numInts * sizeof(int));
}
}
template<typename T, MQFlavor flavor>
MQDescriptor<T, flavor>::MQDescriptor() : MQDescriptor(
std::vector<android::hardware::GrantorDescriptor>(),
nullptr /* nHandle */,
0 /* size */) {}
template<typename T, MQFlavor flavor>
MQDescriptor<T, flavor>::~MQDescriptor() {
if (mHandle != nullptr) {
native_handle_close(mHandle);
native_handle_delete(mHandle);
}
}
template<typename T, MQFlavor flavor>
size_t MQDescriptor<T, flavor>::getSize() const {
return mGrantors[DATAPTRPOS].extent;
}
template<typename T, MQFlavor flavor>
size_t MQDescriptor<T, flavor>::getQuantum() const { return mQuantum; }
template<typename T, MQFlavor flavor>
int32_t MQDescriptor<T, flavor>::getFlags() const { return mFlags; }
template<typename T, MQFlavor flavor>
std::string toString(const MQDescriptor<T, flavor> &q) {
std::string os;
if (flavor & kSynchronizedReadWrite) {
os += "fmq_sync";
}
if (flavor & kUnsynchronizedWrite) {
os += "fmq_unsync";
}
os += " {"
+ toString(q.grantors().size()) + " grantor(s), "
+ "size = " + toString(q.getSize())
+ ", .handle = " + toString(q.handle())
+ ", .quantum = " + toString(q.getQuantum()) + "}";
return os;
}
} // namespace hardware
} // namespace android
#endif // FMSGQ_DESCRIPTOR_H

View file

@ -0,0 +1,273 @@
/*
* 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.
*/
#ifndef ANDROID_HARDWARE_BINDER_STATUS_H
#define ANDROID_HARDWARE_BINDER_STATUS_H
#include <cstdint>
#include <sstream>
#include <hidl/HidlInternal.h>
#include <utils/Errors.h>
#include <utils/StrongPointer.h>
namespace android {
namespace hardware {
// An object similar in function to a status_t except that it understands
// how exceptions are encoded in the prefix of a Parcel. Used like:
//
// Parcel data;
// Parcel reply;
// status_t status;
// binder::Status remote_exception;
// if ((status = data.writeInterfaceToken(interface_descriptor)) != OK ||
// (status = data.writeInt32(function_input)) != OK) {
// // We failed to write into the memory of our local parcel?
// }
// if ((status = remote()->transact(transaction, data, &reply)) != OK) {
// // Something has gone wrong in the binder driver or libbinder.
// }
// if ((status = remote_exception.readFromParcel(reply)) != OK) {
// // The remote didn't correctly write the exception header to the
// // reply.
// }
// if (!remote_exception.isOk()) {
// // The transaction went through correctly, but the remote reported an
// // exception during handling.
// }
//
class Status final {
public:
// Keep the exception codes in sync with android/os/Parcel.java.
enum Exception {
EX_NONE = 0,
EX_SECURITY = -1,
EX_BAD_PARCELABLE = -2,
EX_ILLEGAL_ARGUMENT = -3,
EX_NULL_POINTER = -4,
EX_ILLEGAL_STATE = -5,
EX_NETWORK_MAIN_THREAD = -6,
EX_UNSUPPORTED_OPERATION = -7,
// This is special and Java specific; see Parcel.java.
EX_HAS_REPLY_HEADER = -128,
// This is special, and indicates to C++ binder proxies that the
// transaction has failed at a low level.
EX_TRANSACTION_FAILED = -129,
};
// A more readable alias for the default constructor.
static Status ok();
// Authors should explicitly pick whether their integer is:
// - an exception code (EX_* above)
// - status_t
//
// Prefer a generic exception code when possible or a status_t
// for low level transport errors. Service specific errors
// should be at a higher level in HIDL.
static Status fromExceptionCode(int32_t exceptionCode);
static Status fromExceptionCode(int32_t exceptionCode,
const char *message);
static Status fromStatusT(status_t status);
Status() = default;
~Status() = default;
// Status objects are copyable and contain just simple data.
Status(const Status& status) = default;
Status(Status&& status) = default;
Status& operator=(const Status& status) = default;
// Set one of the pre-defined exception types defined above.
void setException(int32_t ex, const char *message);
// Setting a |status| != OK causes generated code to return |status|
// from Binder transactions, rather than writing an exception into the
// reply Parcel. This is the least preferable way of reporting errors.
void setFromStatusT(status_t status);
// Get information about an exception.
int32_t exceptionCode() const { return mException; }
const char *exceptionMessage() const { return mMessage.c_str(); }
status_t transactionError() const {
return mException == EX_TRANSACTION_FAILED ? mErrorCode : OK;
}
bool isOk() const { return mException == EX_NONE; }
// For debugging purposes only
std::string description() const;
private:
Status(int32_t exceptionCode, int32_t errorCode);
Status(int32_t exceptionCode, int32_t errorCode, const char *message);
// If |mException| == EX_TRANSACTION_FAILED, generated code will return
// |mErrorCode| as the result of the transaction rather than write an
// exception to the reply parcel.
//
// Otherwise, we always write |mException| to the parcel.
// If |mException| != EX_NONE, we write |mMessage| as well.
int32_t mException = EX_NONE;
int32_t mErrorCode = 0;
std::string mMessage;
}; // class Status
// For gtest output logging
std::ostream& operator<< (std::ostream& stream, const Status& s);
template<typename T> class Return;
namespace details {
class return_status {
private:
Status mStatus {};
mutable bool mCheckedStatus = false;
template <typename T, typename U>
friend Return<U> StatusOf(const Return<T> &other);
protected:
void assertOk() const;
public:
return_status() {}
return_status(Status s) : mStatus(s) {}
return_status(const return_status &) = delete;
return_status &operator=(const return_status &) = delete;
return_status(return_status &&other) {
*this = std::move(other);
}
return_status &operator=(return_status &&other);
~return_status();
bool isOk() const {
mCheckedStatus = true;
return mStatus.isOk();
}
// Check if underlying error is DEAD_OBJECT.
// Check mCheckedStatus only if this method returns true.
bool isDeadObject() const {
bool dead = mStatus.transactionError() == DEAD_OBJECT;
// This way, if you only check isDeadObject your process will
// only be killed for more serious unchecked errors
if (dead) {
mCheckedStatus = true;
}
return dead;
}
// For debugging purposes only
std::string description() const {
// Doesn't consider checked.
return mStatus.description();
}
};
} // namespace details
template<typename T> class Return : public details::return_status {
private:
T mVal {};
public:
Return(T v) : details::return_status(), mVal{v} {}
Return(Status s) : details::return_status(s) {}
// move-able.
// precondition: "this" has checked status
// postcondition: other is safe to destroy after moving to *this.
Return(Return &&other) = default;
Return &operator=(Return &&) = default;
~Return() = default;
operator T() const {
assertOk();
return mVal;
}
T withDefault(T t) {
return isOk() ? mVal : t;
}
};
template<typename T> class Return<sp<T>> : public details::return_status {
private:
sp<T> mVal {};
public:
Return(sp<T> v) : details::return_status(), mVal{v} {}
Return(T* v) : details::return_status(), mVal{v} {}
// Constructors matching a different type (that is related by inheritance)
template<typename U> Return(sp<U> v) : details::return_status(), mVal{v} {}
template<typename U> Return(U* v) : details::return_status(), mVal{v} {}
Return(Status s) : details::return_status(s) {}
// move-able.
// precondition: "this" has checked status
// postcondition: other is safe to destroy after moving to *this.
Return(Return &&other) = default;
Return &operator=(Return &&) = default;
~Return() = default;
operator sp<T>() const {
assertOk();
return mVal;
}
sp<T> withDefault(sp<T> t) {
return isOk() ? mVal : t;
}
};
template<> class Return<void> : public details::return_status {
public:
Return() : details::return_status() {}
Return(Status s) : details::return_status(s) {}
// move-able.
// precondition: "this" has checked status
// postcondition: other is safe to destroy after moving to *this.
Return(Return &&) = default;
Return &operator=(Return &&) = default;
~Return() = default;
};
static inline Return<void> Void() {
return Return<void>();
}
namespace details {
// Create a Return<U> from the Status of Return<T>. The provided
// Return<T> must have an error status and have it checked.
template <typename T, typename U>
Return<U> StatusOf(const Return<T> &other) {
if (other.mStatus.isOk() || !other.mCheckedStatus) {
details::logAlwaysFatal("cannot call statusOf on an OK Status or an unchecked status");
}
return Return<U>{other.mStatus};
}
} // namespace details
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_BINDER_STATUS_H

View file

@ -0,0 +1,101 @@
/*
* 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_SYNCHRONIZED_QUEUE_H
#define ANDROID_HIDL_SYNCHRONIZED_QUEUE_H
#include <condition_variable>
#include <mutex>
#include <queue>
#include <thread>
namespace android {
namespace hardware {
namespace details {
/* Threadsafe queue.
*/
template <typename T>
struct SynchronizedQueue {
SynchronizedQueue(size_t limit);
/* Gets an item from the front of the queue.
*
* Blocks until the item is available.
*/
T wait_pop();
/* Puts an item onto the end of the queue.
*/
bool push(const T& item);
/* Gets the size of the array.
*/
size_t size();
private:
std::condition_variable mCondition;
std::mutex mMutex;
std::queue<T> mQueue;
const size_t mQueueLimit;
};
template <typename T>
SynchronizedQueue<T>::SynchronizedQueue(size_t limit) : mQueueLimit(limit) {
}
template <typename T>
T SynchronizedQueue<T>::wait_pop() {
std::unique_lock<std::mutex> lock(mMutex);
mCondition.wait(lock, [this]{
return !this->mQueue.empty();
});
T item = mQueue.front();
mQueue.pop();
return item;
}
template <typename T>
bool SynchronizedQueue<T>::push(const T &item) {
bool success;
{
std::unique_lock<std::mutex> lock(mMutex);
if (mQueue.size() < mQueueLimit) {
mQueue.push(item);
success = true;
} else {
success = false;
}
}
mCondition.notify_one();
return success;
}
template <typename T>
size_t SynchronizedQueue<T>::size() {
std::unique_lock<std::mutex> lock(mMutex);
return mQueue.size();
}
} // namespace details
} // namespace hardware
} // namespace android
#endif // ANDROID_HIDL_SYNCHRONIZED_QUEUE_H

View file

@ -0,0 +1,65 @@
/*
* 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_TASK_RUNNER_H
#define ANDROID_HIDL_TASK_RUNNER_H
#include "SynchronizedQueue.h"
#include <memory>
#include <thread>
namespace android {
namespace hardware {
namespace details {
/*
* A background infinite loop that runs the Tasks push()'ed.
* Equivalent to a simple single-threaded Looper.
*/
class TaskRunner {
public:
using Task = std::function<void(void)>;
/* Create an empty task runner. Nothing will be done until start() is called. */
TaskRunner();
/*
* Notify the background thread to terminate and return immediately.
* Tasks in the queue will continue to be done sequentially in background
* until all tasks are finished.
*/
~TaskRunner();
/*
* Sets the queue limit. Fails the push operation once the limit is reached.
* Then kicks off the loop.
*/
void start(size_t limit);
/*
* Add a task. Return true if successful, false if
* the queue's size exceeds limit or t doesn't contain a callable target.
*/
bool push(const Task &t);
private:
std::shared_ptr<SynchronizedQueue<Task>> mQueue;
};
} // namespace details
} // namespace hardware
} // namespace android
#endif // ANDROID_HIDL_TASK_RUNNER_H