diff options
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 @@ -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> |