diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2020-04-28 20:26:25 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2020-04-28 20:26:25 +0000 |
commit | 278e9d242f65f45265da2f14aee13355decd1bad (patch) | |
tree | 3cdc09f9859f0f721e9fb431d45cfb13c8fc9bad | |
parent | 96b10ca07bd474425614eed8d47d0db7a3d05700 (diff) | |
parent | 87d7ad9d8fe6cbb0405983b37ff9e79927451bc7 (diff) | |
download | libhidl-q_tzdata_aml_297100000.tar.gz |
Snap for 6439596 from 87d7ad9d8fe6cbb0405983b37ff9e79927451bc7 to qt-aml-tzdata-releaseq_tzdata_aml_297100400q_tzdata_aml_297100300q_tzdata_aml_297100000q_tzdata_aml_296200000q_tzdata_aml_295600118q_tzdata_aml_295600110q_tzdata_aml_295500002q_tzdata_aml_295500001q_tzdata_aml_294400310android-mainline-12.0.0_r54android-mainline-12.0.0_r111android-mainline-10.0.0_r13android-mainline-10.0.0_r12android-mainline-10.0.0_r11q_tzdata_aml_297100000android12-mainline-tzdata-releaseandroid10-mainline-tzdata-releaseandroid10-android13-mainline-tzdata-release
Change-Id: I410d82f717bc22d5640b0d86ac1fde47169456a6
50 files changed, 1419 insertions, 711 deletions
@@ -22,21 +22,8 @@ cc_defaults { ], } -phony { - name: "libhidl", - required: [ - "libhidlbase", - ], -} - -cc_library_headers { - name: "libhidl_gtest_helper", - export_include_dirs: ["gtest_helper"], -} - cc_test { name: "libhidl_test", - host_supported: true, defaults: ["libhidl-defaults"], gtest: false, srcs: ["test_main.cpp"], @@ -46,6 +33,8 @@ cc_test { "android.hidl.memory@1.0", "libbase", "libhidlbase", + "libhidltransport", + "libhwbinder", "liblog", "libutils", "libcutils", @@ -76,7 +65,6 @@ cc_defaults { cc_library { name: "libhidlbase", defaults: ["libhidlbase-combined-impl"], - host_supported: true, recovery_available: true, vendor_available: true, vndk: { @@ -101,8 +89,6 @@ cc_library { whole_static_libs: [ "libhwbinder_pgo-impl-internal", ], - - visibility: ["//system/libhwbinder:__subpackages__"], } // WARNING: deprecated @@ -110,5 +96,10 @@ cc_library { // on libhidlbase instead. cc_library { name: "libhidltransport", + recovery_available: true, vendor_available: true, + vndk: { + enabled: true, + support_system_process: true, + }, } diff --git a/TEST_MAPPING b/TEST_MAPPING index c4a663e..3e17fc4 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -2,9 +2,6 @@ "presubmit": [ { "name": "libhidl_test" - }, - { - "name": "hidl_implementation_test" } ] } diff --git a/adapter/Android.bp b/adapter/Android.bp index ae801bc..eb322bc 100644 --- a/adapter/Android.bp +++ b/adapter/Android.bp @@ -23,11 +23,14 @@ cc_library { shared_libs: [ "libbase", "libhidlbase", + "libhidltransport", + "libhwbinder", "liblog", "libutils", ], export_shared_lib_headers: [ "libhidlbase", + "libhidltransport", "libutils", ], } diff --git a/base/Android.bp b/base/Android.bp index ca4e259..8fe2702 100644 --- a/base/Android.bp +++ b/base/Android.bp @@ -28,9 +28,8 @@ cc_defaults { cc_library { name: "libhidlbase-impl-internal", - host_supported: true, - recovery_available: true, vendor_available: true, + recovery_available: true, defaults: [ "libhidlbase-impl-shared-libs", "libhidl-defaults" @@ -54,6 +53,4 @@ cc_library { cflags: ["-DLIBHIDL_TARGET_DEBUGGABLE"], }, }, - - visibility: ["//system/libhidl:__subpackages__"], } diff --git a/base/HidlInternal.cpp b/base/HidlInternal.cpp index 956effd..440b30f 100644 --- a/base/HidlInternal.cpp +++ b/base/HidlInternal.cpp @@ -21,6 +21,7 @@ #include <android-base/logging.h> #include <android-base/properties.h> #include <android-base/stringprintf.h> +#include <cutils/properties.h> #ifdef LIBHIDL_TARGET_DEBUGGABLE #include <dirent.h> @@ -55,7 +56,7 @@ std::string getVndkVersionStr() { // "0" means the vndkVersion must be initialized with the property value. // Otherwise, return the value. if (vndkVersion == "0") { - vndkVersion = base::GetProperty("ro.vndk.version", ""); + vndkVersion = android::base::GetProperty("ro.vndk.version", ""); if (vndkVersion != "" && vndkVersion != "current") { vndkVersion = "-" + vndkVersion; } else { @@ -75,44 +76,44 @@ HidlInstrumentor::HidlInstrumentor(const std::string& package, const std::string configureInstrumentation(false); if (__sanitizer_cov_dump != nullptr) { ::android::add_sysprop_change_callback( - []() { - bool enableCoverage = base::GetBoolProperty(kSysPropHalCoverage, false); - if (enableCoverage) { - __sanitizer_cov_dump(); - } - }, - 0); + []() { + bool enableCoverage = property_get_bool(kSysPropHalCoverage, false); + if (enableCoverage) { + __sanitizer_cov_dump(); + } + }, + 0); } - if (base::GetBoolProperty("ro.vts.coverage", false)) { + if (property_get_bool("ro.vts.coverage", false)) { const char* prefixOverride = getenv(kGcovPrefixOverrideEnvVar); if (prefixOverride == nullptr || strcmp(prefixOverride, "true") != 0) { const std::string gcovPath = kGcovPrefixPath + std::to_string(getpid()); setenv(kGcovPrefixEnvVar, gcovPath.c_str(), true /* overwrite */); } ::android::add_sysprop_change_callback( - []() { - const bool enableCoverage = base::GetBoolProperty(kSysPropHalCoverage, false); - if (enableCoverage) { - dl_iterate_phdr( - [](struct dl_phdr_info* info, size_t /* size */, void* /* data */) { - if (strlen(info->dlpi_name) == 0) return 0; - - void* handle = dlopen(info->dlpi_name, RTLD_LAZY); - if (handle == nullptr) { - LOG(INFO) << "coverage dlopen failed: " << dlerror(); - return 0; - } - void (*flush)() = (void (*)())dlsym(handle, "__gcov_flush"); - if (flush == nullptr) { - return 0; - } - flush(); - return 0; - }, - nullptr /* data */); - } - }, - 0 /* priority */); + []() { + const bool enableCoverage = property_get_bool(kSysPropHalCoverage, false); + if (enableCoverage) { + dl_iterate_phdr( + [](struct dl_phdr_info* info, size_t /* size */, void* /* data */) { + if (strlen(info->dlpi_name) == 0) return 0; + + void* handle = dlopen(info->dlpi_name, RTLD_LAZY); + if (handle == nullptr) { + LOG(INFO) << "coverage dlopen failed: " << dlerror(); + return 0; + } + void (*flush)() = (void (*)())dlsym(handle, "__gcov_flush"); + if (flush == nullptr) { + return 0; + } + flush(); + return 0; + }, + nullptr /* data */); + } + }, + 0 /* priority */); } #endif } @@ -120,7 +121,7 @@ HidlInstrumentor::HidlInstrumentor(const std::string& package, const std::string HidlInstrumentor::~HidlInstrumentor() {} void HidlInstrumentor::configureInstrumentation(bool log) { - mEnableInstrumentation = base::GetBoolProperty("hal.instrumentation.enable", false); + mEnableInstrumentation = property_get_bool("hal.instrumentation.enable", false); if (mEnableInstrumentation) { if (log) { LOG(INFO) << "Enable instrumentation."; @@ -139,8 +140,8 @@ void HidlInstrumentor::registerInstrumentationCallbacks( std::vector<InstrumentationCallback> *instrumentationCallbacks) { #ifdef LIBHIDL_TARGET_DEBUGGABLE std::vector<std::string> instrumentationLibPaths; - const std::string instrumentationLibPath = base::GetProperty(kSysPropInstrumentationPath, ""); - if (instrumentationLibPath.size() > 0) { + char instrumentationLibPath[PROPERTY_VALUE_MAX]; + if (property_get(kSysPropInstrumentationPath, instrumentationLibPath, "") > 0) { instrumentationLibPaths.push_back(instrumentationLibPath); } else { static std::string halLibPathVndkSp = android::base::StringPrintf( diff --git a/base/HidlSupport.cpp b/base/HidlSupport.cpp index af805b9..f97f216 100644 --- a/base/HidlSupport.cpp +++ b/base/HidlSupport.cpp @@ -35,8 +35,10 @@ bool debuggable() { } } // namespace details -hidl_handle::hidl_handle() : mHandle(nullptr), mOwnsHandle(false) { - memset(mPad, 0, sizeof(mPad)); +hidl_handle::hidl_handle() { + memset(this, 0, sizeof(*this)); + // mHandle = nullptr; + // mOwnsHandle = false; } hidl_handle::~hidl_handle() { @@ -136,8 +138,11 @@ void hidl_handle::freeHandle() { static const char *const kEmptyString = ""; -hidl_string::hidl_string() : mBuffer(kEmptyString), mSize(0), mOwnsBuffer(false) { - memset(mPad, 0, sizeof(mPad)); +hidl_string::hidl_string() { + memset(this, 0, sizeof(*this)); + // mSize is zero + // mOwnsBuffer is false + mBuffer = kEmptyString; } hidl_string::~hidl_string() { diff --git a/base/Status.cpp b/base/Status.cpp index 7698ff8..90474a0 100644 --- a/base/Status.cpp +++ b/base/Status.cpp @@ -149,51 +149,36 @@ void setProcessHidlReturnRestriction(HidlReturnRestriction restriction) { } namespace details { - void return_status::onValueRetrieval() const { + void return_status::assertOk() const { if (!isOk()) { LOG(FATAL) << "Attempted to retrieve value from failed HIDL call: " << description(); } } - void return_status::onIgnored() const { + return_status::~return_status() { + // mCheckedStatus must be checked before isOk since isOk modifies mCheckedStatus + 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); + CallStack::logStack("unchecked HIDL return", CallStack::getCurrent(10).get(), ANDROID_LOG_ERROR); } else { LOG(FATAL) << "Failed to check status of HIDL Return."; } } - void return_status::assertOk() const { - if (!isOk()) { - LOG(FATAL) << "Failed HIDL return status not checked. Usually this happens because of " - "a transport error (error parceling, binder driver, or from unparceling)" - ". If you see this in code calling into \"Bn\" classes in for a HAL " - "server process, then it is likely that the code there is returning " - "transport errors there (as opposed to errors defined within its " - "protocol). Error is: " << description(); - } - } - - return_status::~return_status() { - // mCheckedStatus must be checked before isOk since isOk modifies mCheckedStatus - if (mCheckedStatus) return; - - assertOk(); - onIgnored(); - } - return_status& return_status::operator=(return_status&& other) noexcept { - if (!mCheckedStatus) { - assertOk(); - onIgnored(); + if (!mCheckedStatus && !isOk()) { + LOG(FATAL) << "Failed HIDL return status not checked: " << description(); } - std::swap(mStatus, other.mStatus); std::swap(mCheckedStatus, other.mCheckedStatus); return *this; diff --git a/base/include/hidl/HidlSupport.h b/base/include/hidl/HidlSupport.h index 1b91c26..93a6251 100644 --- a/base/include/hidl/HidlSupport.h +++ b/base/include/hidl/HidlSupport.h @@ -20,24 +20,18 @@ #include <algorithm> #include <array> #include <iterator> +#include <cutils/native_handle.h> #include <hidl/HidlInternal.h> +#include <hidl/Status.h> #include <map> #include <sstream> #include <stddef.h> #include <tuple> #include <type_traits> -#include <vector> - -// no requirements on types not used in scatter/gather -// no requirements on other libraries -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#include <cutils/native_handle.h> -#include <hidl/Status.h> #include <utils/Errors.h> #include <utils/RefBase.h> #include <utils/StrongPointer.h> -#pragma clang diagnostic pop +#include <vector> namespace android { @@ -129,9 +123,8 @@ struct hidl_handle { private: void freeHandle(); - details::hidl_pointer<const native_handle_t> mHandle; - bool mOwnsHandle; - uint8_t mPad[7]; + details::hidl_pointer<const native_handle_t> mHandle __attribute__ ((aligned(8))); + bool mOwnsHandle __attribute ((aligned(8))); }; struct hidl_string { @@ -181,7 +174,6 @@ private: details::hidl_pointer<const char> mBuffer; uint32_t mSize; // NOT including the terminating '\0'. bool mOwnsBuffer; // if true then mBuffer is a mutable char * - uint8_t mPad[3]; // copy from data with size. Assume that my memory is freed // (through clear(), for example) @@ -302,9 +294,9 @@ struct hidl_memory { static const size_t kOffsetOfName; private: - hidl_handle mHandle; - uint64_t mSize; - hidl_string mName; + hidl_handle mHandle __attribute__ ((aligned(8))); + uint64_t mSize __attribute__ ((aligned(8))); + hidl_string mName __attribute__ ((aligned(8))); }; // HidlMemory is a wrapper class to support sp<> for hidl_memory. It also @@ -334,12 +326,15 @@ protected: template<typename T> struct hidl_vec { - using value_type = T; - - hidl_vec() : mBuffer(nullptr), mSize(0), mOwnsBuffer(false) { + hidl_vec() { static_assert(hidl_vec<T>::kOffsetOfBuffer == 0, "wrong offset"); - memset(mPad, 0, sizeof(mPad)); + memset(this, 0, sizeof(*this)); + // mSize is 0 + // mBuffer is nullptr + + // this is for consistency with the original implementation + mOwnsBuffer = true; } // Note, does not initialize primitive types. @@ -515,7 +510,7 @@ struct hidl_vec { T* newBuffer = new T[size](); for (size_t i = 0; i < std::min(static_cast<uint32_t>(size), mSize); ++i) { - newBuffer[i] = std::move(mBuffer[i]); + newBuffer[i] = mBuffer[i]; } if (mOwnsBuffer) { @@ -576,15 +571,11 @@ public: iterator end() { return data()+mSize; } const_iterator begin() const { return data(); } const_iterator end() const { return data()+mSize; } - iterator find(const T& v) { return std::find(begin(), end(), v); } - const_iterator find(const T& v) const { return std::find(begin(), end(), v); } - bool contains(const T& v) const { return find(v) != end(); } - private: +private: details::hidl_pointer<T> mBuffer; uint32_t mSize; bool mOwnsBuffer; - uint8_t mPad[3]; // copy from an array-like object, assuming my resources are freed. template <typename Array> @@ -740,8 +731,6 @@ struct hidl_array { using std_array_type = typename details::std_array<T, SIZE1, SIZES...>::type; hidl_array() = default; - hidl_array(const hidl_array&) noexcept = default; - hidl_array(hidl_array&&) noexcept = default; // Copies the data from source, using T::operator=(const T &). hidl_array(const T *source) { @@ -756,9 +745,6 @@ struct hidl_array { modifier = array; } - hidl_array& operator=(const hidl_array&) noexcept = default; - hidl_array& operator=(hidl_array&&) noexcept = default; - T *data() { return mBuffer; } const T *data() const { return mBuffer; } @@ -807,12 +793,10 @@ private: // An array of T's. Assumes that T::operator=(const T &) is defined. template<typename T, size_t SIZE1> struct hidl_array<T, SIZE1> { - using value_type = T; + using std_array_type = typename details::std_array<T, SIZE1>::type; hidl_array() = default; - hidl_array(const hidl_array&) noexcept = default; - hidl_array(hidl_array&&) noexcept = default; // Copies the data from source, using T::operator=(const T &). hidl_array(const T *source) { @@ -824,9 +808,6 @@ struct hidl_array<T, SIZE1> { // Copies the data from the given std::array, using T::operator=(const T &). hidl_array(const std_array_type &array) : hidl_array(array.data()) {} - hidl_array& operator=(const hidl_array&) noexcept = default; - hidl_array& operator=(hidl_array&&) noexcept = default; - T *data() { return mBuffer; } const T *data() const { return mBuffer; } diff --git a/base/include/hidl/Status.h b/base/include/hidl/Status.h index 74901bb..817277f 100644 --- a/base/include/hidl/Status.h +++ b/base/include/hidl/Status.h @@ -141,15 +141,8 @@ namespace details { Status mStatus {}; mutable bool mCheckedStatus = false; - // called when an unchecked status is discarded - // makes sure this status is checked according to the preference - // set by setProcessHidlReturnRestriction - void onIgnored() const; - template <typename T, typename U> friend Return<U> StatusOf(const Return<T> &other); - protected: - void onValueRetrieval() const; public: void assertOk() const; return_status() {} @@ -231,7 +224,7 @@ public: ~Return() = default; operator T() const { - onValueRetrieval(); // assert okay + assertOk(); return mVal; } @@ -260,7 +253,7 @@ public: ~Return() = default; operator sp<T>() const { - onValueRetrieval(); // assert okay + assertOk(); return mVal; } diff --git a/gtest_helper/hidl/GtestPrinter.h b/gtest_helper/hidl/GtestPrinter.h deleted file mode 100644 index 4b5ac2d..0000000 --- a/gtest_helper/hidl/GtestPrinter.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2019 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 <gtest/gtest.h> - -namespace android { -namespace hardware { - -static inline std::string Sanitize(std::string name) { - for (size_t i = 0; i < name.size(); i++) { - // gtest test names must only contain alphanumeric characters - if (!std::isalnum(name[i])) name[i] = '_'; - } - return name; -} - -static inline std::string PrintInstanceNameToString( - const testing::TestParamInfo<std::string>& info) { - // test names need to be unique -> index prefix - std::string name = std::to_string(info.index) + "/" + info.param; - return Sanitize(name); -} - -template <typename... T> -static inline std::string PrintInstanceTupleNameToString( - const testing::TestParamInfo<std::tuple<T...>>& info) { - std::vector<std::string> instances = std::apply( - [](auto&&... elems) { - std::vector<std::string> instances; - instances.reserve(sizeof...(elems)); - (instances.push_back(std::forward<decltype(elems)>(elems)), ...); - return instances; - }, - info.param); - std::string param_string; - for (const std::string& instance : instances) { - param_string += instance + "_"; - } - param_string += std::to_string(info.index); - - return Sanitize(param_string); -} - -} // namespace hardware -} // namespace android diff --git a/libhidlcache/Android.bp b/libhidlcache/Android.bp new file mode 100644 index 0000000..d28a4f1 --- /dev/null +++ b/libhidlcache/Android.bp @@ -0,0 +1,71 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_library { + name: "libhidlcache", + vendor_available: true, + vndk: { + enabled: true, + }, + defaults: ["libhidl-defaults"], + shared_libs: [ + "libbase", + "liblog", + "libutils", + "libcutils", + "libhidlbase", + "libhidlmemory", + "libhwbinder", + "libhidltransport", + "android.hidl.memory@1.0", + "android.hidl.memory.block@1.0", + "android.hidl.memory.token@1.0", + ], + export_include_dirs: ["include"], + + export_shared_lib_headers: [ + "android.hidl.memory@1.0", + "android.hidl.memory.block@1.0", + "android.hidl.memory.token@1.0", + "libhidlbase", + ], + srcs: [ + "HidlMemoryCache.cpp", + "MemoryDealer.cpp", + "mapping.cpp", + ], +} + +cc_test { + name: "libhidlcache_test", + defaults: ["hidl-gen-defaults"], + + shared_libs: [ + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + "android.hidl.memory.block@1.0", + "android.hidl.memory.token@1.0", + "libbase", + "libcutils", + "libhidlbase", + "libhidlmemory", + "libhidlcache", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + ], + + srcs: ["libhidlcache_test.cpp"], +} diff --git a/libhidlcache/HidlCache.h b/libhidlcache/HidlCache.h new file mode 100644 index 0000000..39a7b3a --- /dev/null +++ b/libhidlcache/HidlCache.h @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef ANDROID_HARDWARE_HIDL_CACHE_H +#define ANDROID_HARDWARE_HIDL_CACHE_H + +#include <utils/Log.h> + +namespace android { +namespace hardware { + +// A generic cache to map Key to sp<Value>. The cache records are kept with +// wp<Value>, so that it does not block the Value to be garbage collected +// when there's no other sp<> externally. +template <class Key, class Value, class Compare = std::less<Key>> +class HidlCache : public virtual RefBase { + using Mutex = std::mutex; + using Lock = std::lock_guard<Mutex>; + + public: + // A RAII class to manage lock/unlock HidlCache. + class HidlCacheLock : public virtual RefBase { + public: + HidlCacheLock(sp<HidlCache> cache, const Key& key) : mCache(cache), mKey(key) { + mCache->lock(mKey); + } + ~HidlCacheLock() { mCache->unlock(mKey); } + + private: + sp<HidlCache> mCache; + const Key mKey; + }; + // lock the IMemory refered by key and keep it alive even if there's no + // other memory block refers to. + virtual bool lock(const Key& key); + virtual sp<Value> unlock(const Key& key); + virtual bool flush(const Key& key); + // fetch the sp<Value> with key from cache, + // make a new instance with fill() if it does not present currently. + virtual sp<Value> fetch(const Key& key); + virtual sp<HidlCacheLock> lockGuard(const Key& key) { return new HidlCacheLock(this, key); } + + virtual ~HidlCache() {} + + protected: + friend void HidlCacheWhiteBoxTest(); + // This method shall be called with a lock held + virtual sp<Value> fillLocked(const Key& key) = 0; + + // @return nullptr if it does not present currently. + // @note This method shall be called with a lock held + virtual sp<Value> getCachedLocked(const Key& key); + bool cached(Key key) const { return mCached.count(key) > 0; } + bool locked(Key key) const { return mLocked.count(key) > 0; } + Mutex mMutex; + + std::map<Key, wp<Value>, Compare> mCached; + std::map<Key, sp<Value>, Compare> mLocked; +}; + +template <class Key, class Value, class Compare> +bool HidlCache<Key, Value, Compare>::lock(const Key& key) { + { + Lock lock(mMutex); + if (cached(key)) { + sp<Value> im = mCached[key].promote(); + if (im != nullptr) { + mLocked[key] = im; + return true; + } else { + mCached.erase(key); + } + } + } + sp<Value> value = fetch(key); + if (value == nullptr) { + return false; + } else { + Lock lock(mMutex); + mLocked[key] = value; + return true; + } +} + +template <class Key, class Value, class Compare> +sp<Value> HidlCache<Key, Value, Compare>::unlock(const Key& key) { + Lock lock(mMutex); + if (locked(key)) { + sp<Value> v = mLocked[key]; + mLocked.erase(key); + return v; + } + return nullptr; +} + +template <class Key, class Value, class Compare> +bool HidlCache<Key, Value, Compare>::flush(const Key& key) { + Lock lock(mMutex); + bool contain = cached(key); + mCached.erase(key); + return contain; +} + +template <class Key, class Value, class Compare> +sp<Value> HidlCache<Key, Value, Compare>::getCachedLocked(const Key& key) { + if (cached(key)) { + wp<Value> cache = mCached[key]; + sp<Value> mem = cache.promote(); + if (mem != nullptr) { + return mem; + } else { + mCached.erase(key); + } + } + return nullptr; +} + +template <class Key, class Value, class Compare> +sp<Value> HidlCache<Key, Value, Compare>::fetch(const Key& key) { + Lock lock(mMutex); + sp<Value> value = getCachedLocked(key); + + if (value == nullptr) { + value = fillLocked(key); + } + return value; +} + +} // namespace hardware +} // namespace android +#endif diff --git a/libhidlcache/HidlMemoryCache.cpp b/libhidlcache/HidlMemoryCache.cpp new file mode 100644 index 0000000..a23c388 --- /dev/null +++ b/libhidlcache/HidlMemoryCache.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "HidlMemoryCache" +#include "HidlMemoryCache.h" +#include <android/hidl/memory/1.0/IMemory.h> +#include <android/hidl/memory/token/1.0/IMemoryToken.h> +#include <hidlmemory/mapping.h> +#include <sys/mman.h> +#include <utils/Log.h> + +namespace android { +namespace hardware { + +using IMemoryToken = ::android::hidl::memory::token::V1_0::IMemoryToken; +using IMemory = ::android::hidl::memory::V1_0::IMemory; + +class MemoryDecorator : public virtual IMemory { + public: + 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> updateRange(uint64_t start, uint64_t length) override { + return mHeap->updateRange(start, length); + } + Return<void> readRange(uint64_t start, uint64_t length) override { + return mHeap->readRange(start, length); + } + Return<void> commit() override { return mHeap->commit(); } + + Return<void*> getPointer() override { return mHeap->getPointer(); } + Return<uint64_t> getSize() override { return mHeap->getSize(); } + + protected: + sp<IMemory> mHeap; +}; + +class MemoryCacheable : public virtual MemoryDecorator { + public: + MemoryCacheable(const sp<IMemory>& heap, sp<IMemoryToken> key) + : MemoryDecorator(heap), mKey(key) {} + virtual ~MemoryCacheable() { HidlMemoryCache::getInstance()->flush(mKey); } + + protected: + sp<IMemoryToken> mKey; +}; + +class MemoryBlockImpl : public virtual IMemory { + public: + 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<void> readRange(uint64_t start, uint64_t length) override { + if (!validRange(start, length)) { + ALOGE("IMemoryBlock::readRange: out of range"); + return Void(); + } + return mHeap->readRange(mOffset + start, length); + } + Return<void> updateRange(uint64_t start, uint64_t length) override { + if (!validRange(start, length)) { + ALOGE("IMemoryBlock::updateRange: out of range"); + return Void(); + } + 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(); + return (static_cast<char*>(p) + mOffset); + } + + protected: + sp<IMemory> mHeap; + uint64_t mSize; + uint64_t mOffset; + uint64_t mHeapSize; +}; + +sp<HidlMemoryCache> HidlMemoryCache::getInstance() { + static sp<HidlMemoryCache> instance = new HidlMemoryCache(); + return instance; +} + +sp<IMemory> HidlMemoryCache::fillLocked(const sp<IMemoryToken>& key) { + sp<IMemory> memory = nullptr; + Return<void> ret = key->get( + [&](const hidl_memory& mem) { memory = new MemoryCacheable(mapMemory(mem), key); }); + if (!ret.isOk()) { + ALOGE("HidlMemoryCache::fill: cannot IMemoryToken::get."); + return nullptr; + } + mCached[key] = memory; + return memory; +} + +sp<IMemory> HidlMemoryCache::map(const MemoryBlock& memblk) { + sp<IMemoryToken> token = memblk.token; + sp<IMemory> heap = fetch(token); + if (heap == nullptr) { + return nullptr; + } + return new MemoryBlockImpl(heap, memblk.size, memblk.offset); +} + +} // namespace hardware +} // namespace android diff --git a/libhidlcache/HidlMemoryCache.h b/libhidlcache/HidlMemoryCache.h new file mode 100644 index 0000000..c9a533b --- /dev/null +++ b/libhidlcache/HidlMemoryCache.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef ANDROID_HARDWARD_HIDLMEMORY_CACHE_H +#define ANDROID_HARDWARD_HIDLMEMORY_CACHE_H + +#include <android/hidl/memory/block/1.0/types.h> +#include <android/hidl/memory/token/1.0/IMemoryToken.h> +#include <hidl/HidlBinderSupport.h> +#include <hwbinder/IBinder.h> +#include <utils/RefBase.h> +#include "HidlCache.h" + +namespace android { +namespace hardware { + +struct IMemoryTokenCompare { + using IMemoryToken = ::android::hidl::memory::token::V1_0::IMemoryToken; + bool operator()(const sp<IMemoryToken>& lhs, const sp<IMemoryToken>& rhs) const { + sp<IBinder> lb = toBinder<IMemoryToken>(lhs); + sp<IBinder> rb = toBinder<IMemoryToken>(rhs); + return lb < rb; + } +}; + +// The HidlMemoryCache is a singleton class to provides cache for +// IMemoryToken => ::android::hidl::memory::V1_0::IMemory +// It's an abstraction layer on top of the IMapper and supports, but is +// not limited to, the Ashmem type HidlMemory. +class HidlMemoryCache + : public virtual HidlCache<sp<::android::hidl::memory::token::V1_0::IMemoryToken>, + ::android::hidl::memory::V1_0::IMemory, IMemoryTokenCompare> { + using IMemoryToken = ::android::hidl::memory::token::V1_0::IMemoryToken; + using IMemory = ::android::hidl::memory::V1_0::IMemory; + using MemoryBlock = ::android::hidl::memory::block::V1_0::MemoryBlock; + + public: + virtual sp<IMemory> map(const MemoryBlock& block); + // get the singleton + static sp<HidlMemoryCache> getInstance(); + + protected: + HidlMemoryCache() {} + virtual sp<IMemory> fillLocked(const sp<IMemoryToken>& key) override; +}; + +} // namespace hardware +} // namespace android + +#endif diff --git a/libhidlcache/MemoryDealer.cpp b/libhidlcache/MemoryDealer.cpp new file mode 100644 index 0000000..e5686a7 --- /dev/null +++ b/libhidlcache/MemoryDealer.cpp @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "MemoryDealer" + +#include <hidlcache/MemoryDealer.h> +#include <hidlmemory/HidlMemoryToken.h> +#include <hidlmemory/mapping.h> + +#include <list> + +#include <log/log.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <sys/file.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> + +using std::string; + +namespace android { +namespace hardware { + +class SimpleBestFitAllocator { + enum { PAGE_ALIGNED = 0x00000001 }; + + public: + explicit SimpleBestFitAllocator(size_t size); + ~SimpleBestFitAllocator(); + + size_t allocate(size_t size, uint32_t flags = 0); + status_t deallocate(size_t offset); + size_t size() const; + void dump(const char* tag) const; + void dump(string& res, const char* tag) const; + + static size_t getAllocationAlignment() { return kMemoryAlign; } + + private: + struct chunk_t { + chunk_t(size_t start, size_t size) : start(start), size(size), free(1) {} + size_t start; + size_t size : 28; + int free : 4; + }; + using List = std::list<chunk_t*>; + using Iterator = std::list<chunk_t*>::iterator; + using IteratorConst = std::list<chunk_t*>::const_iterator; + using Mutex = std::mutex; + using Lock = std::lock_guard<Mutex>; + + ssize_t alloc(size_t size, uint32_t flags); + chunk_t* dealloc(size_t start); + void dump_l(const char* tag) const; + void dump_l(string& res, const char* tag) const; + + static const int kMemoryAlign; + mutable Mutex mLock; + List mList; + size_t mHeapSize; +}; + +MemoryDealer::MemoryDealer(size_t size) : mAllocator(new SimpleBestFitAllocator(size)) {} + +MemoryDealer::~MemoryDealer() { + delete mAllocator; +} + +ssize_t MemoryDealer::allocateOffset(size_t size) { + return mAllocator->allocate(size); +} + +void MemoryDealer::deallocate(size_t offset) { + mAllocator->deallocate(offset); +} + +void MemoryDealer::dump(const char* tag) const { + mAllocator->dump(tag); +} + +size_t MemoryDealer::getAllocationAlignment() { + return SimpleBestFitAllocator::getAllocationAlignment(); +} + +// align all the memory blocks on a cache-line boundary +const int SimpleBestFitAllocator::kMemoryAlign = 32; + +SimpleBestFitAllocator::SimpleBestFitAllocator(size_t size) { + size_t pagesize = getpagesize(); + mHeapSize = ((size + pagesize - 1) & ~(pagesize - 1)); + + chunk_t* node = new chunk_t(0, mHeapSize / kMemoryAlign); + mList.push_front(node); +} + +SimpleBestFitAllocator::~SimpleBestFitAllocator() { + while (mList.size() != 0) { + chunk_t* removed = mList.front(); + mList.pop_front(); +#ifdef __clang_analyzer__ + // Clang static analyzer gets confused in this loop + // 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.front() == removed); +#endif + delete removed; + } +} + +size_t SimpleBestFitAllocator::size() const { + return mHeapSize; +} + +size_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags) { + Lock lock(mLock); + ssize_t offset = alloc(size, flags); + return offset; +} + +status_t SimpleBestFitAllocator::deallocate(size_t offset) { + Lock lock(mLock); + chunk_t const* const freed = dealloc(offset); + if (freed) { + return NO_ERROR; + } + return NAME_NOT_FOUND; +} + +ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags) { + if (size == 0) { + return 0; + } + size = (size + kMemoryAlign - 1) / kMemoryAlign; + size_t pagesize = getpagesize(); + + Iterator free_chunk_p = mList.end(); + for (Iterator p = mList.begin(); p != mList.end(); p++) { + chunk_t* cur = *p; + int extra = 0; + if (flags & PAGE_ALIGNED) extra = (-cur->start & ((pagesize / kMemoryAlign) - 1)); + + // best fit + if (cur->free && (cur->size >= (size + extra))) { + if ((free_chunk_p == mList.end()) || (cur->size < (*free_chunk_p)->size)) { + free_chunk_p = p; + } + if (cur->size == size) { + break; + } + } + } + if (free_chunk_p != mList.end()) { + chunk_t* free_chunk = *free_chunk_p; + const size_t free_size = free_chunk->size; + free_chunk->free = 0; + free_chunk->size = size; + if (free_size > size) { + int extra = 0; + if (flags & PAGE_ALIGNED) + extra = (-free_chunk->start & ((pagesize / kMemoryAlign) - 1)); + if (extra) { + chunk_t* split = new chunk_t(free_chunk->start, extra); + free_chunk->start += extra; + mList.insert(free_chunk_p, split); + } + + ALOGE_IF( + (flags & PAGE_ALIGNED) && ((free_chunk->start * kMemoryAlign) & (pagesize - 1)), + "PAGE_ALIGNED requested, but page is not aligned!!!"); + + const ssize_t tail_free = free_size - (size + extra); + if (tail_free > 0) { + chunk_t* split = new chunk_t(free_chunk->start + free_chunk->size, tail_free); + mList.insert(++free_chunk_p, split); + } + } + return (free_chunk->start) * kMemoryAlign; + } + return NO_MEMORY; +} + +SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start) { + start = start / kMemoryAlign; + + for (Iterator pos = mList.begin(); pos != mList.end(); pos++) { + chunk_t* cur = *pos; + if (cur->start == start) { + LOG_FATAL_IF(cur->free, "block at offset 0x%08lX of size 0x%08lX already freed", + cur->start * kMemoryAlign, cur->size * kMemoryAlign); + + // merge freed blocks together + chunk_t* freed = cur; + cur->free = 1; + do { + if (pos != mList.begin()) { + pos--; + chunk_t* const p = *pos; + pos++; + if (p->free || !cur->size) { + freed = p; + p->size += cur->size; + pos = mList.erase(pos); + delete cur; + if (pos == mList.end()) break; + } + } + if (++pos == mList.end()) break; + cur = *pos; + } while (cur && cur->free); + +#ifndef NDEBUG + if (!freed->free) { + dump_l("dealloc (!freed->free)"); + } +#endif + LOG_FATAL_IF(!freed->free, "freed block at offset 0x%08lX of size 0x%08lX is not free!", + freed->start * kMemoryAlign, freed->size * kMemoryAlign); + + return freed; + } + } + return nullptr; +} + +void SimpleBestFitAllocator::dump(const char* tag) const { + Lock lock(mLock); + dump_l(tag); +} + +void SimpleBestFitAllocator::dump_l(const char* tag) const { + string result; + dump_l(result, tag); + ALOGD("%s", result.c_str()); +} + +void SimpleBestFitAllocator::dump(string& result, const char* tag) const { + Lock lock(mLock); + dump_l(result, tag); +} + +void SimpleBestFitAllocator::dump_l(string& result, const char* tag) const { + size_t size = 0; + int32_t i = 0; + const size_t SIZE = 256; + char buffer[SIZE]; + snprintf(buffer, SIZE, " %s (%p, size=%u)\n", tag, this, (unsigned int)mHeapSize); + + result.append(buffer); + + for (IteratorConst pos = mList.begin(); pos != mList.end(); pos++) { + chunk_t const* cur = *pos; + + if (!cur->free) size += cur->size * kMemoryAlign; + + i++; + } + snprintf(buffer, SIZE, " size allocated: %u (%u KB)\n", int(size), int(size / 1024)); + result.append(buffer); +} + +bool HidlMemoryDealer::isOk(const MemoryBlock& memblk) { + return memblk.token != nullptr; +} + +sp<::android::hidl::memory::V1_0::IMemory> HidlMemoryDealer::heap() { + return mHeap; +} + +// The required heap size alignment is 4096 bytes +static const uint64_t kHeapSizeAlignment = (0x1ULL << 12); + +sp<HidlMemoryDealer> HidlMemoryDealer::getInstance(const hidl_memory& mem) { + uint64_t msk = (kHeapSizeAlignment - 1); + if (mem.size() & msk || !(mem.size() & ~msk)) { + ALOGE("size is not aligned to %x", static_cast<uint32_t>(kHeapSizeAlignment)); + return nullptr; + } + sp<IMemory> heap = mapMemory(mem); + if (heap == nullptr) { + ALOGE("fail to mapMemory"); + return nullptr; + } + return new HidlMemoryDealer(heap, mem); +} + +HidlMemoryDealer::HidlMemoryDealer(sp<IMemory> heap, const hidl_memory& mem) + : MemoryDealer(heap->getSize()), + mHeap(heap), + mToken(new HidlMemoryToken(HidlMemory::getInstance(mem))) {} + +::android::hidl::memory::block::V1_0::MemoryBlock HidlMemoryDealer::allocate(size_t size) { + MemoryBlock memblk = {nullptr, 0xFFFFFFFFULL, 0xFFFFFFFFULL}; + ssize_t offset = allocateOffset(size); + if (offset >= 0) { + memblk.token = mToken; + memblk.size = size; + memblk.offset = offset; + } + return memblk; +} + +}; // namespace hardware +}; // namespace android diff --git a/libhidlcache/include/hidlcache/MemoryDealer.h b/libhidlcache/include/hidlcache/MemoryDealer.h new file mode 100644 index 0000000..fceed83 --- /dev/null +++ b/libhidlcache/include/hidlcache/MemoryDealer.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HIDL_MEMORY_DEALER_H +#define ANDROID_HIDL_MEMORY_DEALER_H + +#include <android/hidl/memory/1.0/IMemory.h> +#include <android/hidl/memory/block/1.0/types.h> +#include <stdint.h> +#include <sys/types.h> +namespace android { +namespace hardware { + +class SimpleBestFitAllocator; + +// MemoryDealer allocates/deallocates blocks from a continuous memory region. +// It operates on size and offset and does not depend on any specific data types. +class MemoryDealer : public RefBase { + public: + /// Allocate a block with size. The allocated block is identified with an + /// offset. For example: + /// ssize_t K = dealer->allocateOffset(size); + /// On success, K is positive and points to a subregion K ~ (K+size-1) in the heap. + /// It's negative if the allocation fails. + virtual ssize_t allocateOffset(size_t size); + /// @param offset It points to the block that allocated with allocateOffset previously. + virtual void deallocate(size_t offset); + /// @param tag a string tag used to mark the dump message + virtual void dump(const char* tag) const; + + // allocations are aligned to some value. return that value so clients can account for it. + static size_t getAllocationAlignment(); + + MemoryDealer(size_t size); + virtual ~MemoryDealer(); + + protected: + SimpleBestFitAllocator* mAllocator; +}; + +// It extends the generic MemoryDealer and uses +// - sp<IMemory> to represent the main memory region. +// - MemoryBlock to represent the the block to allocate/deallocate +class HidlMemoryDealer : public MemoryDealer { + using IMemory = ::android::hidl::memory::V1_0::IMemory; + using IMemoryToken = ::android::hidl::memory::token::V1_0::IMemoryToken; + using MemoryBlock = ::android::hidl::memory::block::V1_0::MemoryBlock; + + public: + static bool isOk(const MemoryBlock& memblk); + /// @param memory The memory size must align to 4096 bytes + static sp<HidlMemoryDealer> getInstance(const hidl_memory& memory); + virtual MemoryBlock allocate(size_t size); + virtual sp<IMemory> heap(); + + protected: + /// @param heap It must be acquired with mapMemory(memory) with its + /// argument corresponds to the 2nd argument passed to HidlMemoryDealer. + HidlMemoryDealer(sp<IMemory> heap, const hidl_memory& memory); + sp<IMemory> mHeap; + sp<IMemoryToken> mToken; +}; + +}; // namespace hardware +}; // namespace android + +#endif // ANDROID_HIDL_MEMORY_DEALER_H diff --git a/libhidlcache/include/hidlcache/mapping.h b/libhidlcache/include/hidlcache/mapping.h new file mode 100644 index 0000000..972b7b5 --- /dev/null +++ b/libhidlcache/include/hidlcache/mapping.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef ANDROID_HARDWARE_CACHE_MAPPING_H +#define ANDROID_HARDWARE_CACHE_MAPPING_H + +#include <android/hidl/memory/1.0/IMemory.h> +#include <android/hidl/memory/block/1.0/types.h> +#include <android/hidl/memory/token/1.0/IMemoryToken.h> + +namespace android { +namespace hardware { + +/** + * Returns the IMemory instance corresponding to a MemoryBlock. The heap that + * a MemoryBlock belongs to is stored in an internal cache to reduce the number + * of invocations to the mapMemory(hidl_memory) + * + * Note, a cache entry is maintained by reference count and may be flushed when + * the count decrease to zero. Performance critical part that does not want its + * caches to be flushed can use HidlMemoryCacheLock. + */ +sp<::android::hidl::memory::V1_0::IMemory> mapMemory( + const ::android::hidl::memory::block::V1_0::MemoryBlock& block); + +/** + * Internally, there's a cache pool to keep IMemory instances for heap regions + * that are referred by the MemoryBlock. During development, this + * lockMemoryCache(...) method helps to diagnosis whether the cache is effective + * for a specific key. It returns a RAII object used to lock an IMemory instance + * referred by the key and keep it alive even if the instance is not referred by + * any MemoryBlock. If the cache in interest is already effective. It won't differ + * much in performance w/ wo/ the lockMemoryCache() + * + * @note An IMemory instance that is returned from the mapMemory() is + * initialized in an unlocked state. + */ +sp<RefBase> lockMemoryCache(const sp<::android::hidl::memory::token::V1_0::IMemoryToken> key); + +} // namespace hardware +} // namespace android +#endif diff --git a/libhidlcache/libhidlcache_test.cpp b/libhidlcache/libhidlcache_test.cpp new file mode 100644 index 0000000..e514460 --- /dev/null +++ b/libhidlcache/libhidlcache_test.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "hidl-cache-test" + +#include <android/hidl/allocator/1.0/IAllocator.h> +#include <android/hidl/memory/1.0/IMemory.h> +#include <android/hidl/memory/token/1.0/IMemoryToken.h> +#include <gtest/gtest.h> +#include <hidlcache/MemoryDealer.h> +#include <hidlcache/mapping.h> +#include <hidlmemory/HidlMemoryToken.h> +#include <hidlmemory/mapping.h> +#include "HidlMemoryCache.h" + +#define EXPECT_OK(__ret__) EXPECT_TRUE(isOk(__ret__)) + +template <typename T> +static inline ::testing::AssertionResult isOk(const ::android::hardware::Return<T>& ret) { + return ret.isOk() ? (::testing::AssertionSuccess() << ret.description()) + : (::testing::AssertionFailure() << ret.description()); +} + +namespace android { + +namespace hardware { +void HidlCacheWhiteBoxTest() { + using ::android::hardware::HidlMemoryCache; + using ::android::hardware::HidlMemoryToken; + using ::android::hidl::allocator::V1_0::IAllocator; + using ::android::hidl::memory::V1_0::IMemory; + using ::android::hidl::memory::token::V1_0::IMemoryToken; + using ::android::hidl::memory::block::V1_0::MemoryBlock; + + sp<IAllocator> ashmemAllocator; + + ashmemAllocator = IAllocator::getService("ashmem"); + ASSERT_NE(nullptr, ashmemAllocator.get()); + ASSERT_TRUE(ashmemAllocator->isRemote()); // allocator is always remote + + sp<HidlMemory> mem; + EXPECT_OK(ashmemAllocator->allocate(1024, [&](bool success, const hidl_memory& _mem) { + ASSERT_TRUE(success); + mem = HidlMemory::getInstance(_mem); + })); + + sp<IMemoryToken> token = new HidlMemoryToken(mem); + + MemoryBlock blk = {token, 0x200 /* size */, 0x100 /* offset */}; + sp<IMemoryToken> mtoken = blk.token; + mtoken->get([&](const hidl_memory& mem) { sp<IMemory> memory = mapMemory(mem); }); + + sp<HidlMemoryCache> cache = HidlMemoryCache::getInstance(); + EXPECT_FALSE(cache->cached(token)); + + MemoryBlock blk2 = {token, 0x200 /* size */, 0x300 /* offset */}; + + EXPECT_FALSE(cache->cached(token)); + + { + sp<IMemory> mem1 = cache->fetch(token); + EXPECT_TRUE(cache->cached(token)); + EXPECT_NE(nullptr, cache->getCachedLocked(token).get()); + sp<IMemory> mem2 = cache->fetch(token); + EXPECT_TRUE(cache->cached(token)); + EXPECT_NE(nullptr, cache->getCachedLocked(token).get()); + } + EXPECT_FALSE(cache->cached(token)); + { + sp<IMemory> mem1 = mapMemory(blk); + EXPECT_TRUE(cache->cached(token)); + EXPECT_NE(nullptr, cache->getCachedLocked(token).get()); + uint8_t* data = static_cast<uint8_t*>(static_cast<void*>(mem1->getPointer())); + EXPECT_NE(nullptr, data); + } + { + sp<IMemory> mem2 = mapMemory(blk); + EXPECT_TRUE(cache->cached(token)); + EXPECT_NE(nullptr, cache->getCachedLocked(token).get()); + } + EXPECT_FALSE(cache->cached(token)); + EXPECT_TRUE(cache->lock(token)); + EXPECT_TRUE(cache->cached(token)); + EXPECT_NE(nullptr, cache->getCachedLocked(token).get()); + EXPECT_TRUE(cache->unlock(token)); + EXPECT_FALSE(cache->cached(token)); +} +} // namespace hardware + +class HidlCacheTest : public ::testing::Test {}; + +TEST_F(HidlCacheTest, TestAll) { + hardware::HidlCacheWhiteBoxTest(); +} + +TEST_F(HidlCacheTest, MemoryDealer) { + using ::android::hardware::HidlMemory; + using ::android::hardware::hidl_memory; + using ::android::hardware::HidlMemoryDealer; + using ::android::hidl::allocator::V1_0::IAllocator; + using ::android::hidl::memory::block::V1_0::MemoryBlock; + + sp<IAllocator> ashmemAllocator; + + ashmemAllocator = IAllocator::getService("ashmem"); + sp<HidlMemory> m1; + sp<HidlMemory> m2; + // test MemoryDealer + EXPECT_OK(ashmemAllocator->allocate(2048, [&m1](bool success, const hidl_memory& mem) { + ASSERT_TRUE(success); + m1 = HidlMemory::getInstance(mem); + })); + + EXPECT_OK(ashmemAllocator->allocate(4096, [&m2](bool success, const hidl_memory& mem) { + ASSERT_TRUE(success); + m2 = HidlMemory::getInstance(mem); + })); + + sp<HidlMemoryDealer> dealer; + + // m1 does not statisfy the alignment requirement and should fail. + dealer = HidlMemoryDealer::getInstance(*m1); + EXPECT_EQ(nullptr, dealer.get()); + + dealer = HidlMemoryDealer::getInstance(*m2); + EXPECT_NE(nullptr, dealer.get()); + + EXPECT_EQ(dealer->heap()->getSize(), 4096ULL); + MemoryBlock blk = dealer->allocate(1024); + EXPECT_TRUE(HidlMemoryDealer::isOk(blk)); + MemoryBlock blk2 = dealer->allocate(2048); + EXPECT_TRUE(HidlMemoryDealer::isOk(blk2)); + + MemoryBlock blk3 = dealer->allocate(2048); + EXPECT_FALSE(HidlMemoryDealer::isOk(blk3)); + dealer->deallocate(blk2.offset); + blk3 = dealer->allocate(2048); + EXPECT_TRUE(HidlMemoryDealer::isOk(blk3)); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + +} // namespace android
\ No newline at end of file diff --git a/libhidlcache/mapping.cpp b/libhidlcache/mapping.cpp new file mode 100644 index 0000000..2a23e6f --- /dev/null +++ b/libhidlcache/mapping.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#define LOG_TAG "libhidlmemory" + +#include <map> +#include <mutex> +#include <string> + +#include <hidlmemory/mapping.h> + +#include <android-base/logging.h> +#include <hidl/HidlSupport.h> +#include "HidlMemoryCache.h" + +using android::hardware::HidlMemoryCache; +using android::hidl::memory::block::V1_0::MemoryBlock; +using android::hidl::memory::token::V1_0::IMemoryToken; +using android::hidl::memory::V1_0::IMemory; + +namespace android { +namespace hardware { + +sp<IMemory> mapMemory(const ::android::hidl::memory::block::V1_0::MemoryBlock& block) { + sp<HidlMemoryCache> c = HidlMemoryCache::getInstance(); + return c->map(block); +} + +sp<RefBase> lockMemoryCache(const sp<::android::hidl::memory::token::V1_0::IMemoryToken> key) { + sp<HidlMemoryCache> c = HidlMemoryCache::getInstance(); + return c->lockGuard(key); +} + +} // namespace hardware +} // namespace android diff --git a/libhidlmemory/Android.bp b/libhidlmemory/Android.bp index 2f97d5d..2135ef3 100644 --- a/libhidlmemory/Android.bp +++ b/libhidlmemory/Android.bp @@ -26,6 +26,7 @@ cc_library { "libutils", "libcutils", "libhidlbase", + "libhidltransport", "android.hidl.memory@1.0", "android.hidl.memory.token@1.0", ], diff --git a/test_main.cpp b/test_main.cpp index e4cdd29..2b9f52c 100644 --- a/test_main.cpp +++ b/test_main.cpp @@ -16,16 +16,11 @@ #define LOG_TAG "LibHidlTest" -#pragma clang diagnostic push -#pragma clang diagnostic fatal "-Wpadded" -#include <hidl/HidlInternal.h> -#include <hidl/HidlSupport.h> -#pragma clang diagnostic pop - #include <android-base/logging.h> #include <android/hidl/memory/1.0/IMemory.h> #include <gmock/gmock.h> #include <gtest/gtest.h> +#include <hidl/HidlSupport.h> #include <hidl/ServiceManagement.h> #include <hidl/Status.h> #include <hidl/TaskRunner.h> @@ -33,12 +28,6 @@ #include <fstream> #include <vector> -#ifdef __ANDROID__ -static bool kAndroid = true; -#else -static bool kAndroid = false; -#endif - #define EXPECT_ARRAYEQ(__a1__, __a2__, __size__) EXPECT_TRUE(isArrayEqual(__a1__, __a2__, __size__)) #define EXPECT_2DARRAYEQ(__a1__, __a2__, __size1__, __size2__) \ EXPECT_TRUE(is2dArrayEqual(__a1__, __a2__, __size1__, __size2__)) @@ -330,72 +319,6 @@ TEST_F(LibHidlTest, VecRangeCtorTest) { EXPECT_EQ(sum, 1 + 2 + 3); } -struct FailsIfCopied { - FailsIfCopied() {} - - // add failure if copied since in general this can be expensive - FailsIfCopied(const FailsIfCopied& o) { *this = o; } - FailsIfCopied& operator=(const FailsIfCopied&) { - ADD_FAILURE() << "FailsIfCopied copied"; - return *this; - } - - // fine to move this type since in general this is cheaper - FailsIfCopied(FailsIfCopied&& o) = default; - FailsIfCopied& operator=(FailsIfCopied&&) = default; -}; - -TEST_F(LibHidlTest, VecResizeNoCopy) { - using android::hardware::hidl_vec; - - hidl_vec<FailsIfCopied> noCopies; - noCopies.resize(3); // instantiates three elements - - FailsIfCopied* oldPointer = noCopies.data(); - - noCopies.resize(6); // should move three elements, not copy - - // oldPointer should be invalidated at this point. - // hidl_vec doesn't currently try to realloc but if it ever switches - // to an implementation that does, this test wouldn't do anything. - EXPECT_NE(oldPointer, noCopies.data()); -} - -TEST_F(LibHidlTest, VecFindTest) { - using android::hardware::hidl_vec; - hidl_vec<int32_t> hv1 = {10, 20, 30, 40}; - const hidl_vec<int32_t> hv2 = {1, 2, 3, 4}; - - auto it = hv1.find(20); - EXPECT_EQ(20, *it); - *it = 21; - EXPECT_EQ(21, *it); - it = hv1.find(20); - EXPECT_EQ(hv1.end(), it); - it = hv1.find(21); - EXPECT_EQ(21, *it); - - auto cit = hv2.find(4); - EXPECT_EQ(4, *cit); -} - -TEST_F(LibHidlTest, VecContainsTest) { - using android::hardware::hidl_vec; - hidl_vec<int32_t> hv1 = {10, 20, 30, 40}; - const hidl_vec<int32_t> hv2 = {0, 1, 2, 3, 4}; - - EXPECT_TRUE(hv1.contains(10)); - EXPECT_TRUE(hv1.contains(40)); - EXPECT_FALSE(hv1.contains(1)); - EXPECT_FALSE(hv1.contains(0)); - EXPECT_TRUE(hv2.contains(0)); - EXPECT_FALSE(hv2.contains(10)); - - hv1[0] = 11; - EXPECT_FALSE(hv1.contains(10)); - EXPECT_TRUE(hv1.contains(11)); -} - TEST_F(LibHidlTest, ArrayTest) { using android::hardware::hidl_array; int32_t array[] = {5, 6, 7}; @@ -530,52 +453,6 @@ TEST_F(LibHidlTest, ReturnTest) { EXPECT_EQ(three, ret.withDefault(three)); } -TEST_F(LibHidlTest, ReturnDies) { - using ::android::hardware::Return; - using ::android::hardware::Status; - - EXPECT_DEATH({ Return<void>(Status::fromStatusT(-EBUSY)); }, ""); - EXPECT_DEATH({ Return<void>(Status::fromStatusT(-EBUSY)).isDeadObject(); }, ""); - EXPECT_DEATH( - { - Return<int> ret = Return<int>(Status::fromStatusT(-EBUSY)); - int foo = ret; // should crash here - (void)foo; - ret.isOk(); - }, - ""); -} - -TEST_F(LibHidlTest, DetectUncheckedReturn) { - using ::android::hardware::HidlReturnRestriction; - using ::android::hardware::Return; - using ::android::hardware::setProcessHidlReturnRestriction; - using ::android::hardware::Status; - - setProcessHidlReturnRestriction(HidlReturnRestriction::FATAL_IF_UNCHECKED); - - EXPECT_DEATH( - { - auto ret = Return<void>(Status::ok()); - (void)ret; - }, - ""); - EXPECT_DEATH( - { - auto ret = Return<void>(Status::ok()); - ret = Return<void>(Status::ok()); - ret.isOk(); - }, - ""); - - auto ret = Return<void>(Status::ok()); - (void)ret.isOk(); - ret = Return<void>(Status::ok()); - (void)ret.isOk(); - - setProcessHidlReturnRestriction(HidlReturnRestriction::NONE); -} - std::string toString(const ::android::hardware::Status &s) { using ::android::hardware::operator<<; std::ostringstream oss; @@ -599,10 +476,6 @@ TEST_F(LibHidlTest, StatusStringTest) { } TEST_F(LibHidlTest, PreloadTest) { - // HIDL doesn't have support to load passthrough implementations on host, but we - // could do this by loading implementations from the output directory - if (!kAndroid) GTEST_SKIP(); - using ::android::hardware::preloadPassthroughService; using ::android::hidl::memory::V1_0::IMemory; @@ -615,51 +488,6 @@ TEST_F(LibHidlTest, PreloadTest) { EXPECT_TRUE(isLibraryOpen(kLib)); } -template <typename T, size_t start, size_t end> -static void assertZeroInRange(const T* t) { - static_assert(start < sizeof(T)); - static_assert(end <= sizeof(T)); - - const uint8_t* ptr = reinterpret_cast<const uint8_t*>(t); - - for (size_t i = start; i < end; i++) { - EXPECT_EQ(0, ptr[i]); - } -} - -template <typename T, size_t start, size_t end> -static void uninitTest() { - uint8_t buf[sizeof(T)]; - memset(buf, 0xFF, sizeof(T)); - - T* type = new (buf) T; - assertZeroInRange<T, start, end>(type); - type->~T(); -} - -TEST_F(LibHidlTest, HidlVecUninit) { - using ::android::hardware::hidl_vec; - struct SomeType {}; - static_assert(sizeof(hidl_vec<SomeType>) == 16); - - // padding after mOwnsBuffer - uninitTest<hidl_vec<SomeType>, 13, 16>(); -} -TEST_F(LibHidlTest, HidlHandleUninit) { - using ::android::hardware::hidl_handle; - static_assert(sizeof(hidl_handle) == 16); - - // padding after mOwnsHandle - uninitTest<hidl_handle, 9, 16>(); -} -TEST_F(LibHidlTest, HidlStringUninit) { - using ::android::hardware::hidl_string; - static_assert(sizeof(hidl_string) == 16); - - // padding after mOwnsBuffer - uninitTest<hidl_string, 13, 16>(); -} - int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/transport/Android.bp b/transport/Android.bp index 324dbde..50f277e 100644 --- a/transport/Android.bp +++ b/transport/Android.bp @@ -22,32 +22,23 @@ cc_defaults { "libbase", "liblog", "libutils", + "libhwbinder", "libcutils", + "libvndksupport" ], export_shared_lib_headers: [ "libutils", ], - static_libs: [ - "libhwbinder-impl-internal", - ], target: { - android: { - shared_libs: [ - "libvndksupport", - ], - }, recovery: { - exclude_shared_libs: [ - "libvndksupport", - ], + exclude_shared_libs: ["libvndksupport"], }, }, } cc_library_static { name: "libhidltransport-impl-internal", - host_supported: true, vendor_available: true, recovery_available: true, @@ -103,6 +94,4 @@ cc_library_static { cflags: ["-DENFORCE_VINTF_MANIFEST"] }, }, - - visibility: ["//system/libhidl:__subpackages__"], } diff --git a/transport/HidlBinderSupport.cpp b/transport/HidlBinderSupport.cpp index 02d10d0..352ed78 100644 --- a/transport/HidlBinderSupport.cpp +++ b/transport/HidlBinderSupport.cpp @@ -163,6 +163,20 @@ status_t writeEmbeddedToParcel(const hidl_string &string, parentOffset + hidl_string::kOffsetOfBuffer); } +android::status_t writeToParcel(const hidl_version &version, android::hardware::Parcel& parcel) { + return parcel.writeUint32(static_cast<uint32_t>(version.get_major()) << 16 | version.get_minor()); +} + +hidl_version* readFromParcel(const android::hardware::Parcel& parcel) { + uint32_t version; + android::status_t status = parcel.readUint32(&version); + if (status != OK) { + return nullptr; + } else { + return new hidl_version(version >> 16, version & 0xFFFF); + } +} + status_t readFromParcel(Status *s, const Parcel& parcel) { int32_t exception; status_t status = parcel.readInt32(&exception); diff --git a/transport/HidlLazyUtils.cpp b/transport/HidlLazyUtils.cpp index 08ed676..8e3fdf3 100644 --- a/transport/HidlLazyUtils.cpp +++ b/transport/HidlLazyUtils.cpp @@ -181,11 +181,6 @@ LazyServiceRegistrar::LazyServiceRegistrar() { mImpl = std::make_shared<details::LazyServiceRegistrarImpl>(); } -LazyServiceRegistrar& LazyServiceRegistrar::getInstance() { - static auto registrarInstance = new LazyServiceRegistrar(); - return *registrarInstance; -} - status_t LazyServiceRegistrar::registerService( const sp<::android::hidl::base::V1_0::IBase>& service, const std::string& name) { return mImpl->registerService(service, name); diff --git a/transport/HidlTransportSupport.cpp b/transport/HidlTransportSupport.cpp index e645cd0..b433b70 100644 --- a/transport/HidlTransportSupport.cpp +++ b/transport/HidlTransportSupport.cpp @@ -13,16 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include <hidl/HidlTransportSupport.h> - #include <hidl/HidlBinderSupport.h> -#include "InternalStatic.h" +#include <hidl/HidlTransportSupport.h> +#include <hidl/Static.h> #include <android-base/logging.h> #include <android/hidl/manager/1.0/IServiceManager.h> -#include <linux/sched.h> - namespace android { namespace hardware { @@ -95,10 +92,6 @@ bool setMinSchedulerPolicy(const sp<IBase>& service, int policy, int priority) { return true; } -SchedPrio getMinSchedulerPolicy(const sp<IBase>& service) { - return details::gServicePrioMap->get(service, {SCHED_NORMAL, 0}); -} - bool setRequestingSid(const sp<IBase>& service, bool requesting) { if (service->isRemote()) { LOG(ERROR) << "Can't set requesting sid on remote service."; @@ -115,10 +108,6 @@ bool setRequestingSid(const sp<IBase>& service, bool requesting) { return true; } -bool getRequestingSid(const sp<IBase>& service) { - return details::gServiceSidMap->get(service.get(), false); -} - bool interfacesEqual(const sp<IBase>& left, const sp<IBase>& right) { if (left == nullptr || right == nullptr || !left->isRemote() || !right->isRemote()) { return left == right; diff --git a/transport/InternalStatic.h b/transport/InternalStatic.h index 666b2b6..1dfaae4 100644 --- a/transport/InternalStatic.h +++ b/transport/InternalStatic.h @@ -20,26 +20,19 @@ #ifndef ANDROID_HARDWARE_HIDL_INTERNAL_STATIC_H #define ANDROID_HARDWARE_HIDL_INTERNAL_STATIC_H -#include <hidl/HidlTransportSupport.h> // for SchedPrio #include <hidl/Static.h> namespace android { namespace hardware { namespace details { -// TODO(b/69122224): remove this once no prebuilts reference it +// TODO(b/69122224): remove this // deprecated; use getBnConstructorMap instead. extern DoNotDestruct<BnConstructorMap> gBnConstructorMap; -// TODO(b/69122224): remove this once no prebuilts reference it +// TODO(b/69122224): remove this // deprecated; use getBsConstructorMap instead. extern DoNotDestruct<BsConstructorMap> gBsConstructorMap; -// TODO(b/69122224): remove this once no prebuilts reference it -extern DoNotDestruct<ConcurrentMap<wp<::android::hidl::base::V1_0::IBase>, SchedPrio>> - gServicePrioMap; -// TODO(b/69122224): remove this once no prebuilts reference it -extern DoNotDestruct<ConcurrentMap<wp<::android::hidl::base::V1_0::IBase>, bool>> gServiceSidMap; - } // namespace details } // namespace hardware } // namespace android diff --git a/transport/ServiceManagement.cpp b/transport/ServiceManagement.cpp index 19d1d52..e7bec41 100644 --- a/transport/ServiceManagement.cpp +++ b/transport/ServiceManagement.cpp @@ -14,12 +14,9 @@ * limitations under the License. */ -#define LOG_TAG "HidlServiceManagement" +#define LOG_TAG "ServiceManagement" -#ifdef __ANDROID__ #include <android/dlext.h> -#endif // __ANDROID__ - #include <condition_variable> #include <dlfcn.h> #include <dirent.h> @@ -46,7 +43,7 @@ #include <android-base/strings.h> #include <hwbinder/IPCThreadState.h> #include <hwbinder/Parcel.h> -#if !defined(__ANDROID_RECOVERY__) && defined(__ANDROID__) +#if !defined(__ANDROID_RECOVERY__) #include <vndksupport/linker.h> #endif @@ -58,6 +55,8 @@ #define RE_PATH RE_COMPONENT "(?:[.]" RE_COMPONENT ")*" static const std::regex gLibraryFileNamePattern("(" RE_PATH "@[0-9]+[.][0-9]+)-impl(.*?).so"); +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; @@ -67,6 +66,8 @@ using ::android::hidl::manager::V1_0::IServiceNotification; namespace android { namespace hardware { +static const char* kHwServicemanagerReadyProperty = "hwservicemanager.ready"; + #if defined(__ANDROID_RECOVERY__) static constexpr bool kIsRecovery = true; #else @@ -74,18 +75,11 @@ static constexpr bool kIsRecovery = false; #endif static void waitForHwServiceManager() { - // TODO(b/31559095): need bionic host so that we can use 'prop_info' returned - // from WaitForProperty -#ifdef __ANDROID__ - static const char* kHwServicemanagerReadyProperty = "hwservicemanager.ready"; - using std::literals::chrono_literals::operator""s; - using android::base::WaitForProperty; while (!WaitForProperty(kHwServicemanagerReadyProperty, "true", 1s)) { LOG(WARNING) << "Waited for hwservicemanager.ready for a second, waiting another..."; } -#endif // __ANDROID__ } static std::string binaryName() { @@ -382,6 +376,13 @@ struct PassthroughServiceManager : IServiceManager1_1 { } else if (!eachLib(handle, "SELF", sym)) { return; } + + const char* vtsRootPath = std::getenv("VTS_ROOT_PATH"); + if (vtsRootPath && strlen(vtsRootPath) > 0) { + const std::string halLibraryPathVtsOverride = + std::string(vtsRootPath) + HAL_LIBRARY_PATH_SYSTEM; + paths.insert(paths.begin(), halLibraryPathVtsOverride); + } } #endif @@ -394,7 +395,7 @@ struct PassthroughServiceManager : IServiceManager1_1 { if (kIsRecovery || path == HAL_LIBRARY_PATH_SYSTEM) { handle = dlopen(fullPath.c_str(), dlMode); } else { -#if !defined(__ANDROID_RECOVERY__) && defined(__ANDROID__) +#if !defined(__ANDROID_RECOVERY__) handle = android_load_sphal_library(fullPath.c_str(), dlMode); #endif } @@ -558,18 +559,6 @@ sp<IServiceManager1_1> getPassthroughServiceManager1_1() { return manager; } -std::vector<std::string> getAllHalInstanceNames(const std::string& descriptor) { - std::vector<std::string> ret; - auto sm = defaultServiceManager1_2(); - sm->listManifestByInterface(descriptor, [&](const auto& instances) { - ret.reserve(instances.size()); - for (const auto& i : instances) { - ret.push_back(i); - } - }); - return ret; -} - namespace details { void preloadPassthroughService(const std::string &descriptor) { @@ -734,32 +723,11 @@ bool handleCastError(const Return<bool>& castReturn, const std::string& descript return false; } -#ifdef ENFORCE_VINTF_MANIFEST -static constexpr bool kEnforceVintfManifest = true; -#else -static constexpr bool kEnforceVintfManifest = false; -#endif - -#ifdef LIBHIDL_TARGET_DEBUGGABLE -static constexpr bool kDebuggable = true; -#else -static constexpr bool kDebuggable = false; -#endif - -static inline bool isTrebleTestingOverride() { - if (kEnforceVintfManifest && !kDebuggable) { - // don't allow testing override in production - return false; - } - - const char* env = std::getenv("TREBLE_TESTING_OVERRIDE"); - return env && !strcmp(env, "true"); -} - sp<::android::hidl::base::V1_0::IBase> getRawServiceInternal(const std::string& descriptor, const std::string& instance, bool retry, bool getStub) { - using Transport = IServiceManager1_0::Transport; + using Transport = ::android::hidl::manager::V1_0::IServiceManager::Transport; + using ::android::hidl::manager::V1_0::IServiceManager; sp<Waiter> waiter; sp<IServiceManager1_1> sm; @@ -785,19 +753,23 @@ sp<::android::hidl::base::V1_0::IBase> getRawServiceInternal(const std::string& const bool vintfHwbinder = (transport == Transport::HWBINDER); const bool vintfPassthru = (transport == Transport::PASSTHROUGH); - const bool trebleTestingOverride = isTrebleTestingOverride(); - const bool allowLegacy = !kEnforceVintfManifest || (trebleTestingOverride && kDebuggable); - const bool vintfLegacy = (transport == Transport::EMPTY) && allowLegacy; - if (!kEnforceVintfManifest) { - ALOGE("getService: Potential race detected. The VINTF manifest is not being enforced. If " - "a HAL server has a delay in starting and it is not in the manifest, it will not be " - "retrieved. Please make sure all HALs on this device are in the VINTF manifest and " - "enable PRODUCT_ENFORCE_VINTF_MANIFEST on this device (this is also enabled by " - "PRODUCT_FULL_TREBLE). PRODUCT_ENFORCE_VINTF_MANIFEST will ensure that no race " - "condition is possible here."); - sleep(1); - } +#ifdef ENFORCE_VINTF_MANIFEST + +#ifdef LIBHIDL_TARGET_DEBUGGABLE + const char* env = std::getenv("TREBLE_TESTING_OVERRIDE"); + const bool trebleTestingOverride = env && !strcmp(env, "true"); + const bool vintfLegacy = (transport == Transport::EMPTY) && trebleTestingOverride; +#else // ENFORCE_VINTF_MANIFEST but not LIBHIDL_TARGET_DEBUGGABLE + const bool trebleTestingOverride = false; + const bool vintfLegacy = false; +#endif // LIBHIDL_TARGET_DEBUGGABLE + +#else // not ENFORCE_VINTF_MANIFEST + const char* env = std::getenv("TREBLE_TESTING_OVERRIDE"); + const bool trebleTestingOverride = env && !strcmp(env, "true"); + const bool vintfLegacy = (transport == Transport::EMPTY); +#endif // ENFORCE_VINTF_MANIFEST for (int tries = 0; !getStub && (vintfHwbinder || vintfLegacy); tries++) { if (waiter == nullptr && tries > 0) { @@ -841,7 +813,7 @@ sp<::android::hidl::base::V1_0::IBase> getRawServiceInternal(const std::string& } if (getStub || vintfPassthru || vintfLegacy) { - const sp<IServiceManager1_0> pm = getPassthroughServiceManager(); + const sp<IServiceManager> pm = getPassthroughServiceManager(); if (pm != nullptr) { sp<IBase> base = pm->get(descriptor, instance).withDefault(nullptr); if (!getStub || trebleTestingOverride) { @@ -864,19 +836,6 @@ status_t registerAsServiceInternal(const sp<IBase>& service, const std::string& return INVALID_OPERATION; } - const std::string descriptor = getDescriptor(service.get()); - - if (kEnforceVintfManifest && !isTrebleTestingOverride()) { - using Transport = IServiceManager1_0::Transport; - Transport transport = sm->getTransport(descriptor, name); - - if (transport != Transport::HWBINDER) { - LOG(ERROR) << "Service " << descriptor << "/" << name - << " must be in VINTF manifest in order to register/get."; - return UNKNOWN_ERROR; - } - } - bool registered = false; Return<void> ret = service->interfaceChain([&](const auto& chain) { registered = sm->addWithChain(name.c_str(), service, chain).withDefault(false); @@ -887,7 +846,7 @@ status_t registerAsServiceInternal(const sp<IBase>& service, const std::string& } if (registered) { - onRegistrationImpl(descriptor, name); + onRegistrationImpl(getDescriptor(service.get()), name); } return registered ? OK : UNKNOWN_ERROR; diff --git a/transport/allocator/1.0/Android.bp b/transport/allocator/1.0/Android.bp index 80364a7..a3d885a 100644 --- a/transport/allocator/1.0/Android.bp +++ b/transport/allocator/1.0/Android.bp @@ -14,3 +14,4 @@ hidl_interface { ], gen_java: false, } + diff --git a/transport/allocator/1.0/default/Android.bp b/transport/allocator/1.0/default/Android.bp index 1116f1d..1fdfb26 100644 --- a/transport/allocator/1.0/default/Android.bp +++ b/transport/allocator/1.0/default/Android.bp @@ -26,6 +26,8 @@ cc_binary { shared_libs: [ "android.hidl.allocator@1.0", "libhidlbase", + "libhidltransport", + "libhwbinder", "libbase", "liblog", "libutils", diff --git a/transport/allocator/1.0/utils/Android.bp b/transport/allocator/1.0/utils/Android.bp index b324ef1..9f70963 100644 --- a/transport/allocator/1.0/utils/Android.bp +++ b/transport/allocator/1.0/utils/Android.bp @@ -24,6 +24,7 @@ cc_library { "libbinder", "libcutils", "libhidlbase", + "libhidltransport", "android.hidl.memory@1.0" ], export_include_dirs: ["include"], diff --git a/transport/base/1.0/Android.bp b/transport/base/1.0/Android.bp index f90831e..cebb01b 100644 --- a/transport/base/1.0/Android.bp +++ b/transport/base/1.0/Android.bp @@ -12,3 +12,4 @@ hidl_interface { ], gen_java: true, } + diff --git a/transport/base/1.0/vts/functional/Android.bp b/transport/base/1.0/vts/functional/Android.bp index 38b03f7..f0bd45c 100644 --- a/transport/base/1.0/vts/functional/Android.bp +++ b/transport/base/1.0/vts/functional/Android.bp @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. + cc_test { name: "vts_ibase_test", srcs: [ @@ -24,12 +25,10 @@ cc_test { shared_libs: [ "libbase", "libhidlbase", + "libhidltransport", + "libhwbinder", "liblog", "libutils", - "libprotobuf-cpp-lite", - "libhidl-gen-utils", - ], - static_libs: [ - "libinit_test_utils", ], } + diff --git a/transport/base/1.0/vts/functional/vts_ibase_test.cpp b/transport/base/1.0/vts/functional/vts_ibase_test.cpp index b77b2ad..6d66042 100644 --- a/transport/base/1.0/vts/functional/vts_ibase_test.cpp +++ b/transport/base/1.0/vts/functional/vts_ibase_test.cpp @@ -13,32 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#define LOG_TAG "vts_ibase_test" -#include <algorithm> #include <functional> #include <map> -#include <mutex> #include <string> -#include <thread> -#include <vector> -#include <android-base/logging.h> -#include <android-base/properties.h> -#include <android-base/strings.h> #include <android/hidl/base/1.0/IBase.h> #include <android/hidl/manager/1.0/IServiceManager.h> #include <gtest/gtest.h> -#include <hidl-util/FqInstance.h> #include <hidl/HidlBinderSupport.h> #include <hidl/ServiceManagement.h> -#include <init-test-utils/service_utils.h> -using android::FqInstance; -using android::FQName; -using android::sp; -using android::wp; -using android::base::Result; using android::hardware::hidl_array; using android::hardware::hidl_death_recipient; using android::hardware::hidl_handle; @@ -48,8 +33,8 @@ using android::hardware::IBinder; using android::hardware::toBinder; using android::hidl::base::V1_0::IBase; using android::hidl::manager::V1_0::IServiceManager; -using android::init::ServiceInterfacesMap; -using PidInterfacesMap = std::map<pid_t, std::set<FqInstance>>; +using android::sp; +using android::wp; template <typename T> static inline ::testing::AssertionResult isOk(const ::android::hardware::Return<T>& ret) { @@ -62,40 +47,8 @@ static inline ::testing::AssertionResult isOk(const ::android::hardware::Return< struct Hal { sp<IBase> service; std::string name; // space separated list of android.hidl.foo@1.0::IFoo/instance-name - FqInstance fq_instance; }; -template <typename T> -std::string FqInstancesToString(const T& instances) { - std::set<std::string> instance_strings; - for (const FqInstance& instance : instances) { - instance_strings.insert(instance.string()); - } - return android::base::Join(instance_strings, "\n"); -} - -pid_t GetServiceDebugPid(const std::string& service) { - return android::base::GetIntProperty("init.svc_debug_pid." + service, 0); -} - -std::map<std::string, std::vector<Hal>> gDeclaredServiceHalMap; -std::mutex gDeclaredServiceHalMapMutex; - -void GetHal(const std::string& service, const FqInstance& instance) { - if (instance.getFqName() == android::gIBaseFqName) { - return; - } - - sp<IBase> hal = android::hardware::details::getRawServiceInternal( - instance.getFqName().string(), instance.getInstance(), true /*retry*/, - false /*getStub*/); - // Add to gDeclaredServiceHalMap if getRawServiceInternal() returns (even if - // the returned HAL is null). getRawServiceInternal() won't return if the - // HAL is in the VINTF but unable to start. - std::lock_guard<std::mutex> guard(gDeclaredServiceHalMapMutex); - gDeclaredServiceHalMap[service].push_back(Hal{.service = hal, .fq_instance = instance}); -} - class VtsHalBaseV1_0TargetTest : public ::testing::Test { public: virtual void SetUp() override { @@ -133,7 +86,7 @@ class VtsHalBaseV1_0TargetTest : public ::testing::Test { // include all the names this is registered as for error messages iter->second.name += " " + strName; } else { - all_hals_.insert(iter, {binder, Hal{.service = service, .name = strName}}); + all_hals_.insert(iter, {binder, Hal{service, strName}}); } } })); @@ -147,25 +100,6 @@ class VtsHalBaseV1_0TargetTest : public ::testing::Test { } } - PidInterfacesMap GetPidInterfacesMap() { - PidInterfacesMap result; - EXPECT_OK(default_manager_->debugDump([&result](const auto& list) { - for (const auto& debug_info : list) { - if (debug_info.pid != static_cast<int32_t>(IServiceManager::PidConstant::NO_PID)) { - FQName fqName; - ASSERT_TRUE(fqName.setTo(debug_info.interfaceName.c_str())) - << "Unable to parse interface: '" << debug_info.interfaceName.c_str(); - FqInstance fqInstance; - ASSERT_TRUE(fqInstance.setTo(fqName, debug_info.instanceName.c_str())); - if (fqInstance.getFqName() != android::gIBaseFqName) { - result[debug_info.pid].insert(fqInstance); - } - } - } - })); - return result; - } - // default service manager sp<IServiceManager> default_manager_; @@ -231,76 +165,6 @@ TEST_F(VtsHalBaseV1_0TargetTest, HashChain) { }); } -TEST_F(VtsHalBaseV1_0TargetTest, ServiceProvidesAndDeclaresTheSameInterfaces) { - Result<ServiceInterfacesMap> service_interfaces_map = - android::init::GetOnDeviceServiceInterfacesMap(); - ASSERT_TRUE(service_interfaces_map) << service_interfaces_map.error(); - - // Attempt to get handles to all known declared interfaces. This will cause - // any non-running lazy HALs to start up. - // Results are saved in gDeclaredServiceHalMap. - for (const auto& [service, declared_interfaces] : *service_interfaces_map) { - if (declared_interfaces.empty()) { - LOG(INFO) << "Service '" << service << "' does not declare any interfaces."; - } - for (const auto& instance : declared_interfaces) { - std::thread(GetHal, service, instance).detach(); - } - } - // Allow the threads 5 seconds to attempt to get each HAL. Any HAL whose - // thread is stuck during retrieval is excluded from this test. - sleep(5); - - std::lock_guard<std::mutex> guard(gDeclaredServiceHalMapMutex); - PidInterfacesMap pid_interfaces_map = GetPidInterfacesMap(); - - // For each service that had at least one thread return from attempting to - // retrieve a HAL: - for (const auto& [service, hals] : gDeclaredServiceHalMap) { - // Assert that the service is running. - pid_t pid = GetServiceDebugPid(service); - ASSERT_NE(pid, 0) << "Service '" << service << "' is not running."; - - std::set<FqInstance> declared_interfaces; - for (const auto& hal : hals) { - declared_interfaces.insert(hal.fq_instance); - } - - // Warn for any threads that were stuck when attempting to retrieve a - // HAL. - std::vector<FqInstance> missing_declared_interfaces; - std::set_difference((*service_interfaces_map)[service].begin(), - (*service_interfaces_map)[service].end(), declared_interfaces.begin(), - declared_interfaces.end(), - std::back_inserter(missing_declared_interfaces)); - if (!missing_declared_interfaces.empty()) { - LOG(WARNING) - << "Service '" << service - << "' declares interfaces that are present in the VINTF but unable to start:" - << std::endl - << FqInstancesToString(missing_declared_interfaces); - } - - // Expect that the set of interfaces running at this PID is the same as - // the set of interfaces declared by this service. - std::set<FqInstance> served_interfaces = pid_interfaces_map[pid]; - std::vector<FqInstance> served_declared_diff; - std::set_symmetric_difference(declared_interfaces.begin(), declared_interfaces.end(), - served_interfaces.begin(), served_interfaces.end(), - std::back_inserter(served_declared_diff)); - - EXPECT_TRUE(served_declared_diff.empty()) - << "Service '" << service << "' serves and declares different interfaces." - << std::endl - << " Served:" << std::endl - << FqInstancesToString(served_interfaces) << std::endl - << " Declared: " << std::endl - << FqInstancesToString(declared_interfaces) << std::endl - << " Difference: " << std::endl - << FqInstancesToString(served_declared_diff); - } -} - int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/transport/include/hidl/HidlBinderSupport.h b/transport/include/hidl/HidlBinderSupport.h index 5dec5cd..a098805 100644 --- a/transport/include/hidl/HidlBinderSupport.h +++ b/transport/include/hidl/HidlBinderSupport.h @@ -28,7 +28,7 @@ #include <hwbinder/Parcel.h> #include <log/log.h> // TODO(b/65843592): remove. Too many users depending on this transitively. -// Defines functions for hidl_string, Status, hidl_vec, MQDescriptor, +// Defines functions for hidl_string, hidl_version, Status, hidl_vec, MQDescriptor, // etc. to interact with Parcel. namespace android { @@ -72,6 +72,13 @@ status_t readEmbeddedFromParcel(const hidl_string &string, status_t writeEmbeddedToParcel(const hidl_string &string, Parcel *parcel, size_t parentHandle, size_t parentOffset); +// ---------------------- hidl_version + +status_t writeToParcel(const hidl_version &version, android::hardware::Parcel& parcel); + +// Caller is responsible for freeing the returned object. +hidl_version* readFromParcel(const android::hardware::Parcel& parcel); + // ---------------------- Status // Bear in mind that if the client or service is a Java endpoint, this @@ -178,6 +185,127 @@ template<typename T, MQFlavor flavor> return _hidl_err; } +// ---------------------- pointers for HIDL + +template <typename T> +static status_t readEmbeddedReferenceFromParcel( + T const* * /* bufptr */, + const Parcel & parcel, + size_t parentHandle, + size_t parentOffset, + size_t *handle, + bool *shouldResolveRefInBuffer + ) { + // *bufptr is ignored because, if I am embedded in some + // other buffer, the kernel should have fixed me up already. + bool isPreviouslyWritten; + status_t result = parcel.readEmbeddedReference( + nullptr, // ignored, not written to bufptr. + handle, + parentHandle, + parentOffset, + &isPreviouslyWritten); + // tell caller to run T::readEmbeddedToParcel and + // T::readEmbeddedReferenceToParcel if necessary. + // It is not called here because we don't know if these two are valid methods. + *shouldResolveRefInBuffer = !isPreviouslyWritten; + return result; +} + +template <typename T> +static status_t writeEmbeddedReferenceToParcel( + T const* buf, + Parcel *parcel, size_t parentHandle, size_t parentOffset, + size_t *handle, + bool *shouldResolveRefInBuffer + ) { + + if(buf == nullptr) { + *shouldResolveRefInBuffer = false; + return parcel->writeEmbeddedNullReference(handle, parentHandle, parentOffset); + } + + // find whether the buffer exists + size_t childHandle, childOffset; + status_t result; + bool found; + + result = parcel->findBuffer(buf, sizeof(T), &found, &childHandle, &childOffset); + + // tell caller to run T::writeEmbeddedToParcel and + // T::writeEmbeddedReferenceToParcel if necessary. + // It is not called here because we don't know if these two are valid methods. + *shouldResolveRefInBuffer = !found; + + if(result != OK) { + return result; // bad pointers and length given + } + if(!found) { // did not find it. + return parcel->writeEmbeddedBuffer(buf, sizeof(T), handle, + parentHandle, parentOffset); + } + // found the buffer. easy case. + return parcel->writeEmbeddedReference( + handle, + childHandle, + childOffset, + parentHandle, + parentOffset); +} + +template <typename T> +static status_t readReferenceFromParcel( + T const* *bufptr, + const Parcel & parcel, + size_t *handle, + bool *shouldResolveRefInBuffer + ) { + bool isPreviouslyWritten; + status_t result = parcel.readReference(reinterpret_cast<void const* *>(bufptr), + handle, &isPreviouslyWritten); + // tell caller to run T::readEmbeddedToParcel and + // T::readEmbeddedReferenceToParcel if necessary. + // It is not called here because we don't know if these two are valid methods. + *shouldResolveRefInBuffer = !isPreviouslyWritten; + return result; +} + +template <typename T> +static status_t writeReferenceToParcel( + T const *buf, + Parcel * parcel, + size_t *handle, + bool *shouldResolveRefInBuffer + ) { + + if(buf == nullptr) { + *shouldResolveRefInBuffer = false; + return parcel->writeNullReference(handle); + } + + // find whether the buffer exists + size_t childHandle, childOffset; + status_t result; + bool found; + + result = parcel->findBuffer(buf, sizeof(T), &found, &childHandle, &childOffset); + + // tell caller to run T::writeEmbeddedToParcel and + // T::writeEmbeddedReferenceToParcel if necessary. + // It is not called here because we don't know if these two are valid methods. + *shouldResolveRefInBuffer = !found; + + if(result != OK) { + return result; // bad pointers and length given + } + if(!found) { // did not find it. + return parcel->writeBuffer(buf, sizeof(T), handle); + } + // found the buffer. easy case. + return parcel->writeReference(handle, + childHandle, childOffset); +} + // ---------------------- support for casting interfaces // Constructs a binder for this interface and caches it. If it has already been created diff --git a/transport/include/hidl/HidlLazyUtils.h b/transport/include/hidl/HidlLazyUtils.h index 257de98..2205daa 100644 --- a/transport/include/hidl/HidlLazyUtils.h +++ b/transport/include/hidl/HidlLazyUtils.h @@ -29,13 +29,12 @@ class LazyServiceRegistrarImpl; /** Exits when all HALs registered through this object have 0 clients */ class LazyServiceRegistrar { public: - LazyServiceRegistrar(); - static LazyServiceRegistrar& getInstance(); - status_t registerService(const sp<::android::hidl::base::V1_0::IBase>& service, - const std::string& name = "default"); + 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; + std::shared_ptr<details::LazyServiceRegistrarImpl> mImpl; }; } // namespace hardware diff --git a/transport/include/hidl/HidlTransportSupport.h b/transport/include/hidl/HidlTransportSupport.h index 454a4e5..a132bfa 100644 --- a/transport/include/hidl/HidlTransportSupport.h +++ b/transport/include/hidl/HidlTransportSupport.h @@ -84,13 +84,6 @@ status_t handleTransportPoll(int fd); bool setMinSchedulerPolicy(const sp<::android::hidl::base::V1_0::IBase>& service, int policy, int priority); -struct SchedPrio { - int sched_policy; - int prio; -}; - -SchedPrio getMinSchedulerPolicy(const sp<::android::hidl::base::V1_0::IBase>& service); - /** * Sets whether or not this object should request security contexts to be populatd for incoming * calls (e.g. with getCallingSid). @@ -104,12 +97,6 @@ SchedPrio getMinSchedulerPolicy(const sp<::android::hidl::base::V1_0::IBase>& se bool setRequestingSid(const sp<::android::hidl::base::V1_0::IBase>& service, bool requesting); /** - * Says whether or not this service is requesting a SID. If this was set after the service was - * sent to another process, then it will not take effect. - */ -bool getRequestingSid(const sp<::android::hidl::base::V1_0::IBase>& service); - -/** * 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. diff --git a/transport/include/hidl/LegacySupport.h b/transport/include/hidl/LegacySupport.h index 7cb72a9..1e983eb 100644 --- a/transport/include/hidl/LegacySupport.h +++ b/transport/include/hidl/LegacySupport.h @@ -26,12 +26,9 @@ namespace android { namespace hardware { namespace details { -template <typename Interface> -using RegisterServiceCb = std::function<status_t(const sp<Interface>&, const std::string&)>; - -template <class Interface, class ExpectInterface = Interface> +template <class Interface, typename Func> __attribute__((warn_unused_result)) status_t registerPassthroughServiceImplementation( - RegisterServiceCb<Interface> registerServiceCb, const std::string& name = "default") { + Func registerServiceCb, const std::string& name = "default") { sp<Interface> service = Interface::getService(name, true /* getStub */); if (service == nullptr) { @@ -43,10 +40,6 @@ __attribute__((warn_unused_result)) status_t registerPassthroughServiceImplement LOG_FATAL_IF(service->isRemote(), "Implementation of %s/%s is remote!", Interface::descriptor, name.c_str()); - sp<ExpectInterface> expected = ExpectInterface::castFrom(service); - LOG_FATAL_IF(expected == nullptr, "Implementation of %s/%s is not a %s!", Interface::descriptor, - name.c_str(), ExpectInterface::descriptor); - status_t status = registerServiceCb(service, name); if (status == OK) { @@ -64,14 +57,14 @@ __attribute__((warn_unused_result)) status_t registerPassthroughServiceImplement /** * Registers passthrough service implementation. */ -template <class Interface, class ExpectInterface = Interface> +template <class Interface> __attribute__((warn_unused_result)) status_t registerPassthroughServiceImplementation( - const std::string& name = "default") { - return details::registerPassthroughServiceImplementation<Interface, ExpectInterface>( - [](const sp<Interface>& service, const std::string& name) { - return service->registerAsService(name); - }, - name); + const std::string& name = "default") { + return details::registerPassthroughServiceImplementation<Interface>( + [](const sp<Interface>& service, const std::string& name) { + return service->registerAsService(name); + }, + name); } /** @@ -79,11 +72,11 @@ __attribute__((warn_unused_result)) status_t registerPassthroughServiceImplement * * Return value is exit status. */ -template <class Interface, class ExpectInterface = Interface> +template <class Interface> __attribute__((warn_unused_result)) status_t defaultPassthroughServiceImplementation( - const std::string& name, size_t maxThreads = 1) { + const std::string& name, size_t maxThreads = 1) { configureRpcThreadpool(maxThreads, true); - status_t result = registerPassthroughServiceImplementation<Interface, ExpectInterface>(name); + status_t result = registerPassthroughServiceImplementation<Interface>(name); if (result != OK) { return result; @@ -92,11 +85,10 @@ __attribute__((warn_unused_result)) status_t defaultPassthroughServiceImplementa joinRpcThreadpool(); return UNKNOWN_ERROR; } -template <class Interface, class ExpectInterface = Interface> -__attribute__((warn_unused_result)) status_t defaultPassthroughServiceImplementation( - size_t maxThreads = 1) { - return defaultPassthroughServiceImplementation<Interface, ExpectInterface>("default", - maxThreads); +template<class Interface> +__attribute__((warn_unused_result)) +status_t defaultPassthroughServiceImplementation(size_t maxThreads = 1) { + return defaultPassthroughServiceImplementation<Interface>("default", maxThreads); } /** @@ -107,15 +99,20 @@ __attribute__((warn_unused_result)) status_t defaultPassthroughServiceImplementa * 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, class ExpectInterface = Interface> +template <class Interface> __attribute__((warn_unused_result)) status_t registerLazyPassthroughServiceImplementation( - const std::string& name = "default") { - return details::registerPassthroughServiceImplementation<Interface, ExpectInterface>( - [](const sp<Interface>& service, const std::string& name) { - using android::hardware::LazyServiceRegistrar; - return LazyServiceRegistrar::getInstance().registerService(service, name); - }, - name); + 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); } /** @@ -124,12 +121,11 @@ __attribute__((warn_unused_result)) status_t registerLazyPassthroughServiceImple * * Return value is exit status. */ -template <class Interface, class ExpectInterface = Interface> +template <class Interface> __attribute__((warn_unused_result)) status_t defaultLazyPassthroughServiceImplementation( - const std::string& name, size_t maxThreads = 1) { + const std::string& name, size_t maxThreads = 1) { configureRpcThreadpool(maxThreads, true); - status_t result = - registerLazyPassthroughServiceImplementation<Interface, ExpectInterface>(name); + status_t result = registerLazyPassthroughServiceImplementation<Interface>(name); if (result != OK) { return result; @@ -138,11 +134,10 @@ __attribute__((warn_unused_result)) status_t defaultLazyPassthroughServiceImplem joinRpcThreadpool(); return UNKNOWN_ERROR; } -template <class Interface, class ExpectInterface = Interface> +template <class Interface> __attribute__((warn_unused_result)) status_t defaultLazyPassthroughServiceImplementation( - size_t maxThreads = 1) { - return defaultLazyPassthroughServiceImplementation<Interface, ExpectInterface>("default", - maxThreads); + size_t maxThreads = 1) { + return defaultLazyPassthroughServiceImplementation<Interface>("default", maxThreads); } } // namespace hardware diff --git a/transport/include/hidl/ServiceManagement.h b/transport/include/hidl/ServiceManagement.h index 4573a25..a962034 100644 --- a/transport/include/hidl/ServiceManagement.h +++ b/transport/include/hidl/ServiceManagement.h @@ -18,7 +18,6 @@ #define ANDROID_HARDWARE_ISERVICE_MANAGER_H #include <string> -#include <vector> #include <android/hidl/base/1.0/IBase.h> #include <utils/StrongPointer.h> @@ -72,14 +71,6 @@ sp<::android::hidl::manager::V1_0::IServiceManager> getPassthroughServiceManager sp<::android::hidl::manager::V1_1::IServiceManager> getPassthroughServiceManager1_1(); /** - * Given a descriptor (e.g. from IFoo::descriptor), return a list of all instance names - * on a device (e.g. the VINTF manifest). These HALs may not be currently running, but - * the expectation is that if they aren't running, they should start as lazy HALs. - * So, getService should return for each of these instance names. - */ -std::vector<std::string> getAllHalInstanceNames(const std::string& descriptor); - -/** * Given a service that is in passthrough mode, this function will go ahead and load the * required passthrough module library (but not call HIDL_FETCH_I* functions to instantiate it). * diff --git a/transport/include/hidl/Static.h b/transport/include/hidl/Static.h index 3f6203c..be74bae 100644 --- a/transport/include/hidl/Static.h +++ b/transport/include/hidl/Static.h @@ -32,6 +32,17 @@ namespace android { namespace hardware { namespace details { +struct SchedPrio { + int sched_policy; + int prio; +}; + +// 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 DoNotDestruct<ConcurrentMap<const ::android::hidl::base::V1_0::IBase*, diff --git a/transport/manager/1.0/Android.bp b/transport/manager/1.0/Android.bp index c91dcd2..869c58e 100644 --- a/transport/manager/1.0/Android.bp +++ b/transport/manager/1.0/Android.bp @@ -15,3 +15,4 @@ hidl_interface { ], gen_java: true, } + diff --git a/transport/manager/1.1/Android.bp b/transport/manager/1.1/Android.bp index 82545e5..407dfa3 100644 --- a/transport/manager/1.1/Android.bp +++ b/transport/manager/1.1/Android.bp @@ -15,3 +15,4 @@ hidl_interface { ], gen_java: true, } + diff --git a/transport/manager/1.2/Android.bp b/transport/manager/1.2/Android.bp index e7ee143..3f02f78 100644 --- a/transport/manager/1.2/Android.bp +++ b/transport/manager/1.2/Android.bp @@ -17,3 +17,4 @@ hidl_interface { ], gen_java: true, } + diff --git a/transport/memory/1.0/Android.bp b/transport/memory/1.0/Android.bp index dd76889..eaa3037 100644 --- a/transport/memory/1.0/Android.bp +++ b/transport/memory/1.0/Android.bp @@ -16,3 +16,4 @@ hidl_interface { ], gen_java: false, } + diff --git a/transport/memory/1.0/default/Android.bp b/transport/memory/1.0/default/Android.bp index f56ee95..d242ddf 100644 --- a/transport/memory/1.0/default/Android.bp +++ b/transport/memory/1.0/default/Android.bp @@ -29,10 +29,12 @@ cc_library_shared { ], shared_libs: [ "libcutils", + "libhwbinder", "libbase", "liblog", "libutils", "libhidlbase", + "libhidltransport", "android.hidl.memory@1.0", ], } diff --git a/transport/memory/1.0/default/HidlFetch.cpp b/transport/memory/1.0/default/HidlFetch.cpp index a636e03..d47cf97 100644 --- a/transport/memory/1.0/default/HidlFetch.cpp +++ b/transport/memory/1.0/default/HidlFetch.cpp @@ -16,11 +16,9 @@ #include "HidlFetch.h" -#include <string_view> - #include "AshmemMapper.h" -static constexpr std::string_view kAshmemMemoryName = "ashmem"; +static std::string kAshmemMemoryName = "ashmem"; namespace android { namespace hidl { diff --git a/transport/safe_union/1.0/Android.bp b/transport/safe_union/1.0/Android.bp index 2760863..88c7d5d 100644 --- a/transport/safe_union/1.0/Android.bp +++ b/transport/safe_union/1.0/Android.bp @@ -12,3 +12,4 @@ hidl_interface { ], gen_java: true, } + diff --git a/transport/token/1.0/Android.bp b/transport/token/1.0/Android.bp index 28f16f7..c0988cb 100644 --- a/transport/token/1.0/Android.bp +++ b/transport/token/1.0/Android.bp @@ -14,3 +14,4 @@ hidl_interface { ], gen_java: true, } + diff --git a/transport/token/1.0/utils/Android.bp b/transport/token/1.0/utils/Android.bp index 8e23c62..cdbdd97 100644 --- a/transport/token/1.0/utils/Android.bp +++ b/transport/token/1.0/utils/Android.bp @@ -25,22 +25,16 @@ cc_library { "HybridInterface.cpp", ], - header_libs: [ - "libbinder_headers", - ], - shared_libs: [ "android.hidl.token@1.0", + "libbinder", "libhidlbase", "liblog", "libutils", ], - export_header_lib_headers: [ - "libbinder_headers", - ], - export_shared_lib_headers: [ + "libbinder", "libhidlbase", ], diff --git a/transport/token/1.0/utils/HybridInterface.cpp b/transport/token/1.0/utils/HybridInterface.cpp index 675db8f..106ad4e 100644 --- a/transport/token/1.0/utils/HybridInterface.cpp +++ b/transport/token/1.0/utils/HybridInterface.cpp @@ -117,4 +117,5 @@ bool deleteHalToken(const HalToken& token) { return static_cast<bool>(transaction); } -} // namespace android +}; // namespace android + diff --git a/transport/token/1.0/utils/include/hidl/HybridInterface.h b/transport/token/1.0/utils/include/hidl/HybridInterface.h index d00a0a1..125d5e8 100644 --- a/transport/token/1.0/utils/include/hidl/HybridInterface.h +++ b/transport/token/1.0/utils/include/hidl/HybridInterface.h @@ -389,10 +389,7 @@ public: \ return getHalVariant().index(); \ } \ constexpr uint32_t I##INTERFACE::sGetHalTokenTransactionCode; \ - static const ::android::StaticString16 I##INTERFACE##_desc_str16( \ - u##NAME); \ - const ::android::String16 I##INTERFACE::descriptor( \ - I##INTERFACE##_desc_str16); \ + const ::android::String16 I##INTERFACE::descriptor(NAME); \ const ::android::String16& \ I##INTERFACE::getInterfaceDescriptor() const { \ return I##INTERFACE::descriptor; \ @@ -560,6 +557,6 @@ HpInterface<BPINTERFACE, CONVERTER, CONVERTERS...>::HpInterface( // ---------------------------------------------------------------------- -} // namespace android +}; // namespace android #endif // ANDROID_HYBRIDINTERFACE_H |