diff options
9 files changed, 629 insertions, 37 deletions
diff --git a/services/vibratorservice/Android.bp b/services/vibratorservice/Android.bp index fa742c593a..75228d6308 100644 --- a/services/vibratorservice/Android.bp +++ b/services/vibratorservice/Android.bp @@ -35,7 +35,7 @@ cc_library_shared { "libhidlbase", "liblog", "libutils", - "android.hardware.vibrator-cpp", + "android.hardware.vibrator-unstable-cpp", "android.hardware.vibrator@1.0", "android.hardware.vibrator@1.1", "android.hardware.vibrator@1.2", diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp index 9672644d8d..7fee82fb19 100644 --- a/services/vibratorservice/VibratorHalWrapper.cpp +++ b/services/vibratorservice/VibratorHalWrapper.cpp @@ -17,7 +17,6 @@ #define LOG_TAG "VibratorHalWrapper" #include <android/hardware/vibrator/1.3/IVibrator.h> -#include <android/hardware/vibrator/BnVibratorCallback.h> #include <android/hardware/vibrator/IVibrator.h> #include <hardware/vibrator.h> @@ -73,17 +72,6 @@ const constexpr char* STATUS_V_1_0_ERROR_MESSAGE_PREFIX = "android::hardware::vibrator::V1_0::Status = "; template <typename T> -HalResult<T> HalResult<T>::fromStatus(binder::Status status, T data) { - if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { - return HalResult<T>::unsupported(); - } - if (status.isOk()) { - return HalResult<T>::ok(data); - } - return HalResult<T>::failed(std::string(status.toString8().c_str())); -} - -template <typename T> HalResult<T> HalResult<T>::fromStatus(V1_0::Status status, T data) { switch (status) { case V1_0::Status::OK: @@ -145,28 +133,16 @@ HalResult<void> HalResult<void>::fromReturn(hardware::Return<R>& ret) { // ------------------------------------------------------------------------------------------------- -class HalCallbackWrapper : public Aidl::BnVibratorCallback { -public: - HalCallbackWrapper(std::function<void()> completionCallback) - : mCompletionCallback(completionCallback) {} - - binder::Status onComplete() override { - mCompletionCallback(); - return binder::Status::ok(); - } - -private: - const std::function<void()> mCompletionCallback; -}; - -// ------------------------------------------------------------------------------------------------- - HalResult<void> AidlHalWrapper::ping() { return HalResult<void>::fromStatus(IInterface::asBinder(getHal())->pingBinder()); } void AidlHalWrapper::tryReconnect() { - sp<Aidl::IVibrator> newHandle = checkVintfService<Aidl::IVibrator>(); + auto result = mReconnectFn(); + if (!result.isOk()) { + return; + } + sp<Aidl::IVibrator> newHandle = result.value(); if (newHandle) { std::lock_guard<std::mutex> lock(mHandleMutex); mHandle = std::move(newHandle); diff --git a/services/vibratorservice/VibratorManagerHalWrapper.cpp b/services/vibratorservice/VibratorManagerHalWrapper.cpp index 71955af31e..9c4166c63c 100644 --- a/services/vibratorservice/VibratorManagerHalWrapper.cpp +++ b/services/vibratorservice/VibratorManagerHalWrapper.cpp @@ -20,11 +20,14 @@ #include <vibratorservice/VibratorManagerHalWrapper.h> +namespace Aidl = android::hardware::vibrator; + namespace android { namespace vibrator { constexpr int32_t SINGLE_VIBRATOR_ID = 0; +const constexpr char* MISSING_VIBRATOR_MESSAGE_PREFIX = "No vibrator with id="; HalResult<void> LegacyManagerHalWrapper::ping() { return mController->ping(); @@ -34,6 +37,10 @@ void LegacyManagerHalWrapper::tryReconnect() { mController->tryReconnect(); } +HalResult<ManagerCapabilities> LegacyManagerHalWrapper::getCapabilities() { + return HalResult<ManagerCapabilities>::ok(ManagerCapabilities::NONE); +} + HalResult<std::vector<int32_t>> LegacyManagerHalWrapper::getVibratorIds() { if (mController->init()) { return HalResult<std::vector<int32_t>>::ok(std::vector<int32_t>(1, SINGLE_VIBRATOR_ID)); @@ -47,7 +54,7 @@ HalResult<std::shared_ptr<HalController>> LegacyManagerHalWrapper::getVibrator(i return HalResult<std::shared_ptr<HalController>>::ok(mController); } // Controller.init did not connect to any vibrator HAL service, so the device has no vibrator. - return HalResult<std::shared_ptr<HalController>>::failed("No vibrator with id = " + + return HalResult<std::shared_ptr<HalController>>::failed(MISSING_VIBRATOR_MESSAGE_PREFIX + std::to_string(id)); } @@ -63,6 +70,135 @@ HalResult<void> LegacyManagerHalWrapper::cancelSynced() { return HalResult<void>::unsupported(); } +// ------------------------------------------------------------------------------------------------- + +std::shared_ptr<HalWrapper> AidlManagerHalWrapper::ManagedHalConnector::connect( + std::shared_ptr<CallbackScheduler> callbackScheduler) { + std::function<HalResult<sp<Aidl::IVibrator>>()> reconnectFn = [&]() { + sp<Aidl::IVibrator> vibrator; + auto result = this->mManager->getHal()->getVibrator(this->mVibratorId, &vibrator); + return HalResult<sp<Aidl::IVibrator>>::fromStatus(result, vibrator); + }; + auto result = reconnectFn(); + if (!result.isOk()) { + return nullptr; + } + auto vibrator = result.value(); + if (!vibrator) { + return nullptr; + } + return std::move(std::make_unique<AidlHalWrapper>(std::move(callbackScheduler), + std::move(vibrator), reconnectFn)); +} + +HalResult<void> AidlManagerHalWrapper::ping() { + return HalResult<void>::fromStatus(IInterface::asBinder(getHal())->pingBinder()); +} + +void AidlManagerHalWrapper::tryReconnect() { + sp<Aidl::IVibratorManager> newHandle = checkVintfService<Aidl::IVibratorManager>(); + if (newHandle) { + std::lock_guard<std::mutex> lock(mHandleMutex); + mHandle = std::move(newHandle); + } +} + +HalResult<ManagerCapabilities> AidlManagerHalWrapper::getCapabilities() { + std::lock_guard<std::mutex> lock(mCapabilitiesMutex); + if (mCapabilities.has_value()) { + // Return copy of cached value. + return HalResult<ManagerCapabilities>::ok(*mCapabilities); + } + int32_t cap = 0; + auto result = getHal()->getCapabilities(&cap); + auto ret = HalResult<ManagerCapabilities>::fromStatus(result, + static_cast<ManagerCapabilities>(cap)); + if (ret.isOk()) { + // Cache copy of returned value. + mCapabilities.emplace(ret.value()); + } + return ret; +} + +HalResult<std::vector<int32_t>> AidlManagerHalWrapper::getVibratorIds() { + std::lock_guard<std::mutex> lock(mVibratorsMutex); + if (mVibratorIds.has_value()) { + // Return copy of cached values. + return HalResult<std::vector<int32_t>>::ok(*mVibratorIds); + } + std::vector<int32_t> ids; + auto result = getHal()->getVibratorIds(&ids); + auto ret = HalResult<std::vector<int32_t>>::fromStatus(result, ids); + if (ret.isOk()) { + // Cache copy of returned value and the individual controllers. + mVibratorIds.emplace(ret.value()); + for (auto& id : ids) { + auto connector = std::make_unique<ManagedHalConnector>(this, id); + auto controller = + std::make_unique<HalController>(std::move(connector), mCallbackScheduler); + mVibrators[id] = std::move(controller); + } + } + return ret; +} + +HalResult<std::shared_ptr<HalController>> AidlManagerHalWrapper::getVibrator(int32_t id) { + // Make sure we cache vibrator ids and initialize the individual controllers. + getVibratorIds(); + std::lock_guard<std::mutex> lock(mVibratorsMutex); + auto it = mVibrators.find(id); + if (it != mVibrators.end()) { + return HalResult<std::shared_ptr<HalController>>::ok(it->second); + } + return HalResult<std::shared_ptr<HalController>>::failed(MISSING_VIBRATOR_MESSAGE_PREFIX + + std::to_string(id)); +} + +HalResult<void> AidlManagerHalWrapper::prepareSynced(const std::vector<int32_t>& ids) { + auto ret = HalResult<void>::fromStatus(getHal()->prepareSynced(ids)); + if (ret.isOk()) { + // Force reload of all vibrator controllers that were prepared for a sync operation here. + // This will trigger calls to getVibrator(id) on each controller, so they can use the + // latest service provided by this manager. + std::lock_guard<std::mutex> lock(mVibratorsMutex); + for (auto& id : ids) { + auto it = mVibrators.find(id); + if (it != mVibrators.end()) { + it->second->tryReconnect(); + } + } + } + return ret; +} + +HalResult<void> AidlManagerHalWrapper::triggerSynced( + const std::function<void()>& completionCallback) { + HalResult<ManagerCapabilities> capabilities = getCapabilities(); + bool supportsCallback = capabilities.isOk() && + static_cast<int32_t>(capabilities.value() & ManagerCapabilities::TRIGGER_CALLBACK); + auto cb = supportsCallback ? new HalCallbackWrapper(completionCallback) : nullptr; + return HalResult<void>::fromStatus(getHal()->triggerSynced(cb)); +} + +HalResult<void> AidlManagerHalWrapper::cancelSynced() { + auto ret = HalResult<void>::fromStatus(getHal()->cancelSynced()); + if (ret.isOk()) { + // Force reload of all vibrator controllers that were prepared for a sync operation before. + // This will trigger calls to getVibrator(id) on each controller, so they can use the + // latest service provided by this manager. + std::lock_guard<std::mutex> lock(mVibratorsMutex); + for (auto& entry : mVibrators) { + entry.second->tryReconnect(); + } + } + return ret; +} + +sp<Aidl::IVibratorManager> AidlManagerHalWrapper::getHal() { + std::lock_guard<std::mutex> lock(mHandleMutex); + return mHandle; +} + }; // namespace vibrator }; // namespace android diff --git a/services/vibratorservice/benchmarks/Android.bp b/services/vibratorservice/benchmarks/Android.bp index c1a03a16a7..d3130f4fc7 100644 --- a/services/vibratorservice/benchmarks/Android.bp +++ b/services/vibratorservice/benchmarks/Android.bp @@ -23,7 +23,7 @@ cc_benchmark { "liblog", "libutils", "libvibratorservice", - "android.hardware.vibrator-cpp", + "android.hardware.vibrator-unstable-cpp", "android.hardware.vibrator@1.0", "android.hardware.vibrator@1.1", "android.hardware.vibrator@1.2", diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h index bcb735d3c4..638b48346b 100644 --- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h +++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h @@ -19,6 +19,7 @@ #include <android-base/thread_annotations.h> #include <android/hardware/vibrator/1.3/IVibrator.h> +#include <android/hardware/vibrator/BnVibratorCallback.h> #include <android/hardware/vibrator/IVibrator.h> #include <binder/IServiceManager.h> @@ -40,7 +41,15 @@ public: } static HalResult<T> unsupported() { return HalResult("", /* unsupported= */ true); } - static HalResult<T> fromStatus(binder::Status status, T data); + static HalResult<T> fromStatus(binder::Status status, T data) { + if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { + return HalResult<T>::unsupported(); + } + if (status.isOk()) { + return HalResult<T>::ok(data); + } + return HalResult<T>::failed(std::string(status.toString8().c_str())); + } static HalResult<T> fromStatus(hardware::vibrator::V1_0::Status status, T data); template <typename R> @@ -99,6 +108,20 @@ private: : mErrorMessage(std::move(errorMessage)), mFailed(true), mUnsupported(false) {} }; +class HalCallbackWrapper : public hardware::vibrator::BnVibratorCallback { +public: + HalCallbackWrapper(std::function<void()> completionCallback) + : mCompletionCallback(completionCallback) {} + + binder::Status onComplete() override { + mCompletionCallback(); + return binder::Status::ok(); + } + +private: + const std::function<void()> mCompletionCallback; +}; + // ------------------------------------------------------------------------------------------------- // Vibrator HAL capabilities. @@ -178,9 +201,16 @@ protected: // Wrapper for the AIDL Vibrator HAL. class AidlHalWrapper : public HalWrapper { public: - AidlHalWrapper(std::shared_ptr<CallbackScheduler> scheduler, - sp<hardware::vibrator::IVibrator> handle) - : HalWrapper(std::move(scheduler)), mHandle(std::move(handle)) {} + AidlHalWrapper( + std::shared_ptr<CallbackScheduler> scheduler, sp<hardware::vibrator::IVibrator> handle, + std::function<HalResult<sp<hardware::vibrator::IVibrator>>()> reconnectFn = + []() { + return HalResult<sp<hardware::vibrator::IVibrator>>::ok( + checkVintfService<hardware::vibrator::IVibrator>()); + }) + : HalWrapper(std::move(scheduler)), + mReconnectFn(reconnectFn), + mHandle(std::move(handle)) {} virtual ~AidlHalWrapper() = default; HalResult<void> ping() override final; @@ -211,6 +241,7 @@ public: const std::function<void()>& completionCallback) override final; private: + const std::function<HalResult<sp<hardware::vibrator::IVibrator>>()> mReconnectFn; std::mutex mHandleMutex; std::mutex mCapabilitiesMutex; std::mutex mSupportedEffectsMutex; diff --git a/services/vibratorservice/include/vibratorservice/VibratorManagerHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorManagerHalWrapper.h index 99947a51b7..309d681c3a 100644 --- a/services/vibratorservice/include/vibratorservice/VibratorManagerHalWrapper.h +++ b/services/vibratorservice/include/vibratorservice/VibratorManagerHalWrapper.h @@ -17,12 +17,47 @@ #ifndef ANDROID_OS_VIBRATOR_MANAGER_HAL_WRAPPER_H #define ANDROID_OS_VIBRATOR_MANAGER_HAL_WRAPPER_H +#include <android/hardware/vibrator/IVibratorManager.h> #include <vibratorservice/VibratorHalController.h> +#include <unordered_map> namespace android { namespace vibrator { +// VibratorManager HAL capabilities. +enum class ManagerCapabilities : int32_t { + NONE = 0, + SYNC = hardware::vibrator::IVibratorManager::CAP_SYNC, + PREPARE_ON = hardware::vibrator::IVibratorManager::CAP_PREPARE_ON, + PREPARE_PERFORM = hardware::vibrator::IVibratorManager::CAP_PREPARE_PERFORM, + PREPARE_COMPOSE = hardware::vibrator::IVibratorManager::CAP_PREPARE_COMPOSE, + MIXED_TRIGGER_ON = hardware::vibrator::IVibratorManager::IVibratorManager::CAP_MIXED_TRIGGER_ON, + MIXED_TRIGGER_PERFORM = hardware::vibrator::IVibratorManager::CAP_MIXED_TRIGGER_PERFORM, + MIXED_TRIGGER_COMPOSE = hardware::vibrator::IVibratorManager::CAP_MIXED_TRIGGER_COMPOSE, + TRIGGER_CALLBACK = hardware::vibrator::IVibratorManager::CAP_TRIGGER_CALLBACK +}; + +inline ManagerCapabilities operator|(ManagerCapabilities lhs, ManagerCapabilities rhs) { + using underlying = typename std::underlying_type<ManagerCapabilities>::type; + return static_cast<ManagerCapabilities>(static_cast<underlying>(lhs) | + static_cast<underlying>(rhs)); +} + +inline ManagerCapabilities& operator|=(ManagerCapabilities& lhs, ManagerCapabilities rhs) { + return lhs = lhs | rhs; +} + +inline ManagerCapabilities operator&(ManagerCapabilities lhs, ManagerCapabilities rhs) { + using underlying = typename std::underlying_type<ManagerCapabilities>::type; + return static_cast<ManagerCapabilities>(static_cast<underlying>(lhs) & + static_cast<underlying>(rhs)); +} + +inline ManagerCapabilities& operator&=(ManagerCapabilities& lhs, ManagerCapabilities rhs) { + return lhs = lhs & rhs; +} + // Wrapper for VibratorManager HAL handlers. class ManagerHalWrapper { public: @@ -36,6 +71,7 @@ public: */ virtual void tryReconnect() = 0; + virtual HalResult<ManagerCapabilities> getCapabilities() = 0; virtual HalResult<std::vector<int32_t>> getVibratorIds() = 0; virtual HalResult<std::shared_ptr<HalController>> getVibrator(int32_t id) = 0; @@ -55,6 +91,7 @@ public: HalResult<void> ping() override final; void tryReconnect() override final; + HalResult<ManagerCapabilities> getCapabilities() override final; HalResult<std::vector<int32_t>> getVibratorIds() override final; HalResult<std::shared_ptr<HalController>> getVibrator(int32_t id) override final; @@ -66,6 +103,53 @@ private: const std::shared_ptr<HalController> mController; }; +// Wrapper for the AIDL VibratorManager HAL. +class AidlManagerHalWrapper : public ManagerHalWrapper { +public: + explicit AidlManagerHalWrapper(std::shared_ptr<CallbackScheduler> callbackScheduler, + sp<hardware::vibrator::IVibratorManager> handle) + : mHandle(std::move(handle)), mCallbackScheduler(callbackScheduler) {} + virtual ~AidlManagerHalWrapper() = default; + + HalResult<void> ping() override final; + void tryReconnect() override final; + + HalResult<ManagerCapabilities> getCapabilities() override final; + HalResult<std::vector<int32_t>> getVibratorIds() override final; + HalResult<std::shared_ptr<HalController>> getVibrator(int32_t id) override final; + + HalResult<void> prepareSynced(const std::vector<int32_t>& ids) override final; + HalResult<void> triggerSynced(const std::function<void()>& completionCallback) override final; + HalResult<void> cancelSynced() override final; + +private: + std::mutex mHandleMutex; + std::mutex mCapabilitiesMutex; + std::mutex mVibratorsMutex; + sp<hardware::vibrator::IVibratorManager> mHandle GUARDED_BY(mHandleMutex); + std::optional<ManagerCapabilities> mCapabilities GUARDED_BY(mCapabilitiesMutex); + std::optional<std::vector<int32_t>> mVibratorIds GUARDED_BY(mVibratorsMutex); + std::unordered_map<int32_t, std::shared_ptr<HalController>> mVibrators + GUARDED_BY(mVibratorsMutex); + std::shared_ptr<CallbackScheduler> mCallbackScheduler; + + sp<hardware::vibrator::IVibratorManager> getHal(); + + // Connector that creates a HalWrapper from an IVibrator loaded from IVibratorManager. + class ManagedHalConnector : public HalConnector { + public: + ManagedHalConnector(AidlManagerHalWrapper* manager, int32_t vibratorId) + : mManager(manager), mVibratorId(vibratorId) {} + ~ManagedHalConnector() = default; + + std::shared_ptr<HalWrapper> connect(std::shared_ptr<CallbackScheduler>) override final; + + private: + AidlManagerHalWrapper* mManager; + const int32_t mVibratorId; + }; +}; + }; // namespace vibrator }; // namespace android diff --git a/services/vibratorservice/test/Android.bp b/services/vibratorservice/test/Android.bp index 5fc6d450c8..6801f766a6 100644 --- a/services/vibratorservice/test/Android.bp +++ b/services/vibratorservice/test/Android.bp @@ -23,6 +23,7 @@ cc_test { "VibratorHalWrapperHidlV1_1Test.cpp", "VibratorHalWrapperHidlV1_2Test.cpp", "VibratorHalWrapperHidlV1_3Test.cpp", + "VibratorManagerHalWrapperAidlTest.cpp", "VibratorManagerHalWrapperLegacyTest.cpp", ], cflags: [ @@ -37,7 +38,7 @@ cc_test { "liblog", "libvibratorservice", "libutils", - "android.hardware.vibrator-cpp", + "android.hardware.vibrator-unstable-cpp", "android.hardware.vibrator@1.0", "android.hardware.vibrator@1.1", "android.hardware.vibrator@1.2", diff --git a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp new file mode 100644 index 0000000000..dd71a6a525 --- /dev/null +++ b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2020 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 "VibratorManagerHalWrapperAidlTest" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include <utils/Log.h> + +#include <vibratorservice/VibratorManagerHalWrapper.h> + +#include "test_utils.h" + +using android::binder::Status; + +using android::hardware::vibrator::CompositeEffect; +using android::hardware::vibrator::CompositePrimitive; +using android::hardware::vibrator::Effect; +using android::hardware::vibrator::EffectStrength; +using android::hardware::vibrator::IVibrator; +using android::hardware::vibrator::IVibratorCallback; +using android::hardware::vibrator::IVibratorManager; + +using namespace android; +using namespace testing; + +class MockBinder : public BBinder { +public: + MOCK_METHOD(status_t, linkToDeath, + (const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags), (override)); + MOCK_METHOD(status_t, unlinkToDeath, + (const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags, + wp<DeathRecipient>* outRecipient), + (override)); + MOCK_METHOD(status_t, pingBinder, (), (override)); +}; + +class MockIVibrator : public IVibrator { +public: + MOCK_METHOD(Status, getCapabilities, (int32_t * ret), (override)); + MOCK_METHOD(Status, off, (), (override)); + MOCK_METHOD(Status, on, (int32_t timeout, const sp<IVibratorCallback>& cb), (override)); + MOCK_METHOD(Status, perform, + (Effect e, EffectStrength s, const sp<IVibratorCallback>& cb, int32_t* ret), + (override)); + MOCK_METHOD(Status, getSupportedEffects, (std::vector<Effect> * ret), (override)); + MOCK_METHOD(Status, setAmplitude, (float amplitude), (override)); + MOCK_METHOD(Status, setExternalControl, (bool enabled), (override)); + MOCK_METHOD(Status, getCompositionDelayMax, (int32_t * ret), (override)); + MOCK_METHOD(Status, getCompositionSizeMax, (int32_t * ret), (override)); + MOCK_METHOD(Status, getSupportedPrimitives, (std::vector<CompositePrimitive> * ret), + (override)); + MOCK_METHOD(Status, getPrimitiveDuration, (CompositePrimitive p, int32_t* ret), (override)); + MOCK_METHOD(Status, compose, + (const std::vector<CompositeEffect>& e, const sp<IVibratorCallback>& cb), + (override)); + MOCK_METHOD(Status, getSupportedAlwaysOnEffects, (std::vector<Effect> * ret), (override)); + MOCK_METHOD(Status, alwaysOnEnable, (int32_t id, Effect e, EffectStrength s), (override)); + MOCK_METHOD(Status, alwaysOnDisable, (int32_t id), (override)); + MOCK_METHOD(int32_t, getInterfaceVersion, (), (override)); + MOCK_METHOD(std::string, getInterfaceHash, (), (override)); + MOCK_METHOD(IBinder*, onAsBinder, (), (override)); +}; + +class MockIVibratorManager : public IVibratorManager { +public: + MOCK_METHOD(Status, getCapabilities, (int32_t * ret), (override)); + MOCK_METHOD(Status, getVibratorIds, (std::vector<int32_t> * ret), (override)); + MOCK_METHOD(Status, getVibrator, (int32_t id, sp<IVibrator>* ret), (override)); + MOCK_METHOD(Status, prepareSynced, (const std::vector<int32_t>& ids), (override)); + MOCK_METHOD(Status, triggerSynced, (const sp<IVibratorCallback>& cb), (override)); + MOCK_METHOD(Status, cancelSynced, (), (override)); + MOCK_METHOD(int32_t, getInterfaceVersion, (), (override)); + MOCK_METHOD(std::string, getInterfaceHash, (), (override)); + MOCK_METHOD(IBinder*, onAsBinder, (), (override)); +}; + +// ------------------------------------------------------------------------------------------------- + +class VibratorManagerHalWrapperAidlTest : public Test { +public: + void SetUp() override { + mMockBinder = new StrictMock<MockBinder>(); + mMockVibrator = new StrictMock<MockIVibrator>(); + mMockHal = new StrictMock<MockIVibratorManager>(); + mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>(); + mWrapper = std::make_unique<vibrator::AidlManagerHalWrapper>(mMockScheduler, mMockHal); + ASSERT_NE(mWrapper, nullptr); + } + +protected: + std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr; + std::unique_ptr<vibrator::ManagerHalWrapper> mWrapper = nullptr; + sp<StrictMock<MockIVibratorManager>> mMockHal = nullptr; + sp<StrictMock<MockIVibrator>> mMockVibrator = nullptr; + sp<StrictMock<MockBinder>> mMockBinder = nullptr; +}; + +// ------------------------------------------------------------------------------------------------- + +static const std::vector<int32_t> kVibratorIds = {1, 2}; +static constexpr int kVibratorId = 1; + +ACTION(TriggerCallback) { + if (arg0 != nullptr) { + arg0->onComplete(); + } +} + +TEST_F(VibratorManagerHalWrapperAidlTest, TestPing) { + EXPECT_CALL(*mMockHal.get(), onAsBinder()) + .Times(Exactly(2)) + .WillRepeatedly(Return(mMockBinder.get())); + EXPECT_CALL(*mMockBinder.get(), pingBinder()) + .Times(Exactly(2)) + .WillOnce(Return(android::OK)) + .WillRepeatedly(Return(android::DEAD_OBJECT)); + + ASSERT_TRUE(mWrapper->ping().isOk()); + ASSERT_TRUE(mWrapper->ping().isFailed()); +} + +TEST_F(VibratorManagerHalWrapperAidlTest, TestGetCapabilitiesDoesNotCacheFailedResult) { + EXPECT_CALL(*mMockHal.get(), getCapabilities(_)) + .Times(Exactly(3)) + .WillOnce( + Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION))) + .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY))) + .WillRepeatedly(DoAll(SetArgPointee<0>(IVibratorManager::CAP_SYNC), Return(Status()))); + + ASSERT_TRUE(mWrapper->getCapabilities().isUnsupported()); + ASSERT_TRUE(mWrapper->getCapabilities().isFailed()); + + auto result = mWrapper->getCapabilities(); + ASSERT_TRUE(result.isOk()); + ASSERT_EQ(vibrator::ManagerCapabilities::SYNC, result.value()); +} + +TEST_F(VibratorManagerHalWrapperAidlTest, TestGetCapabilitiesCachesResult) { + EXPECT_CALL(*mMockHal.get(), getCapabilities(_)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<0>(IVibratorManager::CAP_SYNC), Return(Status()))); + + std::vector<std::thread> threads; + for (int i = 0; i < 10; i++) { + threads.push_back(std::thread([&]() { + auto result = mWrapper->getCapabilities(); + ASSERT_TRUE(result.isOk()); + ASSERT_EQ(vibrator::ManagerCapabilities::SYNC, result.value()); + })); + } + std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); }); + + auto result = mWrapper->getCapabilities(); + ASSERT_TRUE(result.isOk()); + ASSERT_EQ(vibrator::ManagerCapabilities::SYNC, result.value()); +} + +TEST_F(VibratorManagerHalWrapperAidlTest, TestGetVibratorIdsDoesNotCacheFailedResult) { + EXPECT_CALL(*mMockHal.get(), getVibratorIds(_)) + .Times(Exactly(3)) + .WillOnce( + Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION))) + .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY))) + .WillRepeatedly(DoAll(SetArgPointee<0>(kVibratorIds), Return(Status()))); + + ASSERT_TRUE(mWrapper->getVibratorIds().isUnsupported()); + ASSERT_TRUE(mWrapper->getVibratorIds().isFailed()); + + auto result = mWrapper->getVibratorIds(); + ASSERT_TRUE(result.isOk()); + ASSERT_EQ(kVibratorIds, result.value()); +} + +TEST_F(VibratorManagerHalWrapperAidlTest, TestGetVibratorIdsCachesResult) { + EXPECT_CALL(*mMockHal.get(), getVibratorIds(_)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<0>(kVibratorIds), Return(Status()))); + + std::vector<std::thread> threads; + for (int i = 0; i < 10; i++) { + threads.push_back(std::thread([&]() { + auto result = mWrapper->getVibratorIds(); + ASSERT_TRUE(result.isOk()); + ASSERT_EQ(kVibratorIds, result.value()); + })); + } + std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); }); + + auto result = mWrapper->getVibratorIds(); + ASSERT_TRUE(result.isOk()); + ASSERT_EQ(kVibratorIds, result.value()); +} + +TEST_F(VibratorManagerHalWrapperAidlTest, TestGetVibratorWithValidIdReturnsController) { + { + InSequence seq; + EXPECT_CALL(*mMockHal.get(), getVibratorIds(_)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<0>(kVibratorIds), Return(Status()))); + + EXPECT_CALL(*mMockHal.get(), getVibrator(Eq(kVibratorId), _)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<1>(mMockVibrator), Return(Status()))); + } + + auto result = mWrapper->getVibrator(kVibratorId); + ASSERT_TRUE(result.isOk()); + ASSERT_NE(nullptr, result.value().get()); + ASSERT_TRUE(result.value().get()->init()); +} + +TEST_F(VibratorManagerHalWrapperAidlTest, TestGetVibratorWithInvalidIdFails) { + EXPECT_CALL(*mMockHal.get(), getVibratorIds(_)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<0>(kVibratorIds), Return(Status()))); + + ASSERT_TRUE(mWrapper->getVibrator(0).isFailed()); +} + +TEST_F(VibratorManagerHalWrapperAidlTest, TestGetVibratorRecoversVibratorPointer) { + EXPECT_CALL(*mMockHal.get(), getVibratorIds(_)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<0>(kVibratorIds), Return(Status()))); + + EXPECT_CALL(*mMockHal.get(), getVibrator(Eq(kVibratorId), _)) + .Times(Exactly(3)) + .WillOnce(DoAll(SetArgPointee<1>(nullptr), + Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))) + .WillRepeatedly(DoAll(SetArgPointee<1>(mMockVibrator), Return(Status()))); + + EXPECT_CALL(*mMockVibrator.get(), getCapabilities(_)) + .Times(Exactly(3)) + .WillOnce( + Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION))) + .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY))) + .WillRepeatedly(DoAll(SetArgPointee<0>(IVibrator::CAP_ON_CALLBACK), Return(Status()))); + + // Get vibrator controller is successful even if first getVibrator. + auto result = mWrapper->getVibrator(kVibratorId); + ASSERT_TRUE(result.isOk()); + ASSERT_NE(nullptr, result.value().get()); + + auto vibrator = result.value(); + // First getVibrator call fails. + ASSERT_FALSE(vibrator->init()); + // First and second getCapabilities calls fail, reload IVibrator with getVibrator. + ASSERT_FALSE(vibrator->getCapabilities().isOk()); + // Third call to getCapabilities worked after IVibrator reloaded. + ASSERT_TRUE(vibrator->getCapabilities().isOk()); +} + +TEST_F(VibratorManagerHalWrapperAidlTest, TestPrepareSynced) { + EXPECT_CALL(*mMockHal.get(), getVibratorIds(_)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<0>(kVibratorIds), Return(Status()))); + + EXPECT_CALL(*mMockHal.get(), getVibrator(_, _)) + .Times(Exactly(2)) + .WillRepeatedly(DoAll(SetArgPointee<1>(mMockVibrator), Return(Status()))); + + EXPECT_CALL(*mMockHal.get(), prepareSynced(Eq(kVibratorIds))) + .Times(Exactly(3)) + .WillOnce( + Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION))) + .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY))) + .WillRepeatedly(Return(Status())); + + ASSERT_TRUE(mWrapper->getVibratorIds().isOk()); + ASSERT_TRUE(mWrapper->prepareSynced(kVibratorIds).isUnsupported()); + ASSERT_TRUE(mWrapper->prepareSynced(kVibratorIds).isFailed()); + ASSERT_TRUE(mWrapper->prepareSynced(kVibratorIds).isOk()); +} + +TEST_F(VibratorManagerHalWrapperAidlTest, TestTriggerSyncedWithCallbackSupport) { + { + InSequence seq; + EXPECT_CALL(*mMockHal.get(), getCapabilities(_)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<0>(IVibratorManager::CAP_TRIGGER_CALLBACK), + Return(Status()))); + EXPECT_CALL(*mMockHal.get(), triggerSynced(_)) + .Times(Exactly(3)) + .WillOnce(Return( + Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION))) + .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY))) + .WillRepeatedly(DoAll(TriggerCallback(), Return(Status()))); + } + + std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>(); + auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get()); + + ASSERT_TRUE(mWrapper->triggerSynced(callback).isUnsupported()); + ASSERT_TRUE(mWrapper->triggerSynced(callback).isFailed()); + ASSERT_TRUE(mWrapper->triggerSynced(callback).isOk()); + ASSERT_EQ(1, *callbackCounter.get()); +} + +TEST_F(VibratorManagerHalWrapperAidlTest, TestTriggerSyncedWithoutCallbackSupport) { + { + InSequence seq; + EXPECT_CALL(*mMockHal.get(), getCapabilities(_)) + .Times(Exactly(1)) + .WillRepeatedly( + DoAll(SetArgPointee<0>(IVibratorManager::CAP_SYNC), Return(Status()))); + EXPECT_CALL(*mMockHal.get(), triggerSynced(Eq(nullptr))) + .Times(Exactly(1)) + .WillRepeatedly(Return(Status())); + } + + std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>(); + auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get()); + + ASSERT_TRUE(mWrapper->triggerSynced(callback).isOk()); + ASSERT_EQ(0, *callbackCounter.get()); +} + +TEST_F(VibratorManagerHalWrapperAidlTest, TestCancelSynced) { + EXPECT_CALL(*mMockHal.get(), cancelSynced()) + .Times(Exactly(3)) + .WillOnce( + Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION))) + .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY))) + .WillRepeatedly(Return(Status())); + + ASSERT_TRUE(mWrapper->cancelSynced().isUnsupported()); + ASSERT_TRUE(mWrapper->cancelSynced().isFailed()); + ASSERT_TRUE(mWrapper->cancelSynced().isOk()); +} + +TEST_F(VibratorManagerHalWrapperAidlTest, TestCancelSyncedReloadsAllControllers) { + EXPECT_CALL(*mMockHal.get(), getVibratorIds(_)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<0>(kVibratorIds), Return(Status()))); + + EXPECT_CALL(*mMockHal.get(), getVibrator(_, _)) + .Times(Exactly(2)) + .WillRepeatedly(DoAll(SetArgPointee<1>(mMockVibrator), Return(Status()))); + + EXPECT_CALL(*mMockHal.get(), cancelSynced()).Times(Exactly(1)).WillRepeatedly(Return(Status())); + + ASSERT_TRUE(mWrapper->getVibratorIds().isOk()); + ASSERT_TRUE(mWrapper->cancelSynced().isOk()); +} diff --git a/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp b/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp index d5520a18d2..6c2aabb3b1 100644 --- a/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp +++ b/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp @@ -78,6 +78,12 @@ TEST_F(VibratorManagerHalWrapperLegacyTest, TestTryReconnect) { mWrapper->tryReconnect(); } +TEST_F(VibratorManagerHalWrapperLegacyTest, TestGetCapabilities) { + auto result = mWrapper->getCapabilities(); + ASSERT_TRUE(result.isOk()); + ASSERT_EQ(vibrator::ManagerCapabilities::NONE, result.value()); +} + TEST_F(VibratorManagerHalWrapperLegacyTest, TestGetVibratorIds) { std::vector<int32_t> expectedIds; expectedIds.push_back(0); |