summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
l---------[-rw-r--r--].clang-format25
-rw-r--r--Android.bp9
-rw-r--r--TEST_MAPPING8
-rw-r--r--adapter/HidlBinderAdapter.cpp141
-rw-r--r--base/Android.bp1
-rw-r--r--base/HidlInternal.cpp19
-rw-r--r--base/HidlSupport.cpp20
-rw-r--r--base/Status.cpp31
-rw-r--r--base/include/hidl/HidlInternal.h13
-rw-r--r--base/include/hidl/HidlSupport.h96
-rw-r--r--base/include/hidl/MQDescriptor.h25
-rw-r--r--base/include/hidl/Status.h85
-rw-r--r--libhidlcache/HidlCache.h2
-rw-r--r--libhidlcache/HidlMemoryCache.cpp39
-rw-r--r--libhidlcache/MemoryDealer.cpp7
-rw-r--r--minijail/HardwareMinijail.cpp2
-rw-r--r--test_main.cpp28
-rw-r--r--transport/Android.bp12
-rw-r--r--transport/HidlBinderSupport.cpp92
-rw-r--r--transport/HidlLazyUtils.cpp190
-rw-r--r--transport/HidlPassthroughSupport.cpp5
-rw-r--r--transport/HidlTransportSupport.cpp68
-rw-r--r--transport/HidlTransportUtils.cpp4
-rw-r--r--transport/InternalStatic.h40
-rw-r--r--transport/ServiceManagement.cpp256
-rw-r--r--transport/Static.cpp21
-rw-r--r--transport/allocator/1.0/default/Android.bp1
-rw-r--r--transport/allocator/1.0/default/AshmemAllocator.cpp4
-rw-r--r--transport/allocator/1.0/default/android.hidl.allocator@1.0-service.xml11
-rw-r--r--transport/allocator/1.0/utils/Android.bp1
-rw-r--r--transport/allocator/1.0/vts/functional/Android.bp28
-rw-r--r--transport/allocator/1.0/vts/functional/Android.mk22
-rw-r--r--transport/allocator/1.0/vts/functional/AndroidTest.xml32
-rw-r--r--transport/allocator/1.0/vts/functional/VtsHidlAllocatorV1_0TargetTest.cpp139
-rw-r--r--transport/base/1.0/Android.bp4
-rw-r--r--transport/base/1.0/IBase.hal5
-rw-r--r--transport/current.txt9
-rw-r--r--transport/include/hidl/ConcurrentMap.h17
-rw-r--r--transport/include/hidl/HidlBinderSupport.h57
-rw-r--r--transport/include/hidl/HidlLazyUtils.h41
-rw-r--r--transport/include/hidl/HidlTransportSupport.h24
-rw-r--r--transport/include/hidl/LegacySupport.h92
-rw-r--r--transport/include/hidl/ServiceManagement.h28
-rw-r--r--transport/include/hidl/Static.h22
-rw-r--r--transport/manager/1.0/Android.bp1
-rw-r--r--transport/manager/1.0/IServiceManager.hal2
-rw-r--r--transport/manager/1.1/Android.bp1
-rw-r--r--transport/manager/1.2/Android.bp20
-rw-r--r--transport/manager/1.2/IClientCallback.hal36
-rw-r--r--transport/manager/1.2/IServiceManager.hal105
-rw-r--r--transport/safe_union/1.0/Android.bp15
-rw-r--r--transport/safe_union/1.0/types.hal29
-rw-r--r--transport/token/1.0/utils/Android.bp7
-rw-r--r--transport/token/1.0/utils/include/hidl/HybridInterface.h488
-rwxr-xr-xupdate-makefiles.sh2
-rw-r--r--vintfdata/Android.mk46
-rw-r--r--vintfdata/manifest.xml32
-rw-r--r--vintfdata/manifest_healthd_exclude.xml15
58 files changed, 1971 insertions, 604 deletions
diff --git a/.clang-format b/.clang-format
index 9b3f9d9..ddcf5a2 100644..120000
--- a/.clang-format
+++ b/.clang-format
@@ -1,24 +1 @@
-#
-# Copyright (C) 2017 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.
-#
-
-BasedOnStyle: Google
-CommentPragmas: NOLINT:.*
-DerivePointerAlignment: false
-AllowShortFunctionsOnASingleLine: Inline
-ColumnLimit: 100
-TabWidth: 4
-UseTab: Never
-IndentWidth: 4
+../../build/soong/scripts/system-clang-format \ No newline at end of file
diff --git a/Android.bp b/Android.bp
index 032a61a..97ed108 100644
--- a/Android.bp
+++ b/Android.bp
@@ -16,7 +16,9 @@ cc_defaults {
name: "libhidl-defaults",
cflags: [
"-Wall",
+ "-Wdocumentation", // since some users use this
"-Werror",
+ "-Wextra-semi",
],
}
@@ -25,9 +27,10 @@ cc_test {
defaults: ["libhidl-defaults"],
gtest: false,
srcs: ["test_main.cpp"],
+ test_suites: ["device-tests"],
shared_libs: [
- "android.hardware.tests.inheritance@1.0",
+ "android.hidl.memory@1.0",
"libbase",
"libhidlbase",
"libhidltransport",
@@ -38,10 +41,6 @@ cc_test {
],
static_libs: ["libgtest", "libgmock"],
- required: [
- "android.hardware.tests.inheritance@1.0-impl",
- ],
-
cflags: [
"-O0",
"-g",
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..3e17fc4
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,8 @@
+{
+ "presubmit": [
+ {
+ "name": "libhidl_test"
+ }
+ ]
+}
+
diff --git a/adapter/HidlBinderAdapter.cpp b/adapter/HidlBinderAdapter.cpp
index b6aa58e..ed6dad1 100644
--- a/adapter/HidlBinderAdapter.cpp
+++ b/adapter/HidlBinderAdapter.cpp
@@ -36,42 +36,92 @@ using android::base::WaitForProperty;
const static std::string kDeactivateProp = "test.hidl.adapters.deactivated";
-void usage(const std::string& me) {
- std::cerr << "usage: " << me << " [-p] interface-name instance-name number-of-threads."
+int usage(const std::string& me) {
+ std::cerr << "usage: " << me
+ << " [-p|P] [-n instance-name] interface-name instance-name number-of-threads."
<< std::endl;
std::cerr << " -p: stop based on property " << kDeactivateProp << "and reset it."
<< std::endl;
+ std::cerr << " -P: stop based on interface specific property " << kDeactivateProp
+ << ".<fq-name>.<instance-name>" << std::endl;
+ std::cerr
+ << " -n instance-name: register as a different instance name (does not de-register)"
+ << std::endl;
+ return EINVAL;
}
-bool processArguments(int* argc, char*** argv, bool* propertyStop) {
+enum class StopMethod {
+ NONE,
+ ALL,
+ SPECIFIC,
+};
+
+struct Args {
+ StopMethod stopMethod = StopMethod::NONE;
+ std::string interface; // e.x. IFoo
+ std::string instanceName; // e.x. default
+ int threadNumber;
+ std::string registerInstanceName; // e.x. default
+};
+
+bool processArguments(int argc, char** argv, Args* args) {
int c;
- while ((c = getopt(*argc, *argv, "p")) != -1) {
+ while ((c = getopt(argc, argv, "pPn:")) != -1) {
switch (c) {
case 'p': {
- *propertyStop = true;
+ args->stopMethod = StopMethod::ALL;
+ break;
+ }
+ case 'P': {
+ args->stopMethod = StopMethod::SPECIFIC;
+ break;
+ }
+ case 'n': {
+ args->registerInstanceName = optarg;
break;
}
default: { return false; }
}
}
- *argc -= optind;
- *argv += optind;
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 3) {
+ std::cerr << "ERROR: requires exactly three positional arguments for "
+ "interface, instance name, and number of threads, but "
+ << argc << " provided." << std::endl;
+ return false;
+ }
+
+ args->interface = argv[0];
+ args->instanceName = argv[1];
+ args->threadNumber = std::stoi(argv[2]);
+
+ if (args->threadNumber <= 0) {
+ std::cerr << "ERROR: invalid thread number " << args->threadNumber
+ << " must be a positive integer." << std::endl;
+ return false;
+ }
+
+ if (args->registerInstanceName.empty()) {
+ args->registerInstanceName = args->instanceName;
+ }
+
return true;
}
// only applies for -p argument
-void waitForAdaptersDeactivated() {
+void waitForAdaptersDeactivated(const std::string& property) {
using std::literals::chrono_literals::operator""s;
- while (!WaitForProperty(kDeactivateProp, "true", 30s)) {
+ while (!WaitForProperty(property, "true", 30s)) {
// Log this so that when using this option on testing devices, there is
// a clear indication if adapters are not properly stopped
- LOG(WARNING) << "Adapter use in progress. Waiting for stop based on 'true' "
- << kDeactivateProp;
+ LOG(WARNING) << "Adapter use in progress. Waiting for stop based on 'true' " << property;
}
- SetProperty(kDeactivateProp, "false");
+ SetProperty(property, "false");
}
int adapterMain(const std::string& package, int argc, char** argv,
@@ -82,25 +132,12 @@ int adapterMain(const std::string& package, int argc, char** argv,
const std::string& me = argc > 0 ? argv[0] : "(error)";
- bool propertyStop = false;
- if (!processArguments(&argc, &argv, &propertyStop)) {
- usage(me);
- return EINVAL;
- }
-
- if (argc != 3) {
- usage(me);
- return EINVAL;
+ Args args;
+ if (!processArguments(argc, argv, &args)) {
+ return usage(me);
}
- std::string interfaceName = package + "::" + argv[0];
- std::string instanceName = argv[1];
- int threadNumber = std::stoi(argv[2]);
-
- if (threadNumber <= 0) {
- std::cerr << "ERROR: invalid thread number " << threadNumber
- << " must be a positive integer.";
- }
+ std::string interfaceName = package + "::" + args.interface;
auto it = adapters.find(interfaceName);
if (it == adapters.end()) {
@@ -108,9 +145,10 @@ int adapterMain(const std::string& package, int argc, char** argv,
return 1;
}
- std::cout << "Trying to adapt down " << interfaceName << "/" << instanceName << std::endl;
+ std::cout << "Trying to adapt down " << interfaceName << "/" << args.instanceName << " to "
+ << args.registerInstanceName << std::endl;
- configureRpcThreadpool(threadNumber, false /* callerWillJoin */);
+ configureRpcThreadpool(args.threadNumber, false /* callerWillJoin */);
sp<IServiceManager> manager = IServiceManager::getService();
if (manager == nullptr) {
@@ -118,7 +156,7 @@ int adapterMain(const std::string& package, int argc, char** argv,
return 1;
}
- sp<IBase> implementation = manager->get(interfaceName, instanceName).withDefault(nullptr);
+ sp<IBase> implementation = manager->get(interfaceName, args.instanceName).withDefault(nullptr);
if (implementation == nullptr) {
std::cerr << "ERROR: could not retrieve desired implementation" << std::endl;
return 1;
@@ -130,25 +168,40 @@ int adapterMain(const std::string& package, int argc, char** argv,
return 1;
}
- bool replaced = manager->add(instanceName, adapter).withDefault(false);
+ bool replaced = manager->add(args.registerInstanceName, adapter).withDefault(false);
if (!replaced) {
std::cerr << "ERROR: could not register the service with the service manager." << std::endl;
return 1;
}
- if (propertyStop) {
- std::cout << "Set " << kDeactivateProp << " to true to deactivate." << std::endl;
- waitForAdaptersDeactivated();
- } else {
- std::cout << "Press any key to disassociate adapter." << std::endl;
- getchar();
+ switch (args.stopMethod) {
+ case StopMethod::NONE: {
+ std::cout << "Press any key to disassociate adapter." << std::endl;
+ getchar();
+ break;
+ };
+ case StopMethod::SPECIFIC: {
+ const std::string property =
+ kDeactivateProp + "." + interfaceName + "." + args.registerInstanceName;
+ std::cout << "Set " << property << " to true to deactivate." << std::endl;
+ waitForAdaptersDeactivated(property);
+ break;
+ };
+ case StopMethod::ALL: {
+ std::cout << "Set " << kDeactivateProp << " to true to deactivate." << std::endl;
+ waitForAdaptersDeactivated(kDeactivateProp);
+ break;
+ };
}
- bool restored = manager->add(instanceName, implementation).withDefault(false);
- if (!restored) {
- std::cerr << "ERROR: could not re-register interface with the service manager."
- << std::endl;
- return 1;
+ // automatically unregistered on process exit if it is a new instance name
+ if (args.registerInstanceName == args.instanceName) {
+ bool restored = manager->add(args.instanceName, implementation).withDefault(false);
+ if (!restored) {
+ std::cerr << "ERROR: could not re-register interface with the service manager."
+ << std::endl;
+ return 1;
+ }
}
std::cout << "Success." << std::endl;
diff --git a/base/Android.bp b/base/Android.bp
index 22f5ee1..359ac91 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -14,6 +14,7 @@
cc_library {
name: "libhidlbase",
+ recovery_available: true,
vendor_available: true,
vndk: {
enabled: true,
diff --git a/base/HidlInternal.cpp b/base/HidlInternal.cpp
index babdac1..440b30f 100644
--- a/base/HidlInternal.cpp
+++ b/base/HidlInternal.cpp
@@ -31,16 +31,17 @@
#include <regex>
extern "C" __attribute__((weak)) void __sanitizer_cov_dump();
-const char* kGcovPrefixEnvVar = "GCOV_PREFIX";
-const char* kGcovPrefixOverrideEnvVar = "GCOV_PREFIX_OVERRIDE";
-const char* kGcovPrefixPath = "/data/misc/trace/";
-const char* kSysPropHalCoverage = "hal.coverage.enable";
+
+const char kGcovPrefixEnvVar[] = "GCOV_PREFIX";
+const char kGcovPrefixOverrideEnvVar[] = "GCOV_PREFIX_OVERRIDE";
+const char kGcovPrefixPath[] = "/data/misc/trace/";
+const char kSysPropHalCoverage[] = "hal.coverage.enable";
#if defined(__LP64__)
-const char* kSysPropInstrumentationPath = "hal.instrumentation.lib.path.64";
+const char kSysPropInstrumentationPath[] = "hal.instrumentation.lib.path.64";
#else
-const char* kSysPropInstrumentationPath = "hal.instrumentation.lib.path.32";
-#endif
+const char kSysPropInstrumentationPath[] = "hal.instrumentation.lib.path.32";
#endif
+#endif // LIBHIDL_TARGET_DEBUGGABLE
namespace android {
namespace hardware {
@@ -145,7 +146,9 @@ void HidlInstrumentor::registerInstrumentationCallbacks(
} else {
static std::string halLibPathVndkSp = android::base::StringPrintf(
HAL_LIBRARY_PATH_VNDK_SP_FOR_VERSION, getVndkVersionStr().c_str());
+#ifndef __ANDROID_VNDK__
instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_SYSTEM);
+#endif
instrumentationLibPaths.push_back(halLibPathVndkSp);
instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_VENDOR);
instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_ODM);
@@ -153,7 +156,7 @@ void HidlInstrumentor::registerInstrumentationCallbacks(
for (const auto& path : instrumentationLibPaths) {
DIR *dir = opendir(path.c_str());
- if (dir == 0) {
+ if (dir == nullptr) {
LOG(WARNING) << path << " does not exist. ";
return;
}
diff --git a/base/HidlSupport.cpp b/base/HidlSupport.cpp
index e08bf93..f97f216 100644
--- a/base/HidlSupport.cpp
+++ b/base/HidlSupport.cpp
@@ -57,7 +57,7 @@ hidl_handle::hidl_handle(const hidl_handle& other) : hidl_handle() {
}
// move constructor.
-hidl_handle::hidl_handle(hidl_handle&& other) : hidl_handle() {
+hidl_handle::hidl_handle(hidl_handle&& other) noexcept : hidl_handle() {
mOwnsHandle = false;
*this = std::move(other);
}
@@ -88,7 +88,7 @@ hidl_handle &hidl_handle::operator=(const native_handle_t *native_handle) {
return *this;
}
-hidl_handle &hidl_handle::operator=(hidl_handle &&other) {
+hidl_handle& hidl_handle::operator=(hidl_handle&& other) noexcept {
if (this != &other) {
freeHandle();
mHandle = other.mHandle;
@@ -169,11 +169,11 @@ 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() {
+hidl_string::hidl_string(hidl_string&& other) noexcept : hidl_string() {
moveFrom(std::forward<hidl_string>(other));
}
-hidl_string &hidl_string::operator=(hidl_string &&other) {
+hidl_string& hidl_string::operator=(hidl_string&& other) noexcept {
if (this != &other) {
clear();
moveFrom(std::forward<hidl_string>(other));
@@ -256,6 +256,14 @@ 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;
}
+
+ // When the binder driver copies this data into its buffer, it must
+ // have a zero byte there because the remote process will have a pointer
+ // directly into the read-only binder buffer. If we manually copy the
+ // data now to add a zero, then we lose the efficiency of this method.
+ // Checking here (it's also checked in the parceling code later).
+ CHECK(data[size] == '\0');
+
clear();
mBuffer = data;
@@ -309,9 +317,7 @@ HidlMemory::HidlMemory(const hidl_string& name, hidl_handle&& handle, size_t siz
: hidl_memory(name, std::move(handle), size) {}
// it's required to have at least one out-of-line method to avoid weak vtable
-HidlMemory::~HidlMemory() {
- hidl_memory::~hidl_memory();
-}
+HidlMemory::~HidlMemory() {}
} // namespace hardware
} // namespace android
diff --git a/base/Status.cpp b/base/Status.cpp
index 1ba91c3..90474a0 100644
--- a/base/Status.cpp
+++ b/base/Status.cpp
@@ -18,6 +18,7 @@
#include <android-base/logging.h>
#include <hidl/Status.h>
+#include <utils/CallStack.h>
#include <unordered_map>
@@ -82,11 +83,17 @@ Status Status::ok() {
}
Status Status::fromExceptionCode(int32_t exceptionCode) {
+ if (exceptionCode == EX_TRANSACTION_FAILED) {
+ return Status(exceptionCode, FAILED_TRANSACTION);
+ }
return Status(exceptionCode, OK);
}
Status Status::fromExceptionCode(int32_t exceptionCode,
const char *message) {
+ if (exceptionCode == EX_TRANSACTION_FAILED) {
+ return Status(exceptionCode, FAILED_TRANSACTION, message);
+ }
return Status(exceptionCode, OK, message);
}
@@ -107,7 +114,7 @@ Status::Status(int32_t exceptionCode, int32_t errorCode, const char *message)
void Status::setException(int32_t ex, const char *message) {
mException = ex;
- mErrorCode = NO_ERROR; // an exception, not a transaction failure.
+ mErrorCode = ex == EX_TRANSACTION_FAILED ? FAILED_TRANSACTION : NO_ERROR;
mMessage = message;
}
@@ -136,6 +143,11 @@ std::ostream& operator<< (std::ostream& stream, const Status& s) {
return stream;
}
+static HidlReturnRestriction gReturnRestriction = HidlReturnRestriction::NONE;
+void setProcessHidlReturnRestriction(HidlReturnRestriction restriction) {
+ gReturnRestriction = restriction;
+}
+
namespace details {
void return_status::assertOk() const {
if (!isOk()) {
@@ -145,12 +157,25 @@ namespace details {
return_status::~return_status() {
// mCheckedStatus must be checked before isOk since isOk modifies mCheckedStatus
- if (!mCheckedStatus && !isOk()) {
+ if (mCheckedStatus) return;
+
+ if (!isOk()) {
LOG(FATAL) << "Failed HIDL return status not checked: " << description();
}
+
+ if (gReturnRestriction == HidlReturnRestriction::NONE) {
+ return;
+ }
+
+ if (gReturnRestriction == HidlReturnRestriction::ERROR_IF_UNCHECKED) {
+ LOG(ERROR) << "Failed to check status of HIDL Return.";
+ CallStack::logStack("unchecked HIDL return", CallStack::getCurrent(10).get(), ANDROID_LOG_ERROR);
+ } else {
+ LOG(FATAL) << "Failed to check status of HIDL Return.";
+ }
}
- return_status &return_status::operator=(return_status &&other) {
+ return_status& return_status::operator=(return_status&& other) noexcept {
if (!mCheckedStatus && !isOk()) {
LOG(FATAL) << "Failed HIDL return status not checked: " << description();
}
diff --git a/base/include/hidl/HidlInternal.h b/base/include/hidl/HidlInternal.h
index ed9f02c..0b80cd4 100644
--- a/base/include/hidl/HidlInternal.h
+++ b/base/include/hidl/HidlInternal.h
@@ -48,6 +48,15 @@ void logAlwaysFatal(const char *message);
// If "ro.vndk.version" is not set or set to "current", it returns empty string.
std::string getVndkVersionStr();
+// Explicitly invokes the parameterized element's destructor;
+// intended to be used alongside the placement new operator.
+template<typename T>
+void destructElement(T* element) {
+ if (element != nullptr) {
+ element->~T();
+ }
+}
+
// HIDL client/server code should *NOT* use this class.
//
// hidl_pointer wraps a pointer without taking ownership,
@@ -63,13 +72,13 @@ struct hidl_pointer {
}
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(hidl_pointer<T>&& other) noexcept : 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) {
+ hidl_pointer& operator=(hidl_pointer<T>&& other) noexcept {
mPointer = other.mPointer;
other.mPointer = nullptr;
return *this;
diff --git a/base/include/hidl/HidlSupport.h b/base/include/hidl/HidlSupport.h
index f8f79a5..93a6251 100644
--- a/base/include/hidl/HidlSupport.h
+++ b/base/include/hidl/HidlSupport.h
@@ -40,18 +40,22 @@ namespace android {
namespace hidl {
namespace memory {
namespace V1_0 {
- struct IMemory;
-}; // namespace V1_0
-}; // namespace manager
-}; // namespace hidl
+
+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
+
+struct IBase;
+
+} // namespace V1_0
+} // namespace base
+} // namespace hidl
namespace hardware {
@@ -112,6 +116,10 @@ struct hidl_handle {
// 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();
@@ -155,6 +163,8 @@ struct hidl_string {
// 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.
@@ -338,19 +348,7 @@ struct hidl_vec {
*this = std::move(other);
}
- hidl_vec(const std::initializer_list<T> list) : hidl_vec() {
- 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]();
- mOwnsBuffer = true;
-
- size_t idx = 0;
- for (auto it = list.begin(); it != list.end(); ++it) {
- mBuffer[idx++] = *it;
- }
- }
+ hidl_vec(const std::initializer_list<T> list) : hidl_vec() { *this = list; }
hidl_vec(const std::vector<T> &other) : hidl_vec() {
*this = other;
@@ -447,6 +445,24 @@ struct hidl_vec {
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);
@@ -845,6 +861,10 @@ public:
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()));
@@ -989,12 +1009,38 @@ std::string toString(const hidl_array<T, SIZE1, SIZE2, SIZES...> &a) {
+ 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 generates an implementation of this function.
- * E.x.: for(const auto v : hidl_enum_iterator<Enum>) { ... }
+ * Every HIDL generated enum supports this function.
+ * E.x.: for(const auto v : hidl_enum_range<Enum>) { ... }
*/
-template <typename>
-struct hidl_enum_iterator;
+template <typename T, typename = std::enable_if_t<std::is_enum<T>::value>>
+struct hidl_enum_range {
+ 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.
diff --git a/base/include/hidl/MQDescriptor.h b/base/include/hidl/MQDescriptor.h
index 23be971..0f61cb5 100644
--- a/base/include/hidl/MQDescriptor.h
+++ b/base/include/hidl/MQDescriptor.h
@@ -59,18 +59,20 @@ enum MQFlavor : uint32_t {
template <typename T, MQFlavor flavor>
struct MQDescriptor {
+ // Takes ownership of handle
MQDescriptor(
const std::vector<GrantorDescriptor>& grantors,
native_handle_t* nHandle, size_t size);
+ // Takes ownership of handle
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;
+ explicit MQDescriptor(const MQDescriptor& other) : MQDescriptor() { *this = other; }
+ MQDescriptor& operator=(const MQDescriptor& other);
size_t getSize() const;
@@ -213,12 +215,17 @@ MQDescriptor<T, flavor>::MQDescriptor(size_t bufferSize, native_handle_t *nHandl
}
}
-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) {
+template <typename T, MQFlavor flavor>
+MQDescriptor<T, flavor>& MQDescriptor<T, flavor>::operator=(const MQDescriptor& other) {
+ mGrantors = other.mGrantors;
+ if (mHandle != nullptr) {
+ native_handle_close(mHandle);
+ native_handle_delete(mHandle);
+ mHandle = nullptr;
+ }
+ mQuantum = other.mQuantum;
+ mFlags = other.mFlags;
+
if (other.mHandle != nullptr) {
mHandle = native_handle_create(
other.mHandle->numFds, other.mHandle->numInts);
@@ -231,6 +238,8 @@ MQDescriptor<T, flavor>::MQDescriptor(const MQDescriptor<T, flavor> &other)
&other.mHandle->data[other.mHandle->numFds],
other.mHandle->numInts * sizeof(int));
}
+
+ return *this;
}
template<typename T, MQFlavor flavor>
diff --git a/base/include/hidl/Status.h b/base/include/hidl/Status.h
index 1a2ef6d..817277f 100644
--- a/base/include/hidl/Status.h
+++ b/base/include/hidl/Status.h
@@ -27,32 +27,36 @@
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:
+// HIDL formally separates transport error codes from interface error codes. When developing a HIDL
+// interface, errors relevant to a service should be placed in the interface design for that HAL.
//
-// 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.
-// }
+// For instance:
//
+// interface I* {
+// enum FooStatus { NO_FOO, NO_BAR }; // service-specific errors
+// doFoo(...) generates (FooStatus foo);
+// };
+//
+// When calling into this interface, a Return<*> (in this case Return<FooStatus> object will be
+// returned). For most clients, it's expected that they'll just get the result from this function
+// and use it directly. If there is a transport error, the process will just abort. In general,
+// transport errors are expected only in extremely rare circumstances (bug in the
+// code/cosmic radiation/etc..). Aborting allows process to restart using their normal happy path
+// code.
+//
+// For certain processes though which are critical to the functionality of the phone (e.g.
+// hwservicemanager/init), these errors must be handled. Return<*>::isOk and
+// Return<*>::isDeadObject are provided for these cases. Whenever this is done, special attention
+// should be paid to testing the unhappy paths to make sure that error handling is handled
+// properly.
+
+// Transport implementation detail. HIDL implementors, see Return below. HAL implementations should
+// return HIDL-defined errors rather than use this.
class Status final {
public:
- // Keep the exception codes in sync with android/os/Parcel.java.
+ // Note: forked from
+ // - frameworks/base/core/java/android/os/android/os/Parcel.java.
+ // - frameworks/native/libs/binder/include/binder/Status.h
enum Exception {
EX_NONE = 0,
EX_SECURITY = -1,
@@ -139,19 +143,16 @@ namespace details {
template <typename T, typename U>
friend Return<U> StatusOf(const Return<T> &other);
- protected:
- void assertOk() const;
public:
+ void assertOk() const;
return_status() {}
return_status(const 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(return_status&& other) noexcept { *this = std::move(other); }
+ return_status& operator=(return_status&& other) noexcept;
~return_status();
@@ -187,6 +188,26 @@ namespace details {
};
} // namespace details
+enum class HidlReturnRestriction {
+ // Okay to ignore checking transport errors. This would instead rely on init to reset state
+ // after an error in the underlying transport. This is the default and expected for most
+ // usecases.
+ NONE,
+ // Log when there is an unchecked error.
+ ERROR_IF_UNCHECKED,
+ // Fatal when there is an unchecked error.
+ FATAL_IF_UNCHECKED,
+};
+
+/**
+ * This should be called during process initialization (e.g. before binder threadpool is created).
+ *
+ * Note: default of HidlReturnRestriction::NONE should be good for most usecases. See above.
+ *
+ * The restriction will be applied when Return objects are deconstructed.
+ */
+void setProcessHidlReturnRestriction(HidlReturnRestriction restriction);
+
template<typename T> class Return : public details::return_status {
private:
T mVal {};
@@ -197,8 +218,8 @@ public:
// 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(Return&& other) noexcept = default;
+ Return& operator=(Return&&) noexcept = default;
~Return() = default;
@@ -226,8 +247,8 @@ public:
// 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(Return&& other) noexcept = default;
+ Return& operator=(Return&&) noexcept = default;
~Return() = default;
diff --git a/libhidlcache/HidlCache.h b/libhidlcache/HidlCache.h
index db778d3..39a7b3a 100644
--- a/libhidlcache/HidlCache.h
+++ b/libhidlcache/HidlCache.h
@@ -97,7 +97,7 @@ bool HidlCache<Key, Value, Compare>::lock(const Key& key) {
template <class Key, class Value, class Compare>
sp<Value> HidlCache<Key, Value, Compare>::unlock(const Key& key) {
Lock lock(mMutex);
- if (locked(key) > 0) {
+ if (locked(key)) {
sp<Value> v = mLocked[key];
mLocked.erase(key);
return v;
diff --git a/libhidlcache/HidlMemoryCache.cpp b/libhidlcache/HidlMemoryCache.cpp
index 6f9c25c..a23c388 100644
--- a/libhidlcache/HidlMemoryCache.cpp
+++ b/libhidlcache/HidlMemoryCache.cpp
@@ -28,12 +28,12 @@ namespace hardware {
using IMemoryToken = ::android::hidl::memory::token::V1_0::IMemoryToken;
using IMemory = ::android::hidl::memory::V1_0::IMemory;
-class IMemoryDecorator : public virtual IMemory {
+class MemoryDecorator : public virtual IMemory {
public:
- IMemoryDecorator(sp<IMemory> heap) : mHeap(heap) {}
- virtual ~IMemoryDecorator(){};
+ MemoryDecorator(const sp<IMemory>& heap) : mHeap(heap) {}
+ virtual ~MemoryDecorator() {}
Return<void> update() override { return mHeap->update(); }
- Return<void> read() override { return mHeap->read(); };
+ Return<void> read() override { return mHeap->read(); }
Return<void> updateRange(uint64_t start, uint64_t length) override {
return mHeap->updateRange(start, length);
}
@@ -49,29 +49,28 @@ class IMemoryDecorator : public virtual IMemory {
sp<IMemory> mHeap;
};
-class IMemoryCacheable : public virtual IMemoryDecorator {
+class MemoryCacheable : public virtual MemoryDecorator {
public:
- IMemoryCacheable(sp<IMemory> heap, sp<IMemoryToken> key) : IMemoryDecorator(heap), mKey(key) {}
- virtual ~IMemoryCacheable() { HidlMemoryCache::getInstance()->flush(mKey); }
+ MemoryCacheable(const sp<IMemory>& heap, sp<IMemoryToken> key)
+ : MemoryDecorator(heap), mKey(key) {}
+ virtual ~MemoryCacheable() { HidlMemoryCache::getInstance()->flush(mKey); }
protected:
sp<IMemoryToken> mKey;
};
-class IMemoryBlock : public virtual IMemoryDecorator {
+class MemoryBlockImpl : public virtual IMemory {
public:
- IMemoryBlock(sp<IMemory> heap, uint64_t size, uint64_t offset)
- : IMemoryDecorator(heap), mSize(size), mOffset(offset), mHeapSize(heap->getSize()) {}
+ MemoryBlockImpl(const sp<IMemory>& heap, uint64_t size, uint64_t offset)
+ : mHeap(heap), mSize(size), mOffset(offset), mHeapSize(heap->getSize()) {}
bool validRange(uint64_t start, uint64_t length) {
- return (start + length < mSize) && (start + length >= start) &&
- (mOffset + mSize < mHeapSize);
+ return (start + length <= mSize) && (start + length >= start) &&
+ (mOffset + mSize <= mHeapSize);
}
- Return<void> readRange(uint64_t start, uint64_t length) {
+ Return<void> readRange(uint64_t start, uint64_t length) override {
if (!validRange(start, length)) {
ALOGE("IMemoryBlock::readRange: out of range");
- Status status;
- status.setException(Status::EX_ILLEGAL_ARGUMENT, "out of range");
- return Return<void>(status);
+ return Void();
}
return mHeap->readRange(mOffset + start, length);
}
@@ -82,6 +81,9 @@ class IMemoryBlock : public virtual IMemoryDecorator {
}
return mHeap->updateRange(mOffset + start, length);
}
+ Return<void> read() override { return this->readRange(0, mSize); }
+ Return<void> update() override { return this->updateRange(0, mSize); }
+ Return<void> commit() override { return mHeap->commit(); }
Return<uint64_t> getSize() override { return mSize; }
Return<void*> getPointer() override {
void* p = mHeap->getPointer();
@@ -89,6 +91,7 @@ class IMemoryBlock : public virtual IMemoryDecorator {
}
protected:
+ sp<IMemory> mHeap;
uint64_t mSize;
uint64_t mOffset;
uint64_t mHeapSize;
@@ -102,7 +105,7 @@ sp<HidlMemoryCache> HidlMemoryCache::getInstance() {
sp<IMemory> HidlMemoryCache::fillLocked(const sp<IMemoryToken>& key) {
sp<IMemory> memory = nullptr;
Return<void> ret = key->get(
- [&](const hidl_memory& mem) { memory = new IMemoryCacheable(mapMemory(mem), key); });
+ [&](const hidl_memory& mem) { memory = new MemoryCacheable(mapMemory(mem), key); });
if (!ret.isOk()) {
ALOGE("HidlMemoryCache::fill: cannot IMemoryToken::get.");
return nullptr;
@@ -117,7 +120,7 @@ sp<IMemory> HidlMemoryCache::map(const MemoryBlock& memblk) {
if (heap == nullptr) {
return nullptr;
}
- return new IMemoryBlock(heap, memblk.size, memblk.offset);
+ return new MemoryBlockImpl(heap, memblk.size, memblk.offset);
}
} // namespace hardware
diff --git a/libhidlcache/MemoryDealer.cpp b/libhidlcache/MemoryDealer.cpp
index e9196a1..e5686a7 100644
--- a/libhidlcache/MemoryDealer.cpp
+++ b/libhidlcache/MemoryDealer.cpp
@@ -123,7 +123,7 @@ SimpleBestFitAllocator::~SimpleBestFitAllocator() {
// and generates a false positive warning about accessing
// memory that is already freed.
// Add an "assert" to avoid the confusion.
- LOG_ALWAYS_FATAL_IF(mList.head() == removed);
+ LOG_ALWAYS_FATAL_IF(mList.front() == removed);
#endif
delete removed;
}
@@ -221,8 +221,9 @@ SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start) {
if (p->free || !cur->size) {
freed = p;
p->size += cur->size;
- mList.erase(pos);
+ pos = mList.erase(pos);
delete cur;
+ if (pos == mList.end()) break;
}
}
if (++pos == mList.end()) break;
@@ -240,7 +241,7 @@ SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start) {
return freed;
}
}
- return 0;
+ return nullptr;
}
void SimpleBestFitAllocator::dump(const char* tag) const {
diff --git a/minijail/HardwareMinijail.cpp b/minijail/HardwareMinijail.cpp
index e6b1144..990a689 100644
--- a/minijail/HardwareMinijail.cpp
+++ b/minijail/HardwareMinijail.cpp
@@ -29,7 +29,7 @@ void SetupMinijail(const std::string& seccomp_policy_path) {
}
struct minijail* jail = minijail_new();
- if (jail == NULL) {
+ if (jail == nullptr) {
LOG(FATAL) << "Failed to create minijail.";
}
diff --git a/test_main.cpp b/test_main.cpp
index 0de46ec..2b9f52c 100644
--- a/test_main.cpp
+++ b/test_main.cpp
@@ -17,7 +17,7 @@
#define LOG_TAG "LibHidlTest"
#include <android-base/logging.h>
-#include <android/hardware/tests/inheritance/1.0/IParent.h>
+#include <android/hidl/memory/1.0/IMemory.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <hidl/HidlSupport.h>
@@ -280,6 +280,21 @@ TEST_F(LibHidlTest, VecEqTest) {
EXPECT_TRUE(hv1 != hv3);
}
+TEST_F(LibHidlTest, VecEqInitializerTest) {
+ std::vector<int32_t> reference{5, 6, 7};
+ android::hardware::hidl_vec<int32_t> hv1{1, 2, 3};
+ hv1 = {5, 6, 7};
+ android::hardware::hidl_vec<int32_t> hv2;
+ hv2 = {5, 6, 7};
+ android::hardware::hidl_vec<int32_t> hv3;
+ hv3 = {5, 6, 8};
+
+ // use the == and != operator intentionally here
+ EXPECT_TRUE(hv1 == hv2);
+ EXPECT_TRUE(hv1 == reference);
+ EXPECT_TRUE(hv1 != hv3);
+}
+
TEST_F(LibHidlTest, VecRangeCtorTest) {
struct ConvertibleType {
int val;
@@ -390,12 +405,15 @@ TEST_F(LibHidlTest, HidlVersionTest) {
hidl_version v3_0b{3,0};
EXPECT_TRUE(v1_0 < v2_0);
+ EXPECT_TRUE(v1_0 != v2_0);
EXPECT_TRUE(v2_0 < v2_1);
EXPECT_TRUE(v2_1 < v3_0);
EXPECT_TRUE(v2_0 > v1_0);
+ EXPECT_TRUE(v2_0 != v1_0);
EXPECT_TRUE(v2_1 > v2_0);
EXPECT_TRUE(v3_0 > v2_1);
EXPECT_TRUE(v3_0 == v3_0b);
+ EXPECT_FALSE(v3_0 != v3_0b);
EXPECT_TRUE(v3_0 <= v3_0b);
EXPECT_TRUE(v2_2 <= v3_0);
EXPECT_TRUE(v3_0 >= v3_0b);
@@ -459,12 +477,14 @@ TEST_F(LibHidlTest, StatusStringTest) {
TEST_F(LibHidlTest, PreloadTest) {
using ::android::hardware::preloadPassthroughService;
- using ::android::hardware::tests::inheritance::V1_0::IParent;
+ using ::android::hidl::memory::V1_0::IMemory;
- static const std::string kLib = "android.hardware.tests.inheritance@1.0-impl.so";
+ // installed on all devices by default in both bitnesses and not otherwise a dependency of this
+ // test.
+ static const std::string kLib = "android.hidl.memory@1.0-impl.so";
EXPECT_FALSE(isLibraryOpen(kLib));
- preloadPassthroughService<IParent>();
+ preloadPassthroughService<IMemory>();
EXPECT_TRUE(isLibraryOpen(kLib));
}
diff --git a/transport/Android.bp b/transport/Android.bp
index 5b0c11c..6518177 100644
--- a/transport/Android.bp
+++ b/transport/Android.bp
@@ -14,11 +14,11 @@
hidl_package_root {
name: "android.hidl",
- path: "system/libhidl/transport",
}
cc_library {
name: "libhidltransport",
+ recovery_available: true,
vendor_available: true,
vndk: {
enabled: true,
@@ -47,21 +47,25 @@ cc_library {
generated_sources: [
"android.hidl.manager@1.0_genc++",
"android.hidl.manager@1.1_genc++",
+ "android.hidl.manager@1.2_genc++",
"android.hidl.base@1.0_genc++"
],
generated_headers: [
"android.hidl.manager@1.0_genc++_headers",
"android.hidl.manager@1.1_genc++_headers",
+ "android.hidl.manager@1.2_genc++_headers",
"android.hidl.base@1.0_genc++_headers"
],
export_generated_headers: [
"android.hidl.manager@1.0_genc++_headers",
"android.hidl.manager@1.1_genc++_headers",
+ "android.hidl.manager@1.2_genc++_headers",
"android.hidl.base@1.0_genc++_headers"
],
srcs: [
"HidlBinderSupport.cpp",
+ "HidlLazyUtils.cpp",
"HidlPassthroughSupport.cpp",
"HidlTransportSupport.cpp",
"HidlTransportUtils.cpp",
@@ -77,4 +81,10 @@ cc_library {
cflags: ["-DENFORCE_VINTF_MANIFEST"]
},
},
+
+ target: {
+ recovery: {
+ exclude_shared_libs: ["libvndksupport"],
+ },
+ },
}
diff --git a/transport/HidlBinderSupport.cpp b/transport/HidlBinderSupport.cpp
index 4f8d7c5..62b1755 100644
--- a/transport/HidlBinderSupport.cpp
+++ b/transport/HidlBinderSupport.cpp
@@ -18,6 +18,10 @@
#include <hidl/HidlBinderSupport.h>
+#include <InternalStatic.h> // TODO(b/69122224): remove this include, for getOrCreateCachedBinder
+#include <android/hidl/base/1.0/BpHwBase.h>
+#include <hwbinder/IPCThreadState.h>
+
// C includes
#include <inttypes.h>
#include <unistd.h>
@@ -46,6 +50,30 @@ wp<hidl_death_recipient> hidl_binder_death_recipient::getRecipient() {
return mRecipient;
}
+const size_t hidl_handle::kOffsetOfNativeHandle = offsetof(hidl_handle, mHandle);
+static_assert(hidl_handle::kOffsetOfNativeHandle == 0, "wrong offset");
+
+status_t readEmbeddedFromParcel(const hidl_handle& /* handle */,
+ const Parcel &parcel, size_t parentHandle, size_t parentOffset) {
+ const native_handle_t *handle;
+ status_t _hidl_err = parcel.readNullableEmbeddedNativeHandle(
+ parentHandle,
+ parentOffset + hidl_handle::kOffsetOfNativeHandle,
+ &handle);
+
+ return _hidl_err;
+}
+
+status_t writeEmbeddedToParcel(const hidl_handle &handle,
+ Parcel *parcel, size_t parentHandle, size_t parentOffset) {
+ status_t _hidl_err = parcel->writeEmbeddedNativeHandle(
+ handle.getNativeHandle(),
+ parentHandle,
+ parentOffset + hidl_handle::kOffsetOfNativeHandle);
+
+ return _hidl_err;
+}
+
const size_t hidl_memory::kOffsetOfHandle = offsetof(hidl_memory, mHandle);
const size_t hidl_memory::kOffsetOfName = offsetof(hidl_memory, mName);
static_assert(hidl_memory::kOffsetOfHandle == 0, "wrong offset");
@@ -53,6 +81,7 @@ static_assert(hidl_memory::kOffsetOfName == 24, "wrong offset");
status_t readEmbeddedFromParcel(const hidl_memory& memory,
const Parcel &parcel, size_t parentHandle, size_t parentOffset) {
+ // TODO(b/111883309): Invoke readEmbeddedFromParcel(hidl_handle, ...).
const native_handle_t *handle;
::android::status_t _hidl_err = parcel.readNullableEmbeddedNativeHandle(
parentHandle,
@@ -81,6 +110,7 @@ status_t readEmbeddedFromParcel(const hidl_memory& memory,
status_t writeEmbeddedToParcel(const hidl_memory &memory,
Parcel *parcel, size_t parentHandle, size_t parentOffset) {
+ // TODO(b/111883309): Invoke writeEmbeddedToParcel(hidl_handle, ...).
status_t _hidl_err = parcel->writeEmbeddedNativeHandle(
memory.handle(),
parentHandle,
@@ -206,11 +236,63 @@ status_t writeToParcel(const Status &s, Parcel* parcel) {
return status;
}
+sp<IBinder> getOrCreateCachedBinder(::android::hidl::base::V1_0::IBase* ifacePtr) {
+ if (ifacePtr == nullptr) {
+ return nullptr;
+ }
+
+ if (ifacePtr->isRemote()) {
+ using ::android::hidl::base::V1_0::BpHwBase;
+
+ BpHwBase* bpBase = static_cast<BpHwBase*>(ifacePtr);
+ BpHwRefBase* bpRefBase = static_cast<BpHwRefBase*>(bpBase);
+ return sp<IBinder>(bpRefBase->remote());
+ }
+
+ std::string descriptor = details::getDescriptor(ifacePtr);
+ if (descriptor.empty()) {
+ // interfaceDescriptor fails
+ return nullptr;
+ }
+
+ // for get + set
+ std::unique_lock<std::mutex> _lock = details::gBnMap->lock();
+
+ wp<BHwBinder> wBnObj = details::gBnMap->getLocked(ifacePtr, nullptr);
+ sp<IBinder> sBnObj = wBnObj.promote();
+
+ if (sBnObj == nullptr) {
+ auto func = details::getBnConstructorMap().get(descriptor, nullptr);
+ if (!func) {
+ // TODO(b/69122224): remove this static variable when prebuilts updated
+ func = details::gBnConstructorMap->get(descriptor, nullptr);
+ }
+ LOG_ALWAYS_FATAL_IF(func == nullptr, "%s gBnConstructorMap returned null for %s", __func__,
+ descriptor.c_str());
+
+ sBnObj = sp<IBinder>(func(static_cast<void*>(ifacePtr)));
+ LOG_ALWAYS_FATAL_IF(sBnObj == nullptr, "%s Bn constructor function returned null for %s",
+ __func__, descriptor.c_str());
+
+ details::gBnMap->setLocked(ifacePtr, static_cast<BHwBinder*>(sBnObj.get()));
+ }
+
+ return sBnObj;
+}
+
+static bool gThreadPoolConfigured = false;
+
void configureBinderRpcThreadpool(size_t maxThreads, bool callerWillJoin) {
- ProcessState::self()->setThreadPoolConfiguration(maxThreads, callerWillJoin /*callerJoinsPool*/);
+ status_t ret = ProcessState::self()->setThreadPoolConfiguration(
+ maxThreads, callerWillJoin /*callerJoinsPool*/);
+ LOG_ALWAYS_FATAL_IF(ret != OK, "Could not setThreadPoolConfiguration: %d", ret);
+
+ gThreadPoolConfigured = true;
}
void joinBinderRpcThreadpool() {
+ LOG_ALWAYS_FATAL_IF(!gThreadPoolConfigured,
+ "HIDL joinRpcThreadpool without calling configureRpcThreadPool.");
IPCThreadState::self()->joinThreadPool();
}
@@ -218,9 +300,7 @@ int setupBinderPolling() {
int fd;
int err = IPCThreadState::self()->setupPolling(&fd);
- if (err != OK) {
- ALOGE("Failed to setup binder polling: %d (%s)", err, strerror(err));
- }
+ LOG_ALWAYS_FATAL_IF(err != OK, "Failed to setup binder polling: %d (%s)", err, strerror(err));
return err == OK ? fd : -1;
}
@@ -229,5 +309,9 @@ status_t handleBinderPoll() {
return IPCThreadState::self()->handlePolledCommands();
}
+void addPostCommandTask(const std::function<void(void)> task) {
+ IPCThreadState::self()->addPostCommandTask(task);
+}
+
} // namespace hardware
} // namespace android
diff --git a/transport/HidlLazyUtils.cpp b/transport/HidlLazyUtils.cpp
new file mode 100644
index 0000000..8e3fdf3
--- /dev/null
+++ b/transport/HidlLazyUtils.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2018 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/HidlLazyUtils.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include <android-base/logging.h>
+
+#include <android/hidl/manager/1.2/IClientCallback.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+
+namespace android {
+namespace hardware {
+namespace details {
+
+using ::android::hidl::base::V1_0::IBase;
+
+class ClientCounterCallback : public ::android::hidl::manager::V1_2::IClientCallback {
+ public:
+ ClientCounterCallback() : mNumConnectedServices(0) {}
+
+ bool addRegisteredService(const sp<IBase>& service, const std::string& name);
+
+ protected:
+ Return<void> onClients(const sp<IBase>& service, bool clients) override;
+
+ private:
+ /**
+ * Registers or re-registers services. Returns whether successful.
+ */
+ bool registerService(const sp<IBase>& service, const std::string& name);
+
+ /**
+ * Unregisters all services that we can. If we can't unregister all, re-register other
+ * services.
+ */
+ void tryShutdown();
+
+ /**
+ * Counter of the number of services that currently have at least one client.
+ */
+ size_t mNumConnectedServices;
+
+ struct Service {
+ sp<IBase> service;
+ std::string name;
+ };
+ /**
+ * Number of services that have been registered.
+ */
+ std::vector<Service> mRegisteredServices;
+};
+
+class LazyServiceRegistrarImpl {
+ public:
+ LazyServiceRegistrarImpl() : mClientCallback(new ClientCounterCallback) {}
+
+ status_t registerService(const sp<::android::hidl::base::V1_0::IBase>& service,
+ const std::string& name);
+
+ private:
+ sp<ClientCounterCallback> mClientCallback;
+};
+
+bool ClientCounterCallback::addRegisteredService(const sp<IBase>& service,
+ const std::string& name) {
+ bool success = registerService(service, name);
+
+ if (success) {
+ mRegisteredServices.push_back({service, name});
+ }
+
+ return success;
+}
+
+bool ClientCounterCallback::registerService(const sp<IBase>& service, const std::string& name) {
+ auto manager = hardware::defaultServiceManager1_2();
+
+ const std::string descriptor = getDescriptor(service.get());
+
+ LOG(INFO) << "Registering HAL: " << descriptor << " with name: " << name;
+
+ status_t res = android::hardware::details::registerAsServiceInternal(service, name);
+ if (res != android::OK) {
+ LOG(ERROR) << "Failed to register as service.";
+ return false;
+ }
+
+ bool ret = manager->registerClientCallback(getDescriptor(service.get()), name, service, this);
+ if (!ret) {
+ LOG(ERROR) << "Failed to add client callback.";
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * onClients is oneway, so no need to worry about multi-threading. Note that this means multiple
+ * invocations could occur on different threads however.
+ */
+Return<void> ClientCounterCallback::onClients(const sp<::android::hidl::base::V1_0::IBase>& service,
+ bool clients) {
+ if (clients) {
+ mNumConnectedServices++;
+ } else {
+ mNumConnectedServices--;
+ }
+
+ LOG(INFO) << "Process has " << mNumConnectedServices << " (of " << mRegisteredServices.size()
+ << " available) client(s) in use after notification " << getDescriptor(service.get())
+ << " has clients: " << clients;
+
+ if (mNumConnectedServices == 0) {
+ tryShutdown();
+ }
+
+ return Status::ok();
+}
+
+void ClientCounterCallback::tryShutdown() {
+ LOG(INFO) << "Trying to exit HAL. No clients in use for any service in process.";
+
+ auto manager = hardware::defaultServiceManager1_2();
+
+ auto unRegisterIt = mRegisteredServices.begin();
+ for (; unRegisterIt != mRegisteredServices.end(); ++unRegisterIt) {
+ auto& entry = (*unRegisterIt);
+
+ const std::string descriptor = getDescriptor(entry.service.get());
+ bool success = manager->tryUnregister(descriptor, entry.name, entry.service);
+
+ if (!success) {
+ LOG(INFO) << "Failed to unregister HAL " << descriptor << "/" << entry.name;
+ break;
+ }
+ }
+
+ if (unRegisterIt == mRegisteredServices.end()) {
+ LOG(INFO) << "Unregistered all clients and exiting";
+ exit(EXIT_SUCCESS);
+ }
+
+ for (auto reRegisterIt = mRegisteredServices.begin(); reRegisterIt != unRegisterIt;
+ reRegisterIt++) {
+ auto& entry = (*reRegisterIt);
+
+ // re-register entry
+ if (!registerService(entry.service, entry.name)) {
+ // Must restart. Otherwise, clients will never be able to get ahold of this service.
+ LOG(FATAL) << "Bad state: could not re-register " << getDescriptor(entry.service.get());
+ }
+ }
+}
+
+status_t LazyServiceRegistrarImpl::registerService(
+ const sp<::android::hidl::base::V1_0::IBase>& service, const std::string& name) {
+ if (!mClientCallback->addRegisteredService(service, name)) {
+ return ::android::UNKNOWN_ERROR;
+ }
+
+ return ::android::OK;
+}
+
+} // namespace details
+
+LazyServiceRegistrar::LazyServiceRegistrar() {
+ mImpl = std::make_shared<details::LazyServiceRegistrarImpl>();
+}
+
+status_t LazyServiceRegistrar::registerService(
+ const sp<::android::hidl::base::V1_0::IBase>& service, const std::string& name) {
+ return mImpl->registerService(service, name);
+}
+
+} // namespace hardware
+} // namespace android
diff --git a/transport/HidlPassthroughSupport.cpp b/transport/HidlPassthroughSupport.cpp
index e5eb164..bc67656 100644
--- a/transport/HidlPassthroughSupport.cpp
+++ b/transport/HidlPassthroughSupport.cpp
@@ -16,6 +16,8 @@
#include <hidl/HidlPassthroughSupport.h>
+#include <InternalStatic.h> // TODO(b/69122224): remove this include, for tryWrap
+
#include <hidl/HidlTransportUtils.h>
#include <hidl/Static.h>
@@ -28,7 +30,8 @@ namespace details {
static sp<IBase> tryWrap(const std::string& descriptor, sp<IBase> iface) {
auto func = getBsConstructorMap().get(descriptor, nullptr);
if (!func) {
- func = gBsConstructorMap.get(descriptor, nullptr);
+ // TODO(b/69122224): remove this when prebuilts don't reference it
+ func = gBsConstructorMap->get(descriptor, nullptr);
}
if (func) {
return func(static_cast<void*>(iface.get()));
diff --git a/transport/HidlTransportSupport.cpp b/transport/HidlTransportSupport.cpp
index c3a3031..b433b70 100644
--- a/transport/HidlTransportSupport.cpp
+++ b/transport/HidlTransportSupport.cpp
@@ -13,14 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include <hidl/HidlTransportSupport.h>
#include <hidl/HidlBinderSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/Static.h>
+#include <android-base/logging.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
namespace android {
namespace hardware {
+using ::android::hidl::base::V1_0::IBase;
+
void configureRpcThreadpool(size_t maxThreads, bool callerWillJoin) {
// TODO(b/32756130) this should be transport-dependent
configureBinderRpcThreadpool(maxThreads, callerWillJoin);
@@ -40,9 +44,7 @@ status_t handleTransportPoll(int /*fd*/) {
// TODO(b/122472540): only store one data item per object
template <typename V>
-static void pruneMapLocked(ConcurrentMap<wp<::android::hidl::base::V1_0::IBase>, V>& map) {
- using ::android::hidl::base::V1_0::IBase;
-
+static void pruneMapLocked(ConcurrentMap<wp<IBase>, V>& map) {
std::vector<wp<IBase>> toDelete;
for (const auto& kv : map) {
if (kv.first.promote() == nullptr) {
@@ -54,47 +56,65 @@ static void pruneMapLocked(ConcurrentMap<wp<::android::hidl::base::V1_0::IBase>,
}
}
-bool setMinSchedulerPolicy(const sp<::android::hidl::base::V1_0::IBase>& service,
- int policy, int priority) {
+bool setMinSchedulerPolicy(const sp<IBase>& service, int policy, int priority) {
if (service->isRemote()) {
- ALOGE("Can't set scheduler policy on remote service.");
+ LOG(ERROR) << "Can't set scheduler policy on remote service.";
return false;
}
- if (policy != SCHED_NORMAL && policy != SCHED_FIFO && policy != SCHED_RR) {
- ALOGE("Invalid scheduler policy %d", policy);
- return false;
- }
-
- if (policy == SCHED_NORMAL && (priority < -20 || priority > 19)) {
- ALOGE("Invalid priority for SCHED_NORMAL: %d", priority);
- return false;
- } else if (priority < 1 || priority > 99) {
- ALOGE("Invalid priority for real-time policy: %d", priority);
- return false;
+ switch (policy) {
+ case SCHED_NORMAL: {
+ if (priority < -20 || priority > 19) {
+ LOG(ERROR) << "Invalid priority for SCHED_NORMAL: " << priority;
+ return false;
+ }
+ } break;
+ case SCHED_RR:
+ case SCHED_FIFO: {
+ if (priority < 1 || priority > 99) {
+ LOG(ERROR) << "Invalid priority for " << policy << " policy: " << priority;
+ return false;
+ }
+ } break;
+ default: {
+ LOG(ERROR) << "Invalid scheduler policy " << policy;
+ return false;
+ }
}
- details::gServicePrioMap.set(service, { policy, priority });
+ // Due to ABI considerations, IBase cannot have a destructor to clean this up.
+ // So, because this API is so infrequently used, (expected to be usually only
+ // one time for a process, but it can be more), we are cleaning it up here.
+ std::unique_lock<std::mutex> lock = details::gServicePrioMap->lock();
+ pruneMapLocked(details::gServicePrioMap.get());
+ details::gServicePrioMap->setLocked(service, {policy, priority});
return true;
}
-bool setRequestingSid(const sp<::android::hidl::base::V1_0::IBase>& service, bool requesting) {
+bool setRequestingSid(const sp<IBase>& service, bool requesting) {
if (service->isRemote()) {
- ALOGE("Can't set requesting sid on remote service.");
+ LOG(ERROR) << "Can't set requesting sid on remote service.";
return false;
}
// Due to ABI considerations, IBase cannot have a destructor to clean this up.
// So, because this API is so infrequently used, (expected to be usually only
// one time for a process, but it can be more), we are cleaning it up here.
- std::unique_lock<std::mutex> lock = details::gServiceSidMap.lock();
- pruneMapLocked(details::gServiceSidMap);
- details::gServiceSidMap.setLocked(service, requesting);
+ std::unique_lock<std::mutex> lock = details::gServiceSidMap->lock();
+ pruneMapLocked(details::gServiceSidMap.get());
+ details::gServiceSidMap->setLocked(service, requesting);
return true;
}
+bool interfacesEqual(const sp<IBase>& left, const sp<IBase>& right) {
+ if (left == nullptr || right == nullptr || !left->isRemote() || !right->isRemote()) {
+ return left == right;
+ }
+ return getOrCreateCachedBinder(left.get()) == getOrCreateCachedBinder(right.get());
+}
+
namespace details {
int32_t getPidIfSharable() {
#if LIBHIDL_TARGET_DEBUGGABLE
diff --git a/transport/HidlTransportUtils.cpp b/transport/HidlTransportUtils.cpp
index 4e952eb..8c61281 100644
--- a/transport/HidlTransportUtils.cpp
+++ b/transport/HidlTransportUtils.cpp
@@ -56,6 +56,10 @@ Return<bool> canCastInterface(IBase* interface, const char* castTo, bool emitErr
}
std::string getDescriptor(IBase* interface) {
+ if (interface == nullptr) {
+ return "";
+ }
+
std::string myDescriptor{};
auto ret = interface->interfaceDescriptor([&](const hidl_string &types) {
myDescriptor = types.c_str();
diff --git a/transport/InternalStatic.h b/transport/InternalStatic.h
new file mode 100644
index 0000000..1dfaae4
--- /dev/null
+++ b/transport/InternalStatic.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+// This file is for legacy static variables that we are trying to get rid of.
+// TODO(b/69122224): remove this file
+
+#ifndef ANDROID_HARDWARE_HIDL_INTERNAL_STATIC_H
+#define ANDROID_HARDWARE_HIDL_INTERNAL_STATIC_H
+
+#include <hidl/Static.h>
+
+namespace android {
+namespace hardware {
+namespace details {
+
+// TODO(b/69122224): remove this
+// deprecated; use getBnConstructorMap instead.
+extern DoNotDestruct<BnConstructorMap> gBnConstructorMap;
+// TODO(b/69122224): remove this
+// deprecated; use getBsConstructorMap instead.
+extern DoNotDestruct<BsConstructorMap> gBsConstructorMap;
+
+} // namespace details
+} // namespace hardware
+} // namespace android
+
+#endif
diff --git a/transport/ServiceManagement.cpp b/transport/ServiceManagement.cpp
index 01f83bd..e7bec41 100644
--- a/transport/ServiceManagement.cpp
+++ b/transport/ServiceManagement.cpp
@@ -33,17 +33,23 @@
#include <hidl/HidlTransportUtils.h>
#include <hidl/ServiceManagement.h>
#include <hidl/Status.h>
+#include <utils/SystemClock.h>
+#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <hwbinder/IPCThreadState.h>
#include <hwbinder/Parcel.h>
+#if !defined(__ANDROID_RECOVERY__)
#include <vndksupport/linker.h>
+#endif
-#include <android/hidl/manager/1.1/IServiceManager.h>
-#include <android/hidl/manager/1.1/BpHwServiceManager.h>
-#include <android/hidl/manager/1.1/BnHwServiceManager.h>
+#include <android/hidl/manager/1.2/BnHwServiceManager.h>
+#include <android/hidl/manager/1.2/BpHwServiceManager.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
#define RE_COMPONENT "[a-zA-Z_][a-zA-Z_0-9]*"
#define RE_PATH RE_COMPONENT "(?:[.]" RE_COMPONENT ")*"
@@ -51,23 +57,24 @@ static const std::regex gLibraryFileNamePattern("(" RE_PATH "@[0-9]+[.][0-9]+)-i
using android::base::WaitForProperty;
+using ::android::hidl::base::V1_0::IBase;
using IServiceManager1_0 = android::hidl::manager::V1_0::IServiceManager;
using IServiceManager1_1 = android::hidl::manager::V1_1::IServiceManager;
-using android::hidl::manager::V1_0::IServiceNotification;
-using android::hidl::manager::V1_1::BpHwServiceManager;
-using android::hidl::manager::V1_1::BnHwServiceManager;
+using IServiceManager1_2 = android::hidl::manager::V1_2::IServiceManager;
+using ::android::hidl::manager::V1_0::IServiceNotification;
namespace android {
namespace hardware {
-namespace details {
-extern Mutex gDefaultServiceManagerLock;
-extern sp<android::hidl::manager::V1_1::IServiceManager> gDefaultServiceManager;
-} // namespace details
-
static const char* kHwServicemanagerReadyProperty = "hwservicemanager.ready";
-void waitForHwServiceManager() {
+#if defined(__ANDROID_RECOVERY__)
+static constexpr bool kIsRecovery = true;
+#else
+static constexpr bool kIsRecovery = false;
+#endif
+
+static void waitForHwServiceManager() {
using std::literals::chrono_literals::operator""s;
while (!WaitForProperty(kHwServicemanagerReadyProperty, "true", 1s)) {
@@ -75,17 +82,7 @@ void waitForHwServiceManager() {
}
}
-bool endsWith(const std::string &in, const std::string &suffix) {
- return in.size() >= suffix.size() &&
- in.substr(in.size() - suffix.size()) == suffix;
-}
-
-bool startsWith(const std::string &in, const std::string &prefix) {
- return in.size() >= prefix.size() &&
- in.substr(0, prefix.size()) == prefix;
-}
-
-std::string binaryName() {
+static std::string binaryName() {
std::ifstream ifs("/proc/self/cmdline");
std::string cmdline;
if (!ifs.is_open()) {
@@ -101,27 +98,27 @@ std::string binaryName() {
return cmdline;
}
-std::string packageWithoutVersion(const std::string& packageAndVersion) {
+static std::string packageWithoutVersion(const std::string& packageAndVersion) {
size_t at = packageAndVersion.find('@');
if (at == std::string::npos) return packageAndVersion;
return packageAndVersion.substr(0, at);
}
-void tryShortenProcessName(const std::string& packageAndVersion) {
+static void tryShortenProcessName(const std::string& descriptor) {
const static std::string kTasks = "/proc/self/task/";
// make sure that this binary name is in the same package
std::string processName = binaryName();
// e.x. android.hardware.foo is this package
- if (!startsWith(packageWithoutVersion(processName), packageWithoutVersion(packageAndVersion))) {
+ if (!base::StartsWith(packageWithoutVersion(processName), packageWithoutVersion(descriptor))) {
return;
}
- // e.x. android.hardware.module.foo@1.2 -> foo@1.2
- size_t lastDot = packageAndVersion.rfind('.');
+ // e.x. android.hardware.module.foo@1.2::IFoo -> foo@1.2
+ size_t lastDot = descriptor.rfind('.');
if (lastDot == std::string::npos) return;
- size_t secondDot = packageAndVersion.rfind('.', lastDot - 1);
+ size_t secondDot = descriptor.rfind('.', lastDot - 1);
if (secondDot == std::string::npos) return;
std::string newName = processName.substr(secondDot + 1, std::string::npos);
@@ -145,7 +142,7 @@ void tryShortenProcessName(const std::string& packageAndVersion) {
fs >> oldComm;
// don't rename if it already has an explicit name
- if (startsWith(packageAndVersion, oldComm)) {
+ if (base::StartsWith(descriptor, oldComm)) {
fs.seekg(0, fs.beg);
fs << newName;
}
@@ -154,22 +151,69 @@ void tryShortenProcessName(const std::string& packageAndVersion) {
namespace details {
-void onRegistration(const std::string &packageName,
- const std::string& /* interfaceName */,
- const std::string& /* instanceName */) {
- tryShortenProcessName(packageName);
+/*
+ * Returns the age of the current process by reading /proc/self/stat and comparing starttime to the
+ * current time. This is useful for measuring how long it took a HAL to register itself.
+ */
+static long getProcessAgeMs() {
+ constexpr const int PROCFS_STAT_STARTTIME_INDEX = 21;
+ std::string content;
+ android::base::ReadFileToString("/proc/self/stat", &content, false);
+ auto stats = android::base::Split(content, " ");
+ if (stats.size() <= PROCFS_STAT_STARTTIME_INDEX) {
+ LOG(INFO) << "Could not read starttime from /proc/self/stat";
+ return -1;
+ }
+ const std::string& startTimeString = stats[PROCFS_STAT_STARTTIME_INDEX];
+ static const int64_t ticksPerSecond = sysconf(_SC_CLK_TCK);
+ const int64_t uptime = android::uptimeMillis();
+
+ unsigned long long startTimeInClockTicks = 0;
+ if (android::base::ParseUint(startTimeString, &startTimeInClockTicks)) {
+ long startTimeMs = 1000ULL * startTimeInClockTicks / ticksPerSecond;
+ return uptime - startTimeMs;
+ }
+ return -1;
+}
+
+static void onRegistrationImpl(const std::string& descriptor, const std::string& instanceName) {
+ long halStartDelay = getProcessAgeMs();
+ if (halStartDelay >= 0) {
+ // The "start delay" printed here is an estimate of how long it took the HAL to go from
+ // process creation to registering itself as a HAL. Actual start time could be longer
+ // because the process might not have joined the threadpool yet, so it might not be ready to
+ // process transactions.
+ LOG(INFO) << "Registered " << descriptor << "/" << instanceName << " (start delay of "
+ << halStartDelay << "ms)";
+ }
+
+ tryShortenProcessName(descriptor);
+}
+
+void onRegistration(const std::string& packageName, const std::string& interfaceName,
+ const std::string& instanceName) {
+ return onRegistrationImpl(packageName + "::" + interfaceName, instanceName);
}
} // details
sp<IServiceManager1_0> defaultServiceManager() {
- return defaultServiceManager1_1();
+ return defaultServiceManager1_2();
}
sp<IServiceManager1_1> defaultServiceManager1_1() {
+ return defaultServiceManager1_2();
+}
+sp<IServiceManager1_2> defaultServiceManager1_2() {
+ using android::hidl::manager::V1_2::BnHwServiceManager;
+ using android::hidl::manager::V1_2::BpHwServiceManager;
+
+ static std::mutex gDefaultServiceManagerLock;
+ static sp<IServiceManager1_2> gDefaultServiceManager;
+
{
- AutoMutex _l(details::gDefaultServiceManagerLock);
- if (details::gDefaultServiceManager != nullptr) {
- return details::gDefaultServiceManager;
+ std::lock_guard<std::mutex> _l(gDefaultServiceManagerLock);
+ if (gDefaultServiceManager != nullptr) {
+ return gDefaultServiceManager;
}
if (access("/dev/hwbinder", F_OK|R_OK|W_OK) != 0) {
@@ -180,23 +224,22 @@ sp<IServiceManager1_1> defaultServiceManager1_1() {
waitForHwServiceManager();
- while (details::gDefaultServiceManager == nullptr) {
- details::gDefaultServiceManager =
- fromBinder<IServiceManager1_1, BpHwServiceManager, BnHwServiceManager>(
- ProcessState::self()->getContextObject(nullptr));
- if (details::gDefaultServiceManager == nullptr) {
+ while (gDefaultServiceManager == nullptr) {
+ gDefaultServiceManager =
+ fromBinder<IServiceManager1_2, BpHwServiceManager, BnHwServiceManager>(
+ ProcessState::self()->getContextObject(nullptr));
+ if (gDefaultServiceManager == nullptr) {
LOG(ERROR) << "Waited for hwservicemanager, but got nullptr.";
sleep(1);
}
}
}
- return details::gDefaultServiceManager;
+ return gDefaultServiceManager;
}
-std::vector<std::string> search(const std::string &path,
- const std::string &prefix,
- const std::string &suffix) {
+static std::vector<std::string> findFiles(const std::string& path, const std::string& prefix,
+ const std::string& suffix) {
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
if (!dir) return {};
@@ -206,8 +249,7 @@ std::vector<std::string> search(const std::string &path,
while ((dp = readdir(dir.get())) != nullptr) {
std::string name = dp->d_name;
- if (startsWith(name, prefix) &&
- endsWith(name, suffix)) {
+ if (base::StartsWith(name, prefix) && base::EndsWith(name, suffix)) {
results.push_back(name);
}
}
@@ -226,6 +268,11 @@ bool matchPackageName(const std::string& lib, std::string* matchedName, std::str
}
static void registerReference(const hidl_string &interfaceName, const hidl_string &instanceName) {
+ if (kIsRecovery) {
+ // No hwservicemanager in recovery.
+ return;
+ }
+
sp<IServiceManager1_0> binderizedManager = defaultServiceManager();
if (binderizedManager == nullptr) {
LOG(WARNING) << "Could not registerReference for "
@@ -309,8 +356,12 @@ struct PassthroughServiceManager : IServiceManager1_1 {
static std::string halLibPathVndkSp = android::base::StringPrintf(
HAL_LIBRARY_PATH_VNDK_SP_FOR_VERSION, details::getVndkVersionStr().c_str());
- std::vector<std::string> paths = {HAL_LIBRARY_PATH_ODM, HAL_LIBRARY_PATH_VENDOR,
- halLibPathVndkSp, HAL_LIBRARY_PATH_SYSTEM};
+ std::vector<std::string> paths = {
+ HAL_LIBRARY_PATH_ODM, HAL_LIBRARY_PATH_VENDOR, halLibPathVndkSp,
+#ifndef __ANDROID_VNDK__
+ HAL_LIBRARY_PATH_SYSTEM,
+#endif
+ };
#ifdef LIBHIDL_TARGET_DEBUGGABLE
const char* env = std::getenv("TREBLE_TESTING_OVERRIDE");
@@ -336,15 +387,17 @@ struct PassthroughServiceManager : IServiceManager1_1 {
#endif
for (const std::string& path : paths) {
- std::vector<std::string> libs = search(path, prefix, ".so");
+ std::vector<std::string> libs = findFiles(path, prefix, ".so");
for (const std::string &lib : libs) {
const std::string fullPath = path + lib;
- if (path == HAL_LIBRARY_PATH_SYSTEM) {
+ if (kIsRecovery || path == HAL_LIBRARY_PATH_SYSTEM) {
handle = dlopen(fullPath.c_str(), dlMode);
} else {
+#if !defined(__ANDROID_RECOVERY__)
handle = android_load_sphal_library(fullPath.c_str(), dlMode);
+#endif
}
if (handle == nullptr) {
@@ -436,16 +489,26 @@ struct PassthroughServiceManager : IServiceManager1_1 {
HAL_LIBRARY_PATH_VNDK_SP_32BIT_FOR_VERSION, details::getVndkVersionStr().c_str());
static std::vector<std::pair<Arch, std::vector<const char*>>> sAllPaths{
{Arch::IS_64BIT,
- {HAL_LIBRARY_PATH_ODM_64BIT, HAL_LIBRARY_PATH_VENDOR_64BIT,
- halLibPathVndkSp64.c_str(), HAL_LIBRARY_PATH_SYSTEM_64BIT}},
+ {
+ HAL_LIBRARY_PATH_ODM_64BIT, HAL_LIBRARY_PATH_VENDOR_64BIT,
+ halLibPathVndkSp64.c_str(),
+#ifndef __ANDROID_VNDK__
+ HAL_LIBRARY_PATH_SYSTEM_64BIT,
+#endif
+ }},
{Arch::IS_32BIT,
- {HAL_LIBRARY_PATH_ODM_32BIT, HAL_LIBRARY_PATH_VENDOR_32BIT,
- halLibPathVndkSp32.c_str(), HAL_LIBRARY_PATH_SYSTEM_32BIT}}};
+ {
+ HAL_LIBRARY_PATH_ODM_32BIT, HAL_LIBRARY_PATH_VENDOR_32BIT,
+ halLibPathVndkSp32.c_str(),
+#ifndef __ANDROID_VNDK__
+ HAL_LIBRARY_PATH_SYSTEM_32BIT,
+#endif
+ }}};
std::map<std::string, InstanceDebugInfo> map;
for (const auto &pair : sAllPaths) {
Arch arch = pair.first;
for (const auto &path : pair.second) {
- std::vector<std::string> libs = search(path, "", ".so");
+ std::vector<std::string> libs = findFiles(path, "", ".so");
for (const std::string &lib : libs) {
std::string matchedName;
std::string implName;
@@ -563,7 +626,7 @@ struct Waiter : IServiceNotification {
return Void();
}
- void wait() {
+ void wait(bool timeout) {
using std::literals::chrono_literals::operator""s;
if (!mRegisteredForNotifications) {
@@ -574,7 +637,7 @@ struct Waiter : IServiceNotification {
}
std::unique_lock<std::mutex> lock(mMutex);
- while(true) {
+ do {
mCondition.wait_for(lock, 1s, [this]{
return mRegistered;
});
@@ -583,9 +646,8 @@ struct Waiter : IServiceNotification {
break;
}
- LOG(WARNING) << "Waited one second for " << mInterfaceName << "/" << mInstanceName
- << ". Waiting another...";
- }
+ LOG(WARNING) << "Waited one second for " << mInterfaceName << "/" << mInstanceName;
+ } while (!timeout);
}
// Be careful when using this; after calling reset(), you must always try to retrieve
@@ -615,7 +677,7 @@ struct Waiter : IServiceNotification {
private:
const std::string mInterfaceName;
const std::string mInstanceName;
- const sp<IServiceManager1_1>& mSm;
+ sp<IServiceManager1_1> mSm;
std::mutex mMutex;
std::condition_variable mCondition;
bool mRegistered = false;
@@ -626,7 +688,7 @@ struct Waiter : IServiceNotification {
void waitForHwService(
const std::string &interface, const std::string &instanceName) {
sp<Waiter> waiter = new Waiter(interface, instanceName, defaultServiceManager1_1());
- waiter->wait();
+ waiter->wait(false /* timeout */);
waiter->done();
}
@@ -665,24 +727,30 @@ sp<::android::hidl::base::V1_0::IBase> getRawServiceInternal(const std::string&
const std::string& instance,
bool retry, bool getStub) {
using Transport = ::android::hidl::manager::V1_0::IServiceManager::Transport;
- using ::android::hidl::base::V1_0::IBase;
using ::android::hidl::manager::V1_0::IServiceManager;
sp<Waiter> waiter;
- const sp<IServiceManager1_1> sm = defaultServiceManager1_1();
- if (sm == nullptr) {
- ALOGE("getService: defaultServiceManager() is null");
- return nullptr;
- }
+ sp<IServiceManager1_1> sm;
+ Transport transport = Transport::EMPTY;
+ if (kIsRecovery) {
+ transport = Transport::PASSTHROUGH;
+ } else {
+ sm = defaultServiceManager1_1();
+ if (sm == nullptr) {
+ ALOGE("getService: defaultServiceManager() is null");
+ return nullptr;
+ }
- Return<Transport> transportRet = sm->getTransport(descriptor, instance);
+ Return<Transport> transportRet = sm->getTransport(descriptor, instance);
- if (!transportRet.isOk()) {
- ALOGE("getService: defaultServiceManager()->getTransport returns %s",
- transportRet.description().c_str());
- return nullptr;
+ if (!transportRet.isOk()) {
+ ALOGE("getService: defaultServiceManager()->getTransport returns %s",
+ transportRet.description().c_str());
+ return nullptr;
+ }
+ transport = transportRet;
}
- Transport transport = transportRet;
+
const bool vintfHwbinder = (transport == Transport::HWBINDER);
const bool vintfPassthru = (transport == Transport::PASSTHROUGH);
@@ -736,7 +804,7 @@ sp<::android::hidl::base::V1_0::IBase> getRawServiceInternal(const std::string&
if (waiter != nullptr) {
ALOGI("getService: Trying again for %s/%s...", descriptor.c_str(), instance.c_str());
- waiter->wait();
+ waiter->wait(true /* timeout */);
}
}
@@ -758,7 +826,33 @@ sp<::android::hidl::base::V1_0::IBase> getRawServiceInternal(const std::string&
return nullptr;
}
-}; // namespace details
+status_t registerAsServiceInternal(const sp<IBase>& service, const std::string& name) {
+ if (service == nullptr) {
+ return UNEXPECTED_NULL;
+ }
+
+ sp<IServiceManager1_2> sm = defaultServiceManager1_2();
+ if (sm == nullptr) {
+ return INVALID_OPERATION;
+ }
+
+ bool registered = false;
+ Return<void> ret = service->interfaceChain([&](const auto& chain) {
+ registered = sm->addWithChain(name.c_str(), service, chain).withDefault(false);
+ });
+
+ if (!ret.isOk()) {
+ LOG(ERROR) << "Could not retrieve interface chain: " << ret.description();
+ }
+
+ if (registered) {
+ onRegistrationImpl(getDescriptor(service.get()), name);
+ }
+
+ return registered ? OK : UNKNOWN_ERROR;
+}
+
+} // namespace details
-}; // namespace hardware
-}; // namespace android
+} // namespace hardware
+} // namespace android
diff --git a/transport/Static.cpp b/transport/Static.cpp
index a506644..af16e8f 100644
--- a/transport/Static.cpp
+++ b/transport/Static.cpp
@@ -17,6 +17,7 @@
// All static variables go here, to control initialization and
// destruction order in the library.
+#include <InternalStatic.h>
#include <hidl/Static.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
@@ -26,31 +27,29 @@ namespace android {
namespace hardware {
namespace details {
-Mutex gDefaultServiceManagerLock;
-sp<android::hidl::manager::V1_0::IServiceManager> gDefaultServiceManager;
-
// Deprecated; kept for ABI compatibility. Use getBnConstructorMap.
-BnConstructorMap gBnConstructorMap{};
+DoNotDestruct<BnConstructorMap> gBnConstructorMap{};
-ConcurrentMap<const ::android::hidl::base::V1_0::IBase*, wp<::android::hardware::BHwBinder>>
- gBnMap{};
+DoNotDestruct<ConcurrentMap<const ::android::hidl::base::V1_0::IBase*,
+ wp<::android::hardware::BHwBinder>>>
+ gBnMap{};
// TODO(b/122472540): replace with single, hidden map
-ConcurrentMap<wp<::android::hidl::base::V1_0::IBase>, SchedPrio> gServicePrioMap{};
-ConcurrentMap<wp<::android::hidl::base::V1_0::IBase>, bool> gServiceSidMap{};
+DoNotDestruct<ConcurrentMap<wp<::android::hidl::base::V1_0::IBase>, SchedPrio>> gServicePrioMap{};
+DoNotDestruct<ConcurrentMap<wp<::android::hidl::base::V1_0::IBase>, bool>> gServiceSidMap{};
// Deprecated; kept for ABI compatibility. Use getBsConstructorMap.
-BsConstructorMap gBsConstructorMap{};
+DoNotDestruct<BsConstructorMap> gBsConstructorMap{};
// For static executables, it is not guaranteed that gBnConstructorMap are initialized before
// used in HAL definition libraries.
BnConstructorMap& getBnConstructorMap() {
- static BnConstructorMap map{};
+ static BnConstructorMap& map = *new BnConstructorMap();
return map;
}
BsConstructorMap& getBsConstructorMap() {
- static BsConstructorMap map{};
+ static BsConstructorMap& map = *new BsConstructorMap();
return map;
}
diff --git a/transport/allocator/1.0/default/Android.bp b/transport/allocator/1.0/default/Android.bp
index fc352c3..1fdfb26 100644
--- a/transport/allocator/1.0/default/Android.bp
+++ b/transport/allocator/1.0/default/Android.bp
@@ -21,6 +21,7 @@ cc_binary {
"service.cpp"
],
init_rc: ["android.hidl.allocator@1.0-service.rc"],
+ vintf_fragments: ["android.hidl.allocator@1.0-service.xml"],
shared_libs: [
"android.hidl.allocator@1.0",
diff --git a/transport/allocator/1.0/default/AshmemAllocator.cpp b/transport/allocator/1.0/default/AshmemAllocator.cpp
index 0bd4f81..5cc2eea 100644
--- a/transport/allocator/1.0/default/AshmemAllocator.cpp
+++ b/transport/allocator/1.0/default/AshmemAllocator.cpp
@@ -36,8 +36,8 @@ static hidl_memory allocateOne(uint64_t size) {
native_handle_t* handle = native_handle_create(1, 0);
handle->data[0] = fd;
- LOG(WARNING) << "ashmem_create_region(" << size << ") returning hidl_memory(" << handle
- << ", " << size << ")";
+ LOG(VERBOSE) << "ashmem_create_region(" << size << ") returning hidl_memory(" << handle << ", "
+ << size << ")";
return hidl_memory("ashmem", handle, size);
}
diff --git a/transport/allocator/1.0/default/android.hidl.allocator@1.0-service.xml b/transport/allocator/1.0/default/android.hidl.allocator@1.0-service.xml
new file mode 100644
index 0000000..5218241
--- /dev/null
+++ b/transport/allocator/1.0/default/android.hidl.allocator@1.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="framework">
+ <hal>
+ <name>android.hidl.allocator</name>
+ <transport>hwbinder</transport>
+ <version>1.0</version>
+ <interface>
+ <name>IAllocator</name>
+ <instance>ashmem</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/transport/allocator/1.0/utils/Android.bp b/transport/allocator/1.0/utils/Android.bp
index b1a3f41..9f70963 100644
--- a/transport/allocator/1.0/utils/Android.bp
+++ b/transport/allocator/1.0/utils/Android.bp
@@ -18,6 +18,7 @@ cc_library {
vndk: {
enabled: true,
},
+ double_loadable: true,
defaults: ["libhidl-defaults"],
shared_libs: [
"libbinder",
diff --git a/transport/allocator/1.0/vts/functional/Android.bp b/transport/allocator/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..797d3f8
--- /dev/null
+++ b/transport/allocator/1.0/vts/functional/Android.bp
@@ -0,0 +1,28 @@
+//
+// Copyright (C) 2018 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_test {
+ name: "VtsHidlAllocatorV1_0TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHidlAllocatorV1_0TargetTest.cpp"],
+ shared_libs: [
+ "libhidlmemory",
+ ],
+ static_libs: [
+ "android.hidl.allocator@1.0",
+ ],
+}
+
diff --git a/transport/allocator/1.0/vts/functional/Android.mk b/transport/allocator/1.0/vts/functional/Android.mk
new file mode 100644
index 0000000..62880ed
--- /dev/null
+++ b/transport/allocator/1.0/vts/functional/Android.mk
@@ -0,0 +1,22 @@
+#
+# Copyright (C) 2018 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := VtsHidlAllocatorV1_0Target
+-include test/vts/tools/build/Android.host_config.mk
diff --git a/transport/allocator/1.0/vts/functional/AndroidTest.xml b/transport/allocator/1.0/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..6ac167f
--- /dev/null
+++ b/transport/allocator/1.0/vts/functional/AndroidTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="Config for VTS VtsHidlAllocatorV1_0Target test cases">
+ <option name="config-descriptor:metadata" key="plan" value="vts-treble" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="abort-on-push-failure" value="false"/>
+ <option name="push-group" value="HalHidlTargetTest.push"/>
+ </target_preparer>
+ <multi_target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer" />
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="VtsHidlAllocatorV1_0Target"/>
+ <option name="binary-test-working-directory" value="_32bit::/data/nativetest/" />
+ <option name="binary-test-working-directory" value="_64bit::/data/nativetest64/" />
+ <option name="binary-test-source" value="_32bit::DATA/nativetest/VtsHidlAllocatorV1_0TargetTest/VtsHidlAllocatorV1_0TargetTest" />
+ <option name="binary-test-source" value="_64bit::DATA/nativetest64/VtsHidlAllocatorV1_0TargetTest/VtsHidlAllocatorV1_0TargetTest" />
+ <option name="binary-test-type" value="hal_hidl_gtest"/>
+ <option name="test-timeout" value="5m"/>
+ </test>
+</configuration>
diff --git a/transport/allocator/1.0/vts/functional/VtsHidlAllocatorV1_0TargetTest.cpp b/transport/allocator/1.0/vts/functional/VtsHidlAllocatorV1_0TargetTest.cpp
new file mode 100644
index 0000000..39ce606
--- /dev/null
+++ b/transport/allocator/1.0/vts/functional/VtsHidlAllocatorV1_0TargetTest.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2018 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 <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <android-base/logging.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+
+#define ASSERT_OK(ret) ASSERT_TRUE((ret).isOk())
+#define EXPECT_OK(ret) EXPECT_TRUE((ret).isOk())
+
+class AllocatorEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ virtual void registerTestServices() override { registerTestService<IAllocator>(); }
+
+ static AllocatorEnvironment* instance() {
+ static AllocatorEnvironment* instance = new AllocatorEnvironment();
+ return instance;
+ };
+};
+
+class AllocatorHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ allocator = getService<IAllocator>(AllocatorEnvironment::instance());
+ ASSERT_NE(allocator, nullptr);
+ }
+
+ sp<IMemory> expectAllocateSuccess(size_t size) {
+ sp<IMemory> memory;
+ EXPECT_OK(allocator->allocate(size, [&](bool success, const hidl_memory& mem) {
+ ASSERT_TRUE(success) << "Allocate failed for size: " << size;
+ EXPECT_EQ(mem.size(), size)
+ << "Allocated " << size << " but got hidl_memory with size " << mem.size();
+ memory = mapMemory(mem);
+ }));
+ EXPECT_NE(nullptr, memory.get());
+ EXPECT_EQ(memory->getSize(), size)
+ << "Allocated " << size << " but got IMemory with size " << memory->getSize();
+ return memory;
+ }
+
+ std::vector<sp<IMemory>> expectBatchAllocateSuccess(size_t size, size_t count) {
+ std::vector<sp<IMemory>> memories;
+ memories.reserve(count);
+ EXPECT_OK(allocator->batchAllocate(
+ size, count, [&](bool success, const hidl_vec<hidl_memory>& mems) {
+ EXPECT_EQ(count, mems.size());
+
+ for (const hidl_memory& mem : mems) {
+ ASSERT_TRUE(success) << "Allocate failed for size: " << size;
+ EXPECT_EQ(mem.size(), size)
+ << "Allocated " << size << " but got hidl_memory with size " << mem.size();
+ memories.push_back(mapMemory(mem));
+ }
+ }));
+ for (const sp<IMemory>& memory : memories) {
+ EXPECT_NE(nullptr, memory.get());
+ EXPECT_EQ(memory->getSize(), size)
+ << "Allocated " << size << " but got IMemory with size " << memory->getSize();
+ }
+ return memories;
+ }
+
+ sp<IAllocator> allocator;
+};
+
+TEST_F(AllocatorHidlTest, TestAllocateSizes) {
+ for (size_t size : {1, 1023, 1024, 1025, 4096}) {
+ expectAllocateSuccess(size);
+ }
+}
+
+TEST_F(AllocatorHidlTest, TestBatchAllocateSizes) {
+ for (size_t count : {1, 1, 2, 3, 10}) {
+ for (size_t size : {1, 1023, 1024, 1025, 4096}) {
+ expectBatchAllocateSuccess(size, count);
+ }
+ }
+}
+
+TEST_F(AllocatorHidlTest, TestCommit) {
+ constexpr size_t kSize = 1337;
+
+ sp<IMemory> memory = expectAllocateSuccess(kSize);
+ for (int i = 0; i < 100; i++) {
+ EXPECT_OK(memory->read());
+ EXPECT_OK(memory->update());
+ EXPECT_OK(memory->commit());
+
+ EXPECT_OK(memory->read());
+ EXPECT_OK(memory->commit());
+
+ EXPECT_OK(memory->update());
+ EXPECT_OK(memory->commit());
+ }
+
+ for (int i = 0; i < kSize; i++) {
+ EXPECT_OK(memory->readRange(i, kSize));
+ EXPECT_OK(memory->updateRange(i, kSize));
+ EXPECT_OK(memory->commit());
+
+ EXPECT_OK(memory->readRange(i, kSize));
+ EXPECT_OK(memory->commit());
+
+ EXPECT_OK(memory->updateRange(i, kSize));
+ EXPECT_OK(memory->commit());
+ }
+}
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(AllocatorEnvironment::instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ AllocatorEnvironment::instance()->init(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/transport/base/1.0/Android.bp b/transport/base/1.0/Android.bp
index bd2ae49..cebb01b 100644
--- a/transport/base/1.0/Android.bp
+++ b/transport/base/1.0/Android.bp
@@ -3,7 +3,6 @@
hidl_interface {
name: "android.hidl.base@1.0",
root: "android.hidl",
- core_interface: true,
vndk: {
enabled: true,
},
@@ -11,9 +10,6 @@ hidl_interface {
"types.hal",
"IBase.hal",
],
- types: [
- "DebugInfo",
- ],
gen_java: true,
}
diff --git a/transport/base/1.0/IBase.hal b/transport/base/1.0/IBase.hal
index e862ec8..22007f0 100644
--- a/transport/base/1.0/IBase.hal
+++ b/transport/base/1.0/IBase.hal
@@ -87,7 +87,10 @@ interface IBase {
linkToDeath(death_recipient recipient, uint64_t cookie) generates (bool success);
/*
- * Unregisters a previously registered death recipient.
+ * Unregisters the registered death recipient. If this service was registered
+ * multiple times with the same exact death recipient, this unlinks the most
+ * recently registered one.
+ *
* @param recipient a previously registered hidl_death_recipient callback
* @return success whether the death recipient was unregistered successfully.
*/
diff --git a/transport/current.txt b/transport/current.txt
index a48233c..2abf6f7 100644
--- a/transport/current.txt
+++ b/transport/current.txt
@@ -21,4 +21,13 @@ bddab6184d7a346da6a07dc0828cf19a696f4caa3611c51f2e14565a14b40fd9 android.hidl.ba
2e19301ceb87fb0696cd8268fab9c41f95d23c7392d35bc575daaa6eb32807eb android.hidl.memory.token@1.0::IMemoryToken
# ABI preserving changes to HALs during Android Q
+85394f8a0d15e7fb2ee45c52d1fb8b8fd3c13c333e63c78c4aa1ff86840cf6dc android.hidl.manager@1.0::IServiceManager
fcde1d0788066a62d5766f4dc19d4c1ec76967d5ddb636f59ccc66603460bcf8 android.hidl.manager@1.0::IServiceNotification
+
+# Clarification for b/67503915
+ec7fd79ed02dfa85bc499426adae3ebe23ef0524f3cd6957139324b83b18ca4c android.hidl.base@1.0::IBase
+
+# HALs released in Android Q
+a570fd436aed5eeeea2495b9267e7f9c4808d51efd4c9ba0913b9102eb93aeed android.hidl.manager@1.2::IClientCallback
+6f3a8a3fd4bfbd02e4e61c732d2df616ff69434a1ed83cda337303adc6d714df android.hidl.manager@1.2::IServiceManager
+b1c4fbdebe6d0def9b4f63aa83a0641f694fd5732ad32881a57fe12d5310a259 android.hidl.safe_union@1.0::types
diff --git a/transport/include/hidl/ConcurrentMap.h b/transport/include/hidl/ConcurrentMap.h
index 1b06dfd..329752c 100644
--- a/transport/include/hidl/ConcurrentMap.h
+++ b/transport/include/hidl/ConcurrentMap.h
@@ -90,6 +90,23 @@ public:
std::map<K, V> mMap;
};
+namespace details {
+
+// TODO(b/69122224): remove this type and usages of it
+// DO NOT ADD USAGES
+template <typename T>
+class DoNotDestruct {
+ public:
+ DoNotDestruct() { new (buffer) T(); }
+ T& get() { return *reinterpret_cast<T*>(buffer); }
+ T* operator->() { return reinterpret_cast<T*>(buffer); }
+
+ private:
+ alignas(T) char buffer[sizeof(T)];
+};
+
+} // namespace details
+
} // namespace hardware
} // namespace android
diff --git a/transport/include/hidl/HidlBinderSupport.h b/transport/include/hidl/HidlBinderSupport.h
index 9759af1..a098805 100644
--- a/transport/include/hidl/HidlBinderSupport.h
+++ b/transport/include/hidl/HidlBinderSupport.h
@@ -24,11 +24,10 @@
#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportUtils.h>
#include <hidl/MQDescriptor.h>
-#include <hidl/Static.h>
#include <hwbinder/IBinder.h>
-#include <hwbinder/IPCThreadState.h>
#include <hwbinder/Parcel.h>
-#include <hwbinder/ProcessState.h>
+#include <log/log.h> // TODO(b/65843592): remove. Too many users depending on this transitively.
+
// Defines functions for hidl_string, hidl_version, Status, hidl_vec, MQDescriptor,
// etc. to interact with Parcel.
@@ -49,6 +48,14 @@ private:
wp<::android::hidl::base::V1_0::IBase> mBase;
};
+// ---------------------- hidl_handle
+
+status_t readEmbeddedFromParcel(const hidl_handle &handle,
+ const Parcel &parcel, size_t parentHandle, size_t parentOffset);
+
+status_t writeEmbeddedToParcel(const hidl_handle &handle,
+ Parcel *parcel, size_t parentHandle, size_t parentOffset);
+
// ---------------------- hidl_memory
status_t readEmbeddedFromParcel(const hidl_memory &memory,
@@ -301,6 +308,10 @@ static status_t writeReferenceToParcel(
// ---------------------- support for casting interfaces
+// Constructs a binder for this interface and caches it. If it has already been created
+// then it returns it.
+sp<IBinder> getOrCreateCachedBinder(::android::hidl::base::V1_0::IBase* ifacePtr);
+
// Construct a smallest possible binder from the given interface.
// If it is remote, then its remote() will be retrieved.
// Otherwise, the smallest possible BnChild is found where IChild is a subclass of IType
@@ -310,43 +321,7 @@ template <typename IType,
typename = std::enable_if_t<std::is_same<details::i_tag, typename IType::_hidl_tag>::value>>
sp<IBinder> toBinder(sp<IType> iface) {
IType *ifacePtr = iface.get();
- if (ifacePtr == nullptr) {
- return nullptr;
- }
- if (ifacePtr->isRemote()) {
- return ::android::hardware::IInterface::asBinder(
- static_cast<BpInterface<IType>*>(ifacePtr));
- } else {
- std::string myDescriptor = details::getDescriptor(ifacePtr);
- if (myDescriptor.empty()) {
- // interfaceDescriptor fails
- return nullptr;
- }
-
- // for get + set
- std::unique_lock<std::mutex> _lock = details::gBnMap.lock();
-
- wp<BHwBinder> wBnObj = details::gBnMap.getLocked(ifacePtr, nullptr);
- sp<IBinder> sBnObj = wBnObj.promote();
-
- if (sBnObj == nullptr) {
- auto func = details::getBnConstructorMap().get(myDescriptor, nullptr);
- if (!func) {
- func = details::gBnConstructorMap.get(myDescriptor, nullptr);
- if (!func) {
- return nullptr;
- }
- }
-
- sBnObj = sp<IBinder>(func(static_cast<void*>(ifacePtr)));
-
- if (sBnObj != nullptr) {
- details::gBnMap.setLocked(ifacePtr, static_cast<BHwBinder*>(sBnObj.get()));
- }
- }
-
- return sBnObj;
- }
+ return getOrCreateCachedBinder(ifacePtr);
}
template <typename IType, typename ProxyType, typename StubType>
@@ -374,6 +349,8 @@ void joinBinderRpcThreadpool();
int setupBinderPolling();
status_t handleBinderPoll();
+void addPostCommandTask(const std::function<void(void)> task);
+
} // namespace hardware
} // namespace android
diff --git a/transport/include/hidl/HidlLazyUtils.h b/transport/include/hidl/HidlLazyUtils.h
new file mode 100644
index 0000000..2205daa
--- /dev/null
+++ b/transport/include/hidl/HidlLazyUtils.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <android/hidl/base/1.0/IBase.h>
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace hardware {
+namespace details {
+class LazyServiceRegistrarImpl;
+} // namespace details
+
+/** Exits when all HALs registered through this object have 0 clients */
+class LazyServiceRegistrar {
+ public:
+ LazyServiceRegistrar();
+ status_t registerService(const sp<::android::hidl::base::V1_0::IBase>& service,
+ const std::string& name = "default");
+
+ private:
+ std::shared_ptr<details::LazyServiceRegistrarImpl> mImpl;
+};
+
+} // namespace hardware
+} // namespace android
diff --git a/transport/include/hidl/HidlTransportSupport.h b/transport/include/hidl/HidlTransportSupport.h
index cdcb03e..a132bfa 100644
--- a/transport/include/hidl/HidlTransportSupport.h
+++ b/transport/include/hidl/HidlTransportSupport.h
@@ -84,18 +84,6 @@ status_t handleTransportPoll(int fd);
bool setMinSchedulerPolicy(const sp<::android::hidl::base::V1_0::IBase>& service,
int policy, int priority);
-template <typename ILeft,
- typename IRight,
- typename = std::enable_if_t<std::is_same<details::i_tag, typename ILeft::_hidl_tag>::value>,
- typename = std::enable_if_t<std::is_same<details::i_tag, typename IRight::_hidl_tag>::value>>
-bool interfacesEqual(sp<ILeft> left, sp<IRight> right) {
- if (left == nullptr || right == nullptr || !left->isRemote() || !right->isRemote()) {
- return left == right;
- }
-
- return toBinder<ILeft>(left) == toBinder<IRight>(right);
-}
-
/**
* Sets whether or not this object should request security contexts to be populatd for incoming
* calls (e.g. with getCallingSid).
@@ -108,6 +96,14 @@ bool interfacesEqual(sp<ILeft> left, sp<IRight> right) {
*/
bool setRequestingSid(const sp<::android::hidl::base::V1_0::IBase>& service, bool requesting);
+/**
+ * Returns whether two interfaces represent the same interface. References to interfaces in the same
+ * process will always be equivalent. However, in order to compare a service that is a proxy to a
+ * different process, its underlying structure may have to be checked.
+ */
+bool interfacesEqual(const sp<::android::hidl::base::V1_0::IBase>& left,
+ const sp<::android::hidl::base::V1_0::IBase>& right);
+
namespace details {
// Return PID on userdebug / eng builds and IServiceManager::PidConstant::NO_PID on user builds.
@@ -141,7 +137,7 @@ Return<sp<IChild>> castInterface(sp<IParent> parent, const char* childIndicator,
// TODO b/32001926 Needs to be fixed for socket mode.
if (parent->isRemote()) {
// binderized mode. Got BpChild. grab the remote and wrap it.
- return sp<IChild>(new BpChild(toBinder<IParent>(parent)));
+ return sp<IChild>(new BpChild(getOrCreateCachedBinder(parent.get())));
}
// Passthrough mode. Got BnChild or BsChild.
return sp<IChild>(static_cast<IChild *>(parent.get()));
@@ -161,7 +157,7 @@ sp<IType> getServiceInternal(const std::string& instance, bool retry, bool getSt
if (base->isRemote()) {
// getRawServiceInternal guarantees we get the proper class
- return sp<IType>(new BpType(toBinder<IBase>(base)));
+ return sp<IType>(new BpType(getOrCreateCachedBinder(base.get())));
}
return IType::castFrom(base);
diff --git a/transport/include/hidl/LegacySupport.h b/transport/include/hidl/LegacySupport.h
index f03d34d..1e983eb 100644
--- a/transport/include/hidl/LegacySupport.h
+++ b/transport/include/hidl/LegacySupport.h
@@ -14,25 +14,21 @@
* limitations under the License.
*/
+#include <hidl/HidlLazyUtils.h>
#include <hidl/HidlTransportSupport.h>
#include <sys/wait.h>
-#include <utils/Log.h>
#include <utils/Errors.h>
+#include <utils/Log.h>
#include <utils/StrongPointer.h>
-#ifndef ANDROID_HIDL_LEGACY_SUPPORT_H
-#define ANDROID_HIDL_LEGACY_SUPPORT_H
+#pragma once
namespace android {
namespace hardware {
-
-/**
- * Registers passthrough service implementation.
- */
-template<class Interface>
-__attribute__((warn_unused_result))
-status_t registerPassthroughServiceImplementation(
- std::string name = "default") {
+namespace details {
+template <class Interface, typename Func>
+__attribute__((warn_unused_result)) status_t registerPassthroughServiceImplementation(
+ Func registerServiceCb, const std::string& name = "default") {
sp<Interface> service = Interface::getService(name, true /* getStub */);
if (service == nullptr) {
@@ -44,7 +40,7 @@ status_t registerPassthroughServiceImplementation(
LOG_FATAL_IF(service->isRemote(), "Implementation of %s/%s is remote!",
Interface::descriptor, name.c_str());
- status_t status = service->registerAsService(name);
+ status_t status = registerServiceCb(service, name);
if (status == OK) {
ALOGI("Registration complete for %s/%s.",
@@ -56,16 +52,29 @@ status_t registerPassthroughServiceImplementation(
return status;
}
+} // namespace details
+
+/**
+ * Registers passthrough service implementation.
+ */
+template <class Interface>
+__attribute__((warn_unused_result)) status_t registerPassthroughServiceImplementation(
+ const std::string& name = "default") {
+ return details::registerPassthroughServiceImplementation<Interface>(
+ [](const sp<Interface>& service, const std::string& name) {
+ return service->registerAsService(name);
+ },
+ name);
+}
/**
* Creates default passthrough service implementation. This method never returns.
*
* Return value is exit status.
*/
-template<class Interface>
-__attribute__((warn_unused_result))
-status_t defaultPassthroughServiceImplementation(std::string name,
- size_t maxThreads = 1) {
+template <class Interface>
+__attribute__((warn_unused_result)) status_t defaultPassthroughServiceImplementation(
+ const std::string& name, size_t maxThreads = 1) {
configureRpcThreadpool(maxThreads, true);
status_t result = registerPassthroughServiceImplementation<Interface>(name);
@@ -82,7 +91,54 @@ status_t defaultPassthroughServiceImplementation(size_t maxThreads = 1) {
return defaultPassthroughServiceImplementation<Interface>("default", maxThreads);
}
+/**
+ * Registers a passthrough service implementation that exits when there are 0 clients.
+ *
+ * If this function is called multiple times to register different services, then this process will
+ * only exit once all services have 0 clients. This function does not know about clients registered
+ * through registerPassthroughServiceImplementation, so if that function is used in conjunction with
+ * this one, the process may exit while a client is still using the HAL.
+ */
+template <class Interface>
+__attribute__((warn_unused_result)) status_t registerLazyPassthroughServiceImplementation(
+ const std::string& name = "default") {
+ // Make LazyServiceRegistrar static so that multiple calls to
+ // registerLazyPassthroughServiceImplementation work as expected: each HAL is registered and the
+ // process only exits once all HALs have 0 clients.
+ using android::hardware::LazyServiceRegistrar;
+ static auto serviceCounter(std::make_shared<LazyServiceRegistrar>());
+
+ return details::registerPassthroughServiceImplementation<Interface>(
+ [](const sp<Interface>& service, const std::string& name) {
+ return serviceCounter->registerService(service, name);
+ },
+ name);
+}
+
+/**
+ * Creates default passthrough service implementation that exits when there are 0 clients. This
+ * method never returns.
+ *
+ * Return value is exit status.
+ */
+template <class Interface>
+__attribute__((warn_unused_result)) status_t defaultLazyPassthroughServiceImplementation(
+ const std::string& name, size_t maxThreads = 1) {
+ configureRpcThreadpool(maxThreads, true);
+ status_t result = registerLazyPassthroughServiceImplementation<Interface>(name);
+
+ if (result != OK) {
+ return result;
+ }
+
+ joinRpcThreadpool();
+ return UNKNOWN_ERROR;
+}
+template <class Interface>
+__attribute__((warn_unused_result)) status_t defaultLazyPassthroughServiceImplementation(
+ size_t maxThreads = 1) {
+ return defaultLazyPassthroughServiceImplementation<Interface>("default", maxThreads);
+}
+
} // namespace hardware
} // namespace android
-
-#endif // ANDROID_HIDL_LEGACY_SUPPORT_H
diff --git a/transport/include/hidl/ServiceManagement.h b/transport/include/hidl/ServiceManagement.h
index 4df156b..a962034 100644
--- a/transport/include/hidl/ServiceManagement.h
+++ b/transport/include/hidl/ServiceManagement.h
@@ -28,21 +28,21 @@ namespace hidl {
namespace manager {
namespace V1_0 {
struct IServiceManager;
-}; // namespace V1_0
+} // namespace V1_0
namespace V1_1 {
- struct IServiceManager;
-}; // namespace V1_0
-}; // namespace manager
-}; // namespace hidl
+struct IServiceManager;
+} // namespace V1_1
+namespace V1_2 {
+struct IServiceManager;
+} // namespace V1_2
+} // namespace manager
+} // namespace hidl
namespace hardware {
namespace details {
-// e.x.: android.hardware.foo@1.0, IFoo, default
-void onRegistration(const std::string &packageName,
- const std::string &interfaceName,
- const std::string &instanceName);
+// Will not attempt to start a lazy HAL
// e.x.: android.hardware.foo@1.0::IFoo, default
void waitForHwService(const std::string &interface, const std::string &instanceName);
@@ -57,12 +57,16 @@ void preloadPassthroughService(const std::string &descriptor);
sp<::android::hidl::base::V1_0::IBase> getRawServiceInternal(const std::string& descriptor,
const std::string& instance,
bool retry, bool getStub);
-};
+
+status_t registerAsServiceInternal(const sp<::android::hidl::base::V1_0::IBase>& service,
+ const std::string& name);
+} // namespace details
// These functions are for internal use by hidl. If you want to get ahold
// of an interface, the best way to do this is by calling IFoo::getService()
sp<::android::hidl::manager::V1_0::IServiceManager> defaultServiceManager();
sp<::android::hidl::manager::V1_1::IServiceManager> defaultServiceManager1_1();
+sp<::android::hidl::manager::V1_2::IServiceManager> defaultServiceManager1_2();
sp<::android::hidl::manager::V1_0::IServiceManager> getPassthroughServiceManager();
sp<::android::hidl::manager::V1_1::IServiceManager> getPassthroughServiceManager1_1();
@@ -77,8 +81,8 @@ static inline void preloadPassthroughService() {
details::preloadPassthroughService(I::descriptor);
}
-}; // namespace hardware
-}; // namespace android
+} // namespace hardware
+} // namespace android
#endif // ANDROID_HARDWARE_ISERVICE_MANAGER_H
diff --git a/transport/include/hidl/Static.h b/transport/include/hidl/Static.h
index b15be68..be74bae 100644
--- a/transport/include/hidl/Static.h
+++ b/transport/include/hidl/Static.h
@@ -17,6 +17,9 @@
// All static variables go here, to control initialization and
// destruction order in the library.
+#ifndef ANDROID_HARDWARE_HIDL_STATIC_H
+#define ANDROID_HARDWARE_HIDL_STATIC_H
+
#include <functional>
#include <android/hidl/base/1.0/IBase.h>
@@ -34,19 +37,22 @@ struct SchedPrio {
int prio;
};
-extern ConcurrentMap<wp<::android::hidl::base::V1_0::IBase>, SchedPrio> gServicePrioMap;
-extern ConcurrentMap<wp<::android::hidl::base::V1_0::IBase>, bool> gServiceSidMap;
+// TODO(b/69122224): remove this
+extern DoNotDestruct<ConcurrentMap<wp<::android::hidl::base::V1_0::IBase>, SchedPrio>>
+ gServicePrioMap;
+// TODO(b/69122224): remove this
+extern DoNotDestruct<ConcurrentMap<wp<::android::hidl::base::V1_0::IBase>, bool>> gServiceSidMap;
+// TODO(b/69122224): remove this
// For HidlBinderSupport and autogenerated code
-extern ConcurrentMap<const ::android::hidl::base::V1_0::IBase*, wp<::android::hardware::BHwBinder>>
- gBnMap;
+extern DoNotDestruct<ConcurrentMap<const ::android::hidl::base::V1_0::IBase*,
+ wp<::android::hardware::BHwBinder>>>
+ gBnMap;
using BnConstructorMap = ConcurrentMap<std::string, std::function<sp<IBinder>(void*)>>;
// For HidlBinderSupport and autogenerated code
// value function receives reinterpret_cast<void *>(static_cast<IFoo *>(foo)),
// returns sp<IBinder>
-// deprecated; use getBnConstructorMap instead.
-extern BnConstructorMap gBnConstructorMap;
BnConstructorMap& getBnConstructorMap();
using BsConstructorMap = ConcurrentMap<std::string,
@@ -54,9 +60,9 @@ using BsConstructorMap = ConcurrentMap<std::string,
// For HidlPassthroughSupport and autogenerated code
// value function receives reinterpret_cast<void *>(static_cast<IFoo *>(foo)),
// returns sp<IBase>
-// deprecated; use getBsConstructorMap instead.
-extern BsConstructorMap gBsConstructorMap;
BsConstructorMap& getBsConstructorMap();
} // namespace details
} // namespace hardware
} // namespace android
+
+#endif
diff --git a/transport/manager/1.0/Android.bp b/transport/manager/1.0/Android.bp
index e4a120b..869c58e 100644
--- a/transport/manager/1.0/Android.bp
+++ b/transport/manager/1.0/Android.bp
@@ -3,7 +3,6 @@
hidl_interface {
name: "android.hidl.manager@1.0",
root: "android.hidl",
- core_interface: true,
vndk: {
enabled: true,
},
diff --git a/transport/manager/1.0/IServiceManager.hal b/transport/manager/1.0/IServiceManager.hal
index 2b59a56..6eddefb 100644
--- a/transport/manager/1.0/IServiceManager.hal
+++ b/transport/manager/1.0/IServiceManager.hal
@@ -43,7 +43,7 @@ interface IServiceManager {
* WARNING: This function is for libhidl/HwBinder use only. You are likely
* looking for 'IMyInterface::getService("name")' instead.
*
- * @param iface Fully-qualified interface name.
+ * @param fqName Fully-qualified interface name.
* @param name Instance name. Same as in IServiceManager::add.
*
* @return service Handle to requested service, same as provided in
diff --git a/transport/manager/1.1/Android.bp b/transport/manager/1.1/Android.bp
index cde68a7..407dfa3 100644
--- a/transport/manager/1.1/Android.bp
+++ b/transport/manager/1.1/Android.bp
@@ -3,7 +3,6 @@
hidl_interface {
name: "android.hidl.manager@1.1",
root: "android.hidl",
- core_interface: true,
vndk: {
enabled: true,
},
diff --git a/transport/manager/1.2/Android.bp b/transport/manager/1.2/Android.bp
new file mode 100644
index 0000000..3f02f78
--- /dev/null
+++ b/transport/manager/1.2/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hidl.manager@1.2",
+ root: "android.hidl",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "IClientCallback.hal",
+ "IServiceManager.hal",
+ ],
+ interfaces: [
+ "android.hidl.base@1.0",
+ "android.hidl.manager@1.0",
+ "android.hidl.manager@1.1",
+ ],
+ gen_java: true,
+}
+
diff --git a/transport/manager/1.2/IClientCallback.hal b/transport/manager/1.2/IClientCallback.hal
new file mode 100644
index 0000000..8ebb044
--- /dev/null
+++ b/transport/manager/1.2/IClientCallback.hal
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package android.hidl.manager@1.2;
+
+interface IClientCallback {
+ /**
+ * This is called when there is a transition between having >= 1 clients and having 0 clients
+ * (or vice versa).
+ *
+ * Upon receiving hasClients false, if the process decides to exit, it is recommended to try to
+ * unregister using @1.2::IServiceManager's tryUnregister before quiting in case another client
+ * associates.
+ *
+ * @param registered binder 'server' registered with IServiceManager's registerClientCallback
+ * @param hasClients whether there are currently clients
+ * true - when there are >= 1 clients. This must be called as soon as IServiceManager::get
+ * is called (no race).
+ * false - when there are 0 clients. This may be delayed if it is thought that another
+ * may be used again soon.
+ */
+ oneway onClients(interface registered, bool hasClients);
+};
diff --git a/transport/manager/1.2/IServiceManager.hal b/transport/manager/1.2/IServiceManager.hal
new file mode 100644
index 0000000..d79403d
--- /dev/null
+++ b/transport/manager/1.2/IServiceManager.hal
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package android.hidl.manager@1.2;
+
+import @1.1::IServiceManager;
+
+import IClientCallback;
+
+interface IServiceManager extends @1.1::IServiceManager {
+ /**
+ * Adds a callback that must be called when the specified server has no clients.
+ *
+ * If the service has clients at the time of registration, the callback is called with
+ * hasClients true. After that, it is called based on the changes in clientele.
+ *
+ * @param fqName Fully-qualified interface name (used to register)
+ * @param name Instance name (of the registered service)
+ * @param server non-null service waiting to have no clients (previously registered)
+ * @param cb non-null callback to call when there are no clients
+ * @return success
+ * true on success
+ * false if either
+ * - the server or cb parameters are null
+ * - this is called by a process other than the server process
+ */
+ registerClientCallback(string fqName,
+ string name,
+ interface server,
+ IClientCallback cb)
+ generates (bool success);
+
+ /**
+ * Removes a callback previously registered with registerClientCallback.
+ *
+ * If server is null, then this must remove the cb from all matching services.
+ *
+ * @param server service registered with registerClientCallback
+ * @param cb non-null callback to remove
+ * @return success
+ * true if the server(s) have been removed
+ * false if cb is null or if the client callback or server could not be found
+ */
+ unregisterClientCallback(interface server, IClientCallback cb) generates (bool success);
+
+ /**
+ * Exactly the same as @1.0::IServiceManager.add, but the interfaceChain of the service is
+ * provided in the same call.
+ *
+ * @param name Instance name. Must also be used to retrieve service.
+ * @param service Handle to registering service.
+ * @param chain service->interfaceChain
+ *
+ * @return success Whether or not the service was registered.
+ */
+ addWithChain(string name, interface service, vec<string> chain) generates (bool success);
+
+ /**
+ * List all instances of a particular service from the manifest. Must be sorted. These HALs
+ * may not be started if they are lazy.
+ *
+ * See also @1.0::IServiceManager's listByInterface function.
+ *
+ * @param fqName Fully-qualified interface name.
+ *
+ * @return instanceNames List of instance names running the particular service.
+ */
+ listManifestByInterface(string fqName) generates (vec<string> instanceNames);
+
+ /**
+ * Unregisters a service if there are no clients for it. This must only unregister the
+ * service if it is called from the same process that registered the service.
+ *
+ * This unregisters all instances of the service, even if they are under a different instance
+ * name.
+ *
+ * Recommended usage is when creating a lazy process, try unregistering when IClientCallback's
+ * onClients(*, false) is called. If this unregister is successful, then it is safe to exit. If
+ * it is unsuccessful, then you can assume a client re-associated with the server. If a process
+ * has multiple servers, and only some succeed in unregistration, then the unregistered services
+ * can be re-registered.
+ *
+ * See also addWithChain and @1.0::IServiceManager's add.
+ *
+ * @param fqName Fully-qualified interface name.
+ * @param name Instance name.
+ * @param service Handle to registering service.
+ *
+ * @return success Whether the service was successfully unregistered.
+ */
+ tryUnregister(string fqName, string name, interface service) generates (bool success);
+};
diff --git a/transport/safe_union/1.0/Android.bp b/transport/safe_union/1.0/Android.bp
new file mode 100644
index 0000000..88c7d5d
--- /dev/null
+++ b/transport/safe_union/1.0/Android.bp
@@ -0,0 +1,15 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hidl.safe_union@1.0",
+ root: "android.hidl",
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ srcs: [
+ "types.hal",
+ ],
+ gen_java: true,
+}
+
diff --git a/transport/safe_union/1.0/types.hal b/transport/safe_union/1.0/types.hal
new file mode 100644
index 0000000..bc3dbc2
--- /dev/null
+++ b/transport/safe_union/1.0/types.hal
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package android.hidl.safe_union@1.0;
+
+/**
+ * Unit type easily available to be used with safe_union.
+ *
+ * Example usage:
+ *
+ * safe_union MaybeFoo {
+ * Monostate no_init;
+ * Foo foo;
+ * };
+ */
+struct Monostate {};
diff --git a/transport/token/1.0/utils/Android.bp b/transport/token/1.0/utils/Android.bp
index fcb1613..cdbdd97 100644
--- a/transport/token/1.0/utils/Android.bp
+++ b/transport/token/1.0/utils/Android.bp
@@ -19,17 +19,18 @@ cc_library {
vndk: {
enabled: true,
},
+ double_loadable: true,
srcs: [
"HybridInterface.cpp",
],
shared_libs: [
- "libutils",
+ "android.hidl.token@1.0",
"libbinder",
- "liblog",
"libhidlbase",
- "android.hidl.token@1.0",
+ "liblog",
+ "libutils",
],
export_shared_lib_headers: [
diff --git a/transport/token/1.0/utils/include/hidl/HybridInterface.h b/transport/token/1.0/utils/include/hidl/HybridInterface.h
index 984555e..125d5e8 100644
--- a/transport/token/1.0/utils/include/hidl/HybridInterface.h
+++ b/transport/token/1.0/utils/include/hidl/HybridInterface.h
@@ -23,6 +23,9 @@
#include <binder/Parcel.h>
#include <hidl/HidlSupport.h>
+#include <cinttypes>
+#include <variant>
+
/**
* Hybrid Interfaces
* =================
@@ -47,50 +50,130 @@
*
* To demonstrate how this is done, here is an example. Suppose `INTERFACE` is
* `IFoo` and `HALINTERFACE` is `HFoo`. The required steps are:
- * 1. Use DECLARE_HYBRID_META_INTERFACE instead of DECLARE_META_INTERFACE in the
- * definition of `IFoo`. The usage is
- * DECLARE_HYBRID_META_INTERFACE(IFoo, HFoo)
- * inside the body of `IFoo`.
+ * 1. Use `DECLARE_HYBRID_META_INTERFACE` instead of `DECLARE_META_INTERFACE` in
+ * the declaration of `IFoo`. `DECLARE_HYBRID_META_INTERFACE` takes an
+ * additional argument that is the hidl interface to be converted into a
+ * binder interface. Example:
+ * Change from `DECLARE_META_INTERFACE(Foo)`
+ * to `DECLARE_HYBRID_META_INTERFACE(Foo, HFoo)`
* 2. Create a converter class that derives from
- * `H2BConverter<HFoo, IFoo, BnFoo>`. Let us call this `H2BFoo`.
+ * `H2BConverter<HFoo, BnFoo>`. Let us call this `H2BFoo`.
* 3. Add the following constructor in `H2BFoo` that call the corresponding
* constructors in `H2BConverter`:
- * H2BFoo(const sp<HalInterface>& base) : CBase(base) {}
- * Note: `CBase = H2BConverter<HFoo, IFoo, BnFoo>` and `HalInterface = HFoo`
- * are member typedefs of `H2BConverter<HFoo, IFoo, BnFoo>`, so the above
- * line can be copied into `H2BFoo`.
+ * `H2BFoo(const sp<HalInterface>& base) : CBase(base) {}`
+ * Note: `CBase = H2BConverter<HFoo, BnFoo>` and `HalInterface = HFoo` are
+ * member typedefs of `H2BConverter<HFoo, BnFoo>`, so the above line can be
+ * copied verbatim into `H2BFoo`.
* 4. Implement `IFoo` in `H2BFoo` on top of `HFoo`. `H2BConverter` provides a
* protected `mBase` of type `sp<HFoo>` that can be used to access the `HFoo`
- * instance. (There is also a public function named `getHalInterface()` that
- * returns `mBase`.)
+ * instance. (There is also a public function named `getBase()` that returns
+ * `mBase`.)
* 5. Create a hardware proxy class that derives from
* `HpInterface<BpFoo, H2BFoo>`. Name this class `HpFoo`. (This name cannot
* deviate. See step 8 below.)
* 6. Add the following constructor to `HpFoo`:
- * HpFoo(const sp<IBinder>& base): PBase(base) {}
+ * `HpFoo(const sp<IBinder>& base): PBase(base) {}`
* Note: `PBase` a member typedef of `HpInterface<BpFoo, H2BFoo>` that is
* equal to `HpInterface<BpFoo, H2BFoo>` itself, so the above line can be
* copied verbatim into `HpFoo`.
- * 7. Delegate all functions in `HpFoo` that come from `IFoo` except
- * `getHalInterface` to the protected member `mBase`,
- * which is defined in `HpInterface<BpFoo, H2BFoo>` (hence in `HpFoo`) with
- * type `IFoo`. (There is also a public function named `getBaseInterface()`
- * that returns `mBase`.)
- * 8. Replace the existing `IMPLEMENT_META_INTERFACE` for INTERFACE by
- * `IMPLEMENT_HYBRID_META_INTERFACE`. Note that this macro relies on the
- * exact naming of `HpFoo`, where `Foo` comes from the interface name `IFoo`.
- * An example usage is
- * IMPLEMENT_HYBRID_META_INTERFACE(IFoo, HFoo, "example.interface.foo");
+ * 7. Delegate all functions in `HpFoo` that come from `IFoo` (except those that
+ * are defined by the macro `DECLARE_HYBRID_META_INTERFACE`) to the protected
+ * member `mBase`. `mBase` is defined in `HpInterface<BpFoo, H2BFoo>` (hence
+ * in `HpFoo`) with type `IFoo`. There is also a public function named
+ * `getBase()` that returns `mBase`.
+ * 8. Replace the existing `IMPLEMENT_META_INTERFACE` for `IFoo` by
+ * `IMPLEMENT_HYBRID_META_INTERFACE`. This macro assumes that the subclass of
+ * `HpInterface` for `IFoo` is named `HpFoo`.
+ *
+ * After the hybrid interface has been put in place properly, it can be used to
+ * do the following tasks:
+ * 1. Create an `IFoo` instance from an `HFoo` by passing `sp<HFoo>` to
+ * the constructor of `H2BFoo`.
+ * 2. Retrieve an `HFoo` from an `HpFoo` instance by calling
+ * `HpFoo::getHalInterface<HFoo>()`. This function may return `nullptr` if
+ * the `HpFoo` object is not backed by `HFoo`. The template parameter is
+ * required because `HpFoo` in fact may be backed by multiple H2B converter
+ * classes.
+ *
+ * Multiple H2B Converters
+ * =======================
+ *
+ * Because the system may support multiple versions of hidl interfaces for the
+ * same object, one binder interface may correspond to multiple H2B converters.
+ * The hybrid interface is designed to handle this as
+ * well---`DECLARE_HYBRID_META_INTERFACE` and `HpInterface` can take a variable
+ * number of arguments.
+ *
+ * As a concrete example, suppose `IFoo` is a binder interface that corresponds
+ * to two hidl interfaces `HFoo1` and `HFoo2`. That means `HpFoo`, the hybrid
+ * interface presenting `IFoo`, may be backed by `HFoo1` or `HFoo2`. This is
+ * achievable by
+ *
+ * - Replacing `DECLARE_META_INTERFACE(Foo)` by
+ * `DECLARE_HYBRID_META_INTERFACE(Foo, HFoo1, HFoo2)` in the declaration of
+ * `IFoo`.
+ * - Creating `H2BFoo1` as a subclass of `H2BConverter<HFoo1, BnFoo>`;
+ * - Creating `H2BFoo2` as a subclass of `H2BConverter<HFoo2, BnFoo>`; and
+ * - Creating `HpFoo` as a subclass of `HpInterface<BpFoo, H2BFoo1, H2BFoo2>`.
+ *
+ * It is important that `HFoo1` and `HFoo2` are different hidl interfaces. [The
+ * actual requirement is that for each pair `<HFoo, IFoo>`, there can be only
+ * one subclass of `H2BConverter<HFoo, BnFoo>`.]
+ *
+ * As mentioned in the previous section, `HpFoo::getHalInterface` requires a
+ * template argument because it must be able to return different hidl
+ * interface types based on which hidl interface is being used. The user of
+ * `HpFoo` can query the type of the underlying hidl interface by calling
+ * `HpFoo::getHalIndex()`. The return value is a 1-based index into the list of
+ * all the supported hidl interfaces. In the example with 2 hidl interfaces
+ * `HFoo1` and `HFoo2`, index 1 corresponds to `HFoo1` and index 2 corresponds
+ * to `HFoo2`. A typical code block that accesses the underlying hidl interface
+ * of would look like this:
*
- * `GETTOKEN` Template Argument
- * ============================
+ * void someFunction(const sp<IFoo> &foo) {
*
- * Following the instructions above, `H2BConverter` and `HpInterface` would use
- * `transact()` to send over tokens, with `code` (the first argument of
- * `transact()`) equal to `DEFAULT_GET_HAL_TOKEN_TRANSACTION_CODE`. If this
- * value clashes with other values already in use in the `Bp` class, it can be
- * changed by supplying the last optional template argument to `H2BConverter`
- * and `HpInterface`.
+ * switch (foo->getHalIndex()) {
+ * case 1: {
+ * sp<HFoo1> hFoo1 = foo->getHalInterface<HFoo1>();
+ * ...
+ * break;
+ * }
+ * case 2: {
+ * sp<HFoo2> hFoo2 = foo->getHalInterface<HFoo2>();
+ * ...
+ * break;
+ * }
+ * default: // Not backed by a hidl interface.
+ * // Alternatively, "case 0:" can be used.
+ * }
+ *
+ * }
+ *
+ * Error State
+ * ===========
+ *
+ * A corrupted transaction may cause an `HpInterface` to be in an error state.
+ * This could cause `getHalInterface<ExpectedHalInterface>()` to return
+ * `nullptr` even though `getHalIndex()` returns a non-zero index and
+ * `ExpectedHalInterface` is the corresponding hidl interface. It is therefore
+ * recommended that a null check be performed on the return value of
+ * `getHalInterface` before using it.
+ *
+ * DECLARE_HYBRID_META_INTERFACE_WITH_CODE
+ * =======================================
+ *
+ * `H2BConverter` and `HpInterface` use `transact()` to send over tokens with
+ * the transaction code (the first argument of `transact()`) equal to `_GHT`,
+ * which is defined as a global constant named
+ * `DEFAULT_GET_HAL_TOKEN_TRANSACTION_CODE`.
+ *
+ * In the rare occasion that this value clashes with other values already used
+ * by the `Bp` class and modifying the `Bp` class is difficult, the
+ * "GET_HAL_TOKEN" transaction code can be changed to a different value simply
+ * by replacing `DECLARE_HYBRID_META_INTERFACE` with
+ * `DECLARE_HYBRID_META_INTERFACE_WITH_CODE` in the declaration of the base
+ * interface and supplying the new transaction code in the first argument of
+ * this macro.
*
*/
@@ -106,23 +189,19 @@ sp<HInterface> retrieveHalInterface(const HalToken& token);
bool createHalToken(const sp<HInterface>& interface, HalToken* token);
bool deleteHalToken(const HalToken& token);
-template <
- typename HINTERFACE,
- typename INTERFACE,
- typename BNINTERFACE,
- uint32_t GETTOKEN = DEFAULT_GET_HAL_TOKEN_TRANSACTION_CODE>
+template <typename HINTERFACE,
+ typename BNINTERFACE>
class H2BConverter : public BNINTERFACE {
public:
- typedef H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN> CBase; // Converter Base
- typedef INTERFACE BaseInterface;
+ typedef H2BConverter<HINTERFACE, BNINTERFACE> CBase; // Converter Base
+ typedef typename BNINTERFACE::BaseInterface BaseInterface;
typedef HINTERFACE HalInterface;
- static constexpr uint32_t GET_HAL_TOKEN = GETTOKEN;
+ typedef typename BaseInterface::HalVariant HalVariant;
+ using BaseInterface::sGetHalTokenTransactionCode;
- H2BConverter(const sp<HalInterface>& base) : mBase(base) {}
+ H2BConverter(const sp<HalInterface>& base) : mBase{base} {}
virtual status_t onTransact(uint32_t code,
const Parcel& data, Parcel* reply, uint32_t flags = 0);
- virtual sp<HalInterface> getHalInterface() { return mBase; }
- HalInterface* getBaseInterface() { return mBase.get(); }
virtual status_t linkToDeath(
const sp<IBinder::DeathRecipient>& recipient,
void* cookie = nullptr,
@@ -132,9 +211,13 @@ public:
void* cookie = nullptr,
uint32_t flags = 0,
wp<IBinder::DeathRecipient>* outRecipient = nullptr);
+ virtual HalVariant getHalVariant() const override { return { mBase }; }
+ HalInterface* getBase() { return mBase.get(); }
protected:
sp<HalInterface> mBase;
+
+private:
struct Obituary : public hardware::hidl_death_recipient {
wp<IBinder::DeathRecipient> recipient;
void* cookie;
@@ -168,102 +251,210 @@ protected:
};
std::mutex mObituariesLock;
std::vector<sp<Obituary> > mObituaries;
+
+ template <size_t Index = std::variant_size_v<HalVariant> - 1>
+ static constexpr size_t _findIndex() {
+ if constexpr (Index == 0) {
+ return Index;
+ } else if constexpr (
+ std::is_same_v<
+ std::variant_alternative_t<Index, HalVariant>,
+ sp<HalInterface>>) {
+ return Index;
+ } else {
+ return _findIndex<Index - 1>();
+ }
+ }
+
+ static constexpr size_t sHalIndex = _findIndex<>();
+ static_assert(sHalIndex != 0,
+ "H2BConverter from an unrecognized HAL interface.");
};
-template <
- typename BPINTERFACE,
- typename CONVERTER,
- uint32_t GETTOKEN = DEFAULT_GET_HAL_TOKEN_TRANSACTION_CODE>
+template <typename BPINTERFACE, typename CONVERTER, typename... CONVERTERS>
class HpInterface : public CONVERTER::BaseInterface {
public:
- typedef HpInterface<BPINTERFACE, CONVERTER, GETTOKEN> PBase; // Proxy Base
+ typedef HpInterface<BPINTERFACE, CONVERTER, CONVERTERS...> PBase; // Proxy Base
typedef typename CONVERTER::BaseInterface BaseInterface;
- typedef typename CONVERTER::HalInterface HalInterface;
- static constexpr uint32_t GET_HAL_TOKEN = GETTOKEN;
+ typedef typename BaseInterface::HalVariant HalVariant;
+ using BaseInterface::sGetHalTokenTransactionCode;
explicit HpInterface(const sp<IBinder>& impl);
- virtual sp<HalInterface> getHalInterface() { return mHal; }
- BaseInterface* getBaseInterface() { return mBase.get(); }
+ BaseInterface* getBase() { return mBase.get(); }
+ virtual HalVariant getHalVariant() const override { return mHalVariant; }
protected:
- IBinder* mImpl;
+ IBinder* mBpBinder;
sp<BPINTERFACE> mBp;
sp<BaseInterface> mBase;
- sp<HalInterface> mHal;
- IBinder* onAsBinder() override { return mImpl; }
+ HalVariant mHalVariant;
+ bool mHasConverter{false};
+ IBinder* onAsBinder() override { return mBpBinder; }
+
+private:
+ typedef std::variant<std::monostate,
+ CONVERTER, CONVERTERS...> _ConverterVar;
+ typedef std::variant<std::monostate,
+ typename CONVERTER::HalInterface,
+ typename CONVERTERS::HalInterface...> _ConverterHalVar;
+ typedef std::variant<std::monostate,
+ sp<typename CONVERTER::HalInterface>,
+ sp<typename CONVERTERS::HalInterface>...> _ConverterHalPointerVar;
+
+ static_assert(std::is_same_v<_ConverterHalPointerVar, HalVariant>,
+ "Converter classes do not match HAL interfaces.");
+
+ template <size_t Index = std::variant_size_v<HalVariant> - 1>
+ bool _castFromHalBaseAndConvert(size_t halIndex,
+ const sp<HInterface>& halBase) {
+ if constexpr (Index == 0) {
+ return false;
+ } else {
+ if (halIndex != Index) {
+ return _castFromHalBaseAndConvert<Index - 1>(halIndex, halBase);
+ }
+ typedef std::variant_alternative_t<Index, _ConverterHalVar>
+ HalInterface;
+ sp<HalInterface> halInterface = HalInterface::castFrom(halBase);
+ mHalVariant.template emplace<Index>(halInterface);
+ if (!halInterface) {
+ return false;
+ }
+ if (mHasConverter) {
+ typedef std::variant_alternative_t<Index, _ConverterVar>
+ Converter;
+ sp<Converter> converter = new Converter(halInterface);
+ if (converter) {
+ mBase = converter;
+ } else {
+ ALOGW("HpInterface: Failed to create an H2B converter -- "
+ "index = %zu.", Index);
+ }
+ }
+ return true;
+ }
+ }
+
+ bool castFromHalBaseAndConvert(size_t halIndex,
+ const sp<HInterface>& halBase) {
+ if (!_castFromHalBaseAndConvert<>(halIndex, halBase)) {
+ return false;
+ }
+ return true;
+ }
+
};
// ----------------------------------------------------------------------
-#define DECLARE_HYBRID_META_INTERFACE(INTERFACE, HAL) \
- static const ::android::String16 descriptor; \
- static ::android::sp<I##INTERFACE> asInterface( \
- const ::android::sp<::android::IBinder>& obj); \
- virtual const ::android::String16& getInterfaceDescriptor() const; \
- I##INTERFACE(); \
- virtual ~I##INTERFACE(); \
- virtual sp<HAL> getHalInterface(); \
-
-
-#define IMPLEMENT_HYBRID_META_INTERFACE(INTERFACE, HAL, NAME) \
- const ::android::String16 I##INTERFACE::descriptor(NAME); \
- const ::android::String16& \
- I##INTERFACE::getInterfaceDescriptor() const { \
- return I##INTERFACE::descriptor; \
- } \
- ::android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
- const ::android::sp<::android::IBinder>& obj) \
- { \
- ::android::sp<I##INTERFACE> intr; \
- if (obj != nullptr) { \
- intr = static_cast<I##INTERFACE*>( \
- obj->queryLocalInterface( \
- I##INTERFACE::descriptor).get()); \
- if (intr == nullptr) { \
- intr = new Hp##INTERFACE(obj); \
- } \
- } \
- return intr; \
- } \
- I##INTERFACE::I##INTERFACE() { } \
- I##INTERFACE::~I##INTERFACE() { } \
- sp<HAL> I##INTERFACE::getHalInterface() { return nullptr; } \
+#define DECLARE_HYBRID_META_INTERFACE(INTERFACE, ...) \
+ DECLARE_HYBRID_META_INTERFACE_WITH_CODE( \
+ ::android::DEFAULT_GET_HAL_TOKEN_TRANSACTION_CODE, \
+ INTERFACE, __VA_ARGS__) \
+
+
+#define DECLARE_HYBRID_META_INTERFACE_WITH_CODE(GTKCODE, INTERFACE, ...) \
+private: \
+ typedef ::std::variant<::std::monostate, __VA_ARGS__> _HalVariant; \
+ template <typename... Types> \
+ using _SpVariant = \
+ ::std::variant<::std::monostate, ::android::sp<Types>...>; \
+public: \
+ typedef _SpVariant<__VA_ARGS__> HalVariant; \
+ virtual HalVariant getHalVariant() const; \
+ size_t getHalIndex() const; \
+ template <size_t Index> \
+ using HalInterface = ::std::variant_alternative_t<Index, _HalVariant>;\
+ template <typename HAL> \
+ sp<HAL> getHalInterface() const { \
+ HalVariant halVariant = getHalVariant(); \
+ const sp<HAL>* hal = std::get_if<sp<HAL>>(&halVariant); \
+ return hal ? *hal : nullptr; \
+ } \
+ \
+ static const ::android::String16 descriptor; \
+ static ::android::sp<I##INTERFACE> asInterface( \
+ const ::android::sp<::android::IBinder>& obj); \
+ virtual const ::android::String16& getInterfaceDescriptor() const; \
+ I##INTERFACE(); \
+ virtual ~I##INTERFACE(); \
+ static constexpr uint32_t sGetHalTokenTransactionCode = GTKCODE; \
+
+
+#define IMPLEMENT_HYBRID_META_INTERFACE(INTERFACE, NAME) \
+ I##INTERFACE::HalVariant I##INTERFACE::getHalVariant() const { \
+ return HalVariant{std::in_place_index<0>}; \
+ } \
+ size_t I##INTERFACE::getHalIndex() const { \
+ return getHalVariant().index(); \
+ } \
+ constexpr uint32_t I##INTERFACE::sGetHalTokenTransactionCode; \
+ const ::android::String16 I##INTERFACE::descriptor(NAME); \
+ const ::android::String16& \
+ I##INTERFACE::getInterfaceDescriptor() const { \
+ return I##INTERFACE::descriptor; \
+ } \
+ ::android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
+ const ::android::sp<::android::IBinder>& obj) \
+ { \
+ ::android::sp<I##INTERFACE> intr; \
+ if (obj != nullptr) { \
+ intr = static_cast<I##INTERFACE*>( \
+ obj->queryLocalInterface( \
+ I##INTERFACE::descriptor).get()); \
+ if (intr == nullptr) { \
+ intr = new Hp##INTERFACE(obj); \
+ } \
+ } \
+ return intr; \
+ } \
+ I##INTERFACE::I##INTERFACE() { } \
+ I##INTERFACE::~I##INTERFACE() { } \
// ----------------------------------------------------------------------
-template <
- typename HINTERFACE,
- typename INTERFACE,
- typename BNINTERFACE,
- uint32_t GETTOKEN>
-status_t H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN>::
+template <typename HINTERFACE,
+ typename BNINTERFACE>
+status_t H2BConverter<HINTERFACE, BNINTERFACE>::
onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
- if (code == GET_HAL_TOKEN) {
+ if (code == sGetHalTokenTransactionCode) {
+ if (!data.enforceInterface(BaseInterface::getInterfaceDescriptor())) {
+ return BAD_TYPE;
+ }
+
HalToken token;
bool result;
result = createHalToken(mBase, &token);
+ // Write whether a HAL token is present.
+ reply->writeBool(result);
if (!result) {
ALOGE("H2BConverter: Failed to create HAL token.");
+ return NO_ERROR;
}
- reply->writeBool(result);
+
+ // Write the HAL token.
reply->writeByteArray(token.size(), token.data());
+
+ // Write the HAL index.
+ reply->writeUint32(static_cast<uint32_t>(sHalIndex));
+
+ // Write a flag indicating that a converter needs to be created.
+ reply->writeBool(true);
+
return NO_ERROR;
}
return BNINTERFACE::onTransact(code, data, reply, flags);
}
-template <
- typename HINTERFACE,
- typename INTERFACE,
- typename BNINTERFACE,
- uint32_t GETTOKEN>
-status_t H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN>::
- linkToDeath(
+template <typename HINTERFACE,
+ typename BNINTERFACE>
+status_t H2BConverter<HINTERFACE, BNINTERFACE>::linkToDeath(
const sp<IBinder::DeathRecipient>& recipient,
void* cookie, uint32_t flags) {
- LOG_ALWAYS_FATAL_IF(recipient == nullptr,
- "linkToDeath(): recipient must be non-nullptr");
+ LOG_ALWAYS_FATAL_IF(
+ recipient == nullptr,
+ "linkToDeath(): recipient must not be null.");
{
std::lock_guard<std::mutex> lock(mObituariesLock);
mObituaries.push_back(new Obituary(recipient, cookie, flags, this));
@@ -274,13 +465,9 @@ status_t H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN>::
return NO_ERROR;
}
-template <
- typename HINTERFACE,
- typename INTERFACE,
- typename BNINTERFACE,
- uint32_t GETTOKEN>
-status_t H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN>::
- unlinkToDeath(
+template <typename HINTERFACE,
+ typename BNINTERFACE>
+status_t H2BConverter<HINTERFACE, BNINTERFACE>::unlinkToDeath(
const wp<IBinder::DeathRecipient>& recipient,
void* cookie, uint32_t flags,
wp<IBinder::DeathRecipient>* outRecipient) {
@@ -300,37 +487,70 @@ status_t H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN>::
return NAME_NOT_FOUND;
}
-template <typename BPINTERFACE, typename CONVERTER, uint32_t GETTOKEN>
-HpInterface<BPINTERFACE, CONVERTER, GETTOKEN>::HpInterface(
- const sp<IBinder>& impl) :
- mImpl(impl.get()),
- mBp(new BPINTERFACE(impl)) {
+template <typename BPINTERFACE, typename CONVERTER, typename... CONVERTERS>
+HpInterface<BPINTERFACE, CONVERTER, CONVERTERS...>::HpInterface(
+ const sp<IBinder>& impl)
+ : mBpBinder{impl.get()},
+ mBp{new BPINTERFACE(impl)} {
mBase = mBp;
- if (mImpl->remoteBinder() == nullptr) {
+ if (!mBpBinder->remoteBinder()) {
return;
}
Parcel data, reply;
data.writeInterfaceToken(BaseInterface::getInterfaceDescriptor());
- if (mImpl->transact(GET_HAL_TOKEN, data, &reply) == NO_ERROR) {
- bool tokenCreated = reply.readBool();
+ if (mBpBinder->transact(sGetHalTokenTransactionCode,
+ data, &reply) == NO_ERROR) {
+ // Read whether a HAL token is present.
+ bool tokenCreated;
+ if (reply.readBool(&tokenCreated) != OK) {
+ ALOGW("HpInterface: Corrupted parcel from GET_HAL_TOKEN "
+ "(tokenCreated).");
+ }
+
+ if (!tokenCreated) {
+ ALOGW("HpInterface: No HAL token was created.");
+ return;
+ }
+ // Read the HAL token.
std::vector<uint8_t> tokenVector;
- reply.readByteVector(&tokenVector);
- HalToken token = HalToken(tokenVector);
-
- if (tokenCreated) {
- sp<HInterface> hBase = retrieveHalInterface(token);
- if (hBase != nullptr) {
- mHal = HalInterface::castFrom(hBase);
- if (mHal != nullptr) {
- mBase = new CONVERTER(mHal);
- } else {
- ALOGE("HpInterface: Wrong interface type.");
- }
- } else {
- ALOGE("HpInterface: Invalid HAL token.");
- }
- deleteHalToken(token);
+ if (reply.readByteVector(&tokenVector) != OK) {
+ ALOGW("HpInterface: Corrupted parcel from GET_HAL_TOKEN "
+ "(halToken).");
+ return;
+ }
+
+ // Retrieve the HAL interface from the token.
+ HalToken token{tokenVector};
+ sp<HInterface> halBase = retrieveHalInterface(token);
+ deleteHalToken(token);
+
+ if (!halBase) {
+ ALOGW("HpInterface: Failed to retrieve HAL interface.");
+ return;
+ }
+
+ uint32_t halIndex;
+ // Read the hal index.
+ if (reply.readUint32(&halIndex) != OK) {
+ ALOGW("HpInterface: Corrupted parcel from GET_HAL_TOKEN "
+ "(halIndex).");
+ return;
+ }
+
+ // Read the converter flag.
+ if (reply.readBool(&mHasConverter) != OK) {
+ ALOGW("HpInterface: Corrupted parcel from GET_HAL_TOKEN "
+ "(hasConverter).");
+ return;
+ }
+
+ // Call castFrom from the right HAL interface and create a converter if
+ // needed.
+ if (!castFromHalBaseAndConvert(static_cast<size_t>(halIndex),
+ halBase)) {
+ ALOGW("HpInterface: Failed to cast to the correct HAL interface -- "
+ "HAL index = %" PRIu32 ".", halIndex);
}
}
}
diff --git a/update-makefiles.sh b/update-makefiles.sh
index fd0a23c..cf13c83 100755
--- a/update-makefiles.sh
+++ b/update-makefiles.sh
@@ -5,7 +5,9 @@ packages=(
android.hidl.base@1.0
android.hidl.manager@1.0
android.hidl.manager@1.1
+ android.hidl.manager@1.2
android.hidl.memory@1.0
+ android.hidl.safe_union@1.0
android.hidl.token@1.0
)
diff --git a/vintfdata/Android.mk b/vintfdata/Android.mk
index bc7a55a..7a30668 100644
--- a/vintfdata/Android.mk
+++ b/vintfdata/Android.mk
@@ -16,6 +16,12 @@
LOCAL_PATH := $(call my-dir)
+# DEVICE_FRAMEWORK_MANIFEST_FILE is a device-specific framework manifest file
+# that installed to the system image. HALs entries should be written to
+# DEVICE_FRAMEWORK_MANIFEST_FILE or PRODUCT_MANIFEST_FILES depend on the path of
+# the module. It is recommended that such device-specific modules to be
+# installed on product partition.
+
FRAMEWORK_MANIFEST_INPUT_FILES := $(LOCAL_PATH)/manifest.xml
ifdef DEVICE_FRAMEWORK_MANIFEST_FILE
FRAMEWORK_MANIFEST_INPUT_FILES += $(DEVICE_FRAMEWORK_MANIFEST_FILE)
@@ -44,33 +50,27 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/vintf
GEN := $(local-generated-sources-dir)/compatibility_matrix.xml
$(GEN): PRIVATE_VINTF_VNDK_VERSION := $(VINTF_VNDK_VERSION)
+$(GEN): PRIVATE_DEVICE_MATRIX_INPUT_FILE := $(DEVICE_MATRIX_INPUT_FILE)
$(GEN): $(DEVICE_MATRIX_INPUT_FILE) $(HOST_OUT_EXECUTABLES)/assemble_vintf
REQUIRED_VNDK_VERSION=$(PRIVATE_VINTF_VNDK_VERSION) \
BOARD_SYSTEMSDK_VERSIONS="$(BOARD_SYSTEMSDK_VERSIONS)" \
- $(HOST_OUT_EXECUTABLES)/assemble_vintf -i $< -o $@
+ $(HOST_OUT_EXECUTABLES)/assemble_vintf \
+ -i $(call normalize-path-list,$(PRIVATE_DEVICE_MATRIX_INPUT_FILE)) \
+ -o $@
LOCAL_PREBUILT_MODULE_FILE := $(GEN)
include $(BUILD_PREBUILT)
BUILT_VENDOR_MATRIX := $(LOCAL_BUILT_MODULE)
-# Framework Manifest
+# System Manifest
include $(CLEAR_VARS)
-LOCAL_MODULE := framework_manifest.xml
+LOCAL_MODULE := system_manifest.xml
LOCAL_MODULE_STEM := manifest.xml
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/vintf
GEN := $(local-generated-sources-dir)/manifest.xml
-$(GEN): PRIVATE_FLAGS :=
-
-ifeq ($(PRODUCT_ENFORCE_VINTF_MANIFEST),true)
-ifdef BUILT_VENDOR_MATRIX
-$(GEN): $(BUILT_VENDOR_MATRIX)
-$(GEN): PRIVATE_FLAGS += -c "$(BUILT_VENDOR_MATRIX)"
-endif
-endif
-
$(GEN): PRIVATE_VINTF_VNDK_VERSION := $(VINTF_VNDK_VERSION)
$(GEN): PRIVATE_FRAMEWORK_MANIFEST_INPUT_FILES := $(FRAMEWORK_MANIFEST_INPUT_FILES)
$(GEN): $(FRAMEWORK_MANIFEST_INPUT_FILES) $(HOST_OUT_EXECUTABLES)/assemble_vintf
@@ -78,12 +78,32 @@ $(GEN): $(FRAMEWORK_MANIFEST_INPUT_FILES) $(HOST_OUT_EXECUTABLES)/assemble_vintf
PLATFORM_SYSTEMSDK_VERSIONS="$(PLATFORM_SYSTEMSDK_VERSIONS)" \
$(HOST_OUT_EXECUTABLES)/assemble_vintf \
-i $(call normalize-path-list,$(PRIVATE_FRAMEWORK_MANIFEST_INPUT_FILES)) \
- -o $@ $(PRIVATE_FLAGS)
+ -o $@
LOCAL_PREBUILT_MODULE_FILE := $(GEN)
include $(BUILD_PREBUILT)
BUILT_SYSTEM_MANIFEST := $(LOCAL_BUILT_MODULE)
+# Product Manifest
+ifneq ($(PRODUCT_MANIFEST_FILES),)
+include $(CLEAR_VARS)
+LOCAL_MODULE := product_manifest.xml
+LOCAL_MODULE_STEM := manifest.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_RELATIVE_PATH := vintf
+GEN := $(local-generated-sources-dir)/manifest.xml
+$(GEN): PRIVATE_PRODUCT_MANIFEST_FILES := $(PRODUCT_MANIFEST_FILES)
+$(GEN): $(PRODUCT_MANIFEST_FILES) $(HOST_OUT_EXECUTABLES)/assemble_vintf
+ $(HOST_OUT_EXECUTABLES)/assemble_vintf \
+ -i $(call normalize-path-list,$(PRIVATE_PRODUCT_MANIFEST_FILES)) \
+ -o $@
+
+LOCAL_PREBUILT_MODULE_FILE := $(GEN)
+include $(BUILD_PREBUILT)
+BUILT_PRODUCT_MANIFEST := $(LOCAL_BUILT_MODULE)
+endif
+
VINTF_VNDK_VERSION :=
FRAMEWORK_MANIFEST_INPUT_FILES :=
DEVICE_MATRIX_INPUT_FILE :=
+PRODUCT_MANIFEST_INPUT_FILES :=
diff --git a/vintfdata/manifest.xml b/vintfdata/manifest.xml
index 51d68eb..e204671 100644
--- a/vintfdata/manifest.xml
+++ b/vintfdata/manifest.xml
@@ -2,22 +2,13 @@
<hal>
<name>android.hidl.manager</name>
<transport>hwbinder</transport>
- <version>1.1</version>
+ <version>1.2</version>
<interface>
<name>IServiceManager</name>
<instance>default</instance>
</interface>
</hal>
<hal>
- <name>android.hidl.allocator</name>
- <transport>hwbinder</transport>
- <version>1.0</version>
- <interface>
- <name>IAllocator</name>
- <instance>ashmem</instance>
- </interface>
- </hal>
- <hal>
<name>android.hidl.memory</name>
<transport arch="32+64">passthrough</transport>
<version>1.0</version>
@@ -62,7 +53,7 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl">
+ <hal>
<name>android.system.net.netd</name>
<transport>hwbinder</transport>
<version>1.1</version>
@@ -80,25 +71,6 @@
<instance>default</instance>
</interface>
</hal>
- <hal>
- <name>android.hardware.graphics.composer</name>
- <transport>hwbinder</transport>
- <version>2.1</version>
- <interface>
- <name>IComposer</name>
- <instance>vr</instance>
- </interface>
- </hal>
- <hal>
- <name>android.hardware.health</name>
- <transport>hwbinder</transport>
- <version>2.0</version>
- <interface>
- <name>IHealth</name>
- <!-- The backup instance provided by healthd. -->
- <instance>backup</instance>
- </interface>
- </hal>
<hal format="native">
<name>netutils-wrapper</name>
<!--
diff --git a/vintfdata/manifest_healthd_exclude.xml b/vintfdata/manifest_healthd_exclude.xml
deleted file mode 100644
index b4060f0..0000000
--- a/vintfdata/manifest_healthd_exclude.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<!--
- Include this file to DEVICE_FRAMEWORK_MANIFEST_FILE to disable
- having an healthd on the device which is not needed if you have
- an alternative implementation like the following:
- (1) Device has android.hardware.health@2.0-service.override
- (2) Device has android.hardware.health@2.0-service.<device>, which
- contains the following:
- overrides: ["healthd"]
--->
-<manifest version="1.0" type="framework">
- <hal format="hidl" override="true">
- <name>android.hardware.health</name>
- <transport>hwbinder</transport>
- </hal>
-</manifest>