Loading services/vibratorservice/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ cc_library_shared { name: "libvibratorservice", srcs: [ "VibratorCallbackScheduler.cpp", "VibratorHalWrapper.cpp", ], Loading services/vibratorservice/VibratorCallbackScheduler.cpp 0 → 100644 +97 −0 Original line number Diff line number Diff line /* * 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. */ #include <chrono> #include <thread> #include <vibratorservice/VibratorCallbackScheduler.h> namespace android { namespace vibrator { // ------------------------------------------------------------------------------------------------- bool DelayedCallback::isExpired() const { return mExpiration <= std::chrono::steady_clock::now(); } DelayedCallback::Timestamp DelayedCallback::getExpiration() const { return mExpiration; } void DelayedCallback::run() const { mCallback(); } bool DelayedCallback::operator<(const DelayedCallback& other) const { return mExpiration < other.mExpiration; } bool DelayedCallback::operator>(const DelayedCallback& other) const { return mExpiration > other.mExpiration; } // ------------------------------------------------------------------------------------------------- CallbackScheduler::~CallbackScheduler() { { std::lock_guard<std::mutex> lock(mMutex); mFinished = true; } mCondition.notify_all(); if (mCallbackThread && mCallbackThread->joinable()) { mCallbackThread->join(); } } void CallbackScheduler::schedule(std::function<void()> callback, std::chrono::milliseconds delay) { { std::lock_guard<std::mutex> lock(mMutex); if (mCallbackThread == nullptr) { mCallbackThread = std::make_unique<std::thread>(&CallbackScheduler::loop, this); } mQueue.emplace(DelayedCallback(callback, delay)); } mCondition.notify_all(); } void CallbackScheduler::loop() { while (true) { std::lock_guard<std::mutex> lock(mMutex); if (mFinished) { // Destructor was called, so let the callback thread die. break; } while (!mQueue.empty() && mQueue.top().isExpired()) { mQueue.top().run(); mQueue.pop(); } if (mQueue.empty()) { // Wait until a new callback is scheduled. mCondition.wait(mMutex); } else { // Wait until next callback expires, or a new one is scheduled. mCondition.wait_until(mMutex, mQueue.top().getExpiration()); } } } // ------------------------------------------------------------------------------------------------- }; // namespace vibrator }; // namespace android services/vibratorservice/VibratorHalWrapper.cpp +122 −70 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <utils/Log.h> #include <vibratorservice/VibratorCallbackScheduler.h> #include <vibratorservice/VibratorHalWrapper.h> using android::hardware::vibrator::CompositeEffect; Loading @@ -46,10 +47,12 @@ namespace vibrator { template <class T> HalResult<T> loadCached(const std::function<HalResult<T>()>& loadFn, std::optional<T>& cache) { if (cache.has_value()) { return HalResult<T>::ok(cache.value()); // Return copy of cached value. return HalResult<T>::ok(*cache); } HalResult<T> ret = loadFn(); if (ret.isOk()) { // Cache copy of returned value. cache.emplace(ret.value()); } return ret; Loading @@ -62,27 +65,6 @@ bool isStaticCastValid(Effect effect) { return castEffect >= *iter.begin() && castEffect <= *std::prev(iter.end()); } template <class I, class T> using perform_fn = hardware::Return<void> (I::*)(T, V1_0::EffectStrength, V1_0::IVibrator::perform_cb); template <class I, class T> HalResult<milliseconds> perform(perform_fn<I, T> performFn, sp<I> handle, T effect, EffectStrength strength) { V1_0::Status status; int32_t lengthMs; V1_0::IVibrator::perform_cb effectCallback = [&status, &lengthMs](V1_0::Status retStatus, uint32_t retLengthMs) { status = retStatus; lengthMs = retLengthMs; }; V1_0::EffectStrength effectStrength = static_cast<V1_0::EffectStrength>(strength); auto result = std::invoke(performFn, handle, effect, effectStrength, effectCallback); return HalResult<milliseconds>::fromReturn(result, status, milliseconds(lengthMs)); } // ------------------------------------------------------------------------------------------------- template <typename T> Loading Loading @@ -179,7 +161,7 @@ HalResult<void> HalResult<void>::fromReturn(hardware::Return<R>& ret) { class HalCallbackWrapper : public Aidl::BnVibratorCallback { public: HalCallbackWrapper(const std::function<void()>& completionCallback) HalCallbackWrapper(std::function<void()> completionCallback) : mCompletionCallback(completionCallback) {} binder::Status onComplete() override { Loading @@ -200,8 +182,17 @@ HalResult<void> AidlHalWrapper::ping() { HalResult<void> AidlHalWrapper::on(milliseconds timeout, const std::function<void()>& completionCallback) { auto cb = new HalCallbackWrapper(completionCallback); return HalResult<void>::fromStatus(mHandle->on(timeout.count(), cb)); HalResult<Capabilities> capabilities = getCapabilities(); bool supportsCallback = capabilities.isOk() && static_cast<int32_t>(capabilities.value() & Capabilities::ON_CALLBACK); auto cb = supportsCallback ? new HalCallbackWrapper(completionCallback) : nullptr; auto ret = HalResult<void>::fromStatus(mHandle->on(timeout.count(), cb)); if (!supportsCallback && ret.isOk()) { mCallbackScheduler->schedule(completionCallback, timeout); } return ret; } HalResult<void> AidlHalWrapper::off() { Loading @@ -227,39 +218,56 @@ HalResult<void> AidlHalWrapper::alwaysOnDisable(int32_t id) { HalResult<Capabilities> AidlHalWrapper::getCapabilities() { std::lock_guard<std::mutex> lock(mCapabilitiesMutex); static auto loadFn = [this]() { int32_t capabilities = 0; auto result = mHandle->getCapabilities(&capabilities); return HalResult<Capabilities>::fromStatus(result, static_cast<Capabilities>(capabilities)); }; return loadCached<Capabilities>(loadFn, mCapabilities); return loadCached<Capabilities>(std::bind(&AidlHalWrapper::getCapabilitiesInternal, this), mCapabilities); } HalResult<std::vector<Effect>> AidlHalWrapper::getSupportedEffects() { std::lock_guard<std::mutex> lock(mSupportedEffectsMutex); static auto loadFn = [this]() { std::vector<Effect> supportedEffects; auto result = mHandle->getSupportedEffects(&supportedEffects); return HalResult<std::vector<Effect>>::fromStatus(result, supportedEffects); }; return loadCached<std::vector<Effect>>(loadFn, mSupportedEffects); return loadCached<std::vector<Effect>>(std::bind(&AidlHalWrapper::getSupportedEffectsInternal, this), mSupportedEffects); } HalResult<milliseconds> AidlHalWrapper::performEffect( Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) { HalResult<Capabilities> capabilities = getCapabilities(); bool supportsCallback = capabilities.isOk() && static_cast<int32_t>(capabilities.value() & Capabilities::PERFORM_CALLBACK); auto cb = supportsCallback ? new HalCallbackWrapper(completionCallback) : nullptr; int32_t lengthMs; auto cb = new HalCallbackWrapper(completionCallback); auto result = mHandle->perform(effect, strength, cb, &lengthMs); return HalResult<milliseconds>::fromStatus(result, milliseconds(lengthMs)); milliseconds length = milliseconds(lengthMs); auto ret = HalResult<milliseconds>::fromStatus(result, length); if (!supportsCallback && ret.isOk()) { mCallbackScheduler->schedule(completionCallback, length); } return ret; } HalResult<void> AidlHalWrapper::performComposedEffect( const std::vector<CompositeEffect>& primitiveEffects, const std::function<void()>& completionCallback) { // This method should always support callbacks, so no need to double check. auto cb = new HalCallbackWrapper(completionCallback); return HalResult<void>::fromStatus(mHandle->compose(primitiveEffects, cb)); } HalResult<Capabilities> AidlHalWrapper::getCapabilitiesInternal() { int32_t capabilities = 0; auto result = mHandle->getCapabilities(&capabilities); return HalResult<Capabilities>::fromStatus(result, static_cast<Capabilities>(capabilities)); } HalResult<std::vector<Effect>> AidlHalWrapper::getSupportedEffectsInternal() { std::vector<Effect> supportedEffects; auto result = mHandle->getSupportedEffects(&supportedEffects); return HalResult<std::vector<Effect>>::fromStatus(result, supportedEffects); } // ------------------------------------------------------------------------------------------------- HalResult<void> HidlHalWrapperV1_0::ping() { Loading @@ -267,10 +275,14 @@ HalResult<void> HidlHalWrapperV1_0::ping() { return HalResult<void>::fromReturn(result); } HalResult<void> HidlHalWrapperV1_0::on(milliseconds timeout, const std::function<void()>&) { HalResult<void> HidlHalWrapperV1_0::on(milliseconds timeout, const std::function<void()>& completionCallback) { auto result = mHandleV1_0->on(timeout.count()); auto status = result.withDefault(V1_0::Status::UNKNOWN_ERROR); return HalResult<void>::fromStatus(status); auto ret = HalResult<void>::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR)); if (ret.isOk()) { mCallbackScheduler->schedule(completionCallback, timeout); } return ret; } HalResult<void> HidlHalWrapperV1_0::off() { Loading Loading @@ -309,11 +321,10 @@ HalResult<std::vector<Effect>> HidlHalWrapperV1_0::getSupportedEffects() { return HalResult<std::vector<Effect>>::unsupported(); } HalResult<milliseconds> HidlHalWrapperV1_0::performEffect(Effect effect, EffectStrength strength, const std::function<void()>&) { HalResult<milliseconds> HidlHalWrapperV1_0::performEffect( Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) { if (isStaticCastValid<V1_0::Effect>(effect)) { V1_0::Effect e = static_cast<V1_0::Effect>(effect); return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength); return performInternalV1_0(effect, strength, completionCallback); } ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s", Loading @@ -334,17 +345,44 @@ HalResult<Capabilities> HidlHalWrapperV1_0::getCapabilitiesInternal() { return HalResult<Capabilities>::fromReturn(result, capabilities); } template <class I, class T> HalResult<milliseconds> HidlHalWrapperV1_0::performInternal( perform_fn<I, T> performFn, sp<I> handle, T effect, EffectStrength strength, const std::function<void()>& completionCallback) { V1_0::Status status; int32_t lengthMs; auto effectCallback = [&status, &lengthMs](V1_0::Status retStatus, uint32_t retLengthMs) { status = retStatus; lengthMs = retLengthMs; }; V1_0::EffectStrength effectStrength = static_cast<V1_0::EffectStrength>(strength); auto result = std::invoke(performFn, handle, effect, effectStrength, effectCallback); milliseconds length = milliseconds(lengthMs); auto ret = HalResult<milliseconds>::fromReturn(result, status, length); if (ret.isOk()) { mCallbackScheduler->schedule(completionCallback, length); } return ret; } HalResult<milliseconds> HidlHalWrapperV1_0::performInternalV1_0( Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) { V1_0::Effect e = static_cast<V1_0::Effect>(effect); return performInternal(&V1_0::IVibrator::perform, mHandleV1_0, e, strength, completionCallback); } // ------------------------------------------------------------------------------------------------- HalResult<milliseconds> HidlHalWrapperV1_1::performEffect(Effect effect, EffectStrength strength, const std::function<void()>&) { HalResult<milliseconds> HidlHalWrapperV1_1::performEffect( Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) { if (isStaticCastValid<V1_0::Effect>(effect)) { V1_0::Effect e = static_cast<V1_0::Effect>(effect); return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength); return performInternalV1_0(effect, strength, completionCallback); } if (isStaticCastValid<V1_1::Effect_1_1>(effect)) { V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect); return perform(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength); return performInternalV1_1(effect, strength, completionCallback); } ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s", Loading @@ -352,21 +390,25 @@ HalResult<milliseconds> HidlHalWrapperV1_1::performEffect(Effect effect, EffectS return HalResult<milliseconds>::unsupported(); } HalResult<milliseconds> HidlHalWrapperV1_1::performInternalV1_1( Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) { V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect); return performInternal(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength, completionCallback); } // ------------------------------------------------------------------------------------------------- HalResult<milliseconds> HidlHalWrapperV1_2::performEffect(Effect effect, EffectStrength strength, const std::function<void()>&) { HalResult<milliseconds> HidlHalWrapperV1_2::performEffect( Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) { if (isStaticCastValid<V1_0::Effect>(effect)) { V1_0::Effect e = static_cast<V1_0::Effect>(effect); return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength); return performInternalV1_0(effect, strength, completionCallback); } if (isStaticCastValid<V1_1::Effect_1_1>(effect)) { V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect); return perform(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength); return performInternalV1_1(effect, strength, completionCallback); } if (isStaticCastValid<V1_2::Effect>(effect)) { V1_2::Effect e = static_cast<V1_2::Effect>(effect); return perform(&V1_2::IVibrator::perform_1_2, mHandleV1_2, e, strength); return performInternalV1_2(effect, strength, completionCallback); } ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s", Loading @@ -374,6 +416,13 @@ HalResult<milliseconds> HidlHalWrapperV1_2::performEffect(Effect effect, EffectS return HalResult<milliseconds>::unsupported(); } HalResult<milliseconds> HidlHalWrapperV1_2::performInternalV1_2( Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) { V1_2::Effect e = static_cast<V1_2::Effect>(effect); return performInternal(&V1_2::IVibrator::perform_1_2, mHandleV1_2, e, strength, completionCallback); } // ------------------------------------------------------------------------------------------------- HalResult<void> HidlHalWrapperV1_3::setExternalControl(bool enabled) { Loading @@ -381,23 +430,19 @@ HalResult<void> HidlHalWrapperV1_3::setExternalControl(bool enabled) { return HalResult<void>::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR)); } HalResult<milliseconds> HidlHalWrapperV1_3::performEffect(Effect effect, EffectStrength strength, const std::function<void()>&) { HalResult<milliseconds> HidlHalWrapperV1_3::performEffect( Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) { if (isStaticCastValid<V1_0::Effect>(effect)) { V1_0::Effect e = static_cast<V1_0::Effect>(effect); return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength); return performInternalV1_0(effect, strength, completionCallback); } if (isStaticCastValid<V1_1::Effect_1_1>(effect)) { V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect); return perform(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength); return performInternalV1_1(effect, strength, completionCallback); } if (isStaticCastValid<V1_2::Effect>(effect)) { V1_2::Effect e = static_cast<V1_2::Effect>(effect); return perform(&V1_2::IVibrator::perform_1_2, mHandleV1_2, e, strength); return performInternalV1_2(effect, strength, completionCallback); } if (isStaticCastValid<V1_3::Effect>(effect)) { V1_3::Effect e = static_cast<V1_3::Effect>(effect); return perform(&V1_3::IVibrator::perform_1_3, mHandleV1_3, e, strength); return performInternalV1_3(effect, strength, completionCallback); } ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s", Loading @@ -418,6 +463,13 @@ HalResult<Capabilities> HidlHalWrapperV1_3::getCapabilitiesInternal() { return HalResult<Capabilities>::fromReturn(result, capabilities); } HalResult<milliseconds> HidlHalWrapperV1_3::performInternalV1_3( Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) { V1_3::Effect e = static_cast<V1_3::Effect>(effect); return performInternal(&V1_3::IVibrator::perform_1_3, mHandleV1_3, e, strength, completionCallback); } // ------------------------------------------------------------------------------------------------- }; // namespace vibrator Loading services/vibratorservice/include/vibratorservice/VibratorCallbackScheduler.h 0 → 100644 +82 −0 Original line number Diff line number Diff line /* * 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. */ #ifndef ANDROID_VIBRATOR_CALLBACK_SCHEDULER_H #define ANDROID_VIBRATOR_CALLBACK_SCHEDULER_H #include <android-base/thread_annotations.h> #include <chrono> #include <condition_variable> #include <queue> #include <thread> namespace android { namespace vibrator { // Wrapper for a callback to be executed after a delay. class DelayedCallback { public: using Timestamp = std::chrono::time_point<std::chrono::steady_clock>; DelayedCallback(std::function<void()> callback, std::chrono::milliseconds delay) : mCallback(callback), mExpiration(std::chrono::steady_clock::now() + delay) {} ~DelayedCallback() = default; void run() const; bool isExpired() const; Timestamp getExpiration() const; // Compare by expiration time, where A < B when A expires first. bool operator<(const DelayedCallback& other) const; bool operator>(const DelayedCallback& other) const; private: std::function<void()> mCallback; Timestamp mExpiration; }; // Schedules callbacks to be executed after a delay. class CallbackScheduler { public: CallbackScheduler() : mCallbackThread(nullptr), mFinished(false) {} virtual ~CallbackScheduler(); virtual void schedule(std::function<void()> callback, std::chrono::milliseconds delay); private: std::condition_variable_any mCondition; std::mutex mMutex; // Lazily instantiated only at the first time this scheduler is used. std::unique_ptr<std::thread> mCallbackThread; // Used to quit the callback thread when this instance is being destroyed. bool mFinished GUARDED_BY(mMutex); // Priority queue with reverse comparator, so tasks that expire first will be on top. std::priority_queue<DelayedCallback, std::vector<DelayedCallback>, std::greater<DelayedCallback>> mQueue GUARDED_BY(mMutex); void loop(); }; }; // namespace vibrator }; // namespace android #endif // ANDROID_VIBRATOR_CALLBACK_SCHEDULER_H services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h +59 −11 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
services/vibratorservice/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ cc_library_shared { name: "libvibratorservice", srcs: [ "VibratorCallbackScheduler.cpp", "VibratorHalWrapper.cpp", ], Loading
services/vibratorservice/VibratorCallbackScheduler.cpp 0 → 100644 +97 −0 Original line number Diff line number Diff line /* * 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. */ #include <chrono> #include <thread> #include <vibratorservice/VibratorCallbackScheduler.h> namespace android { namespace vibrator { // ------------------------------------------------------------------------------------------------- bool DelayedCallback::isExpired() const { return mExpiration <= std::chrono::steady_clock::now(); } DelayedCallback::Timestamp DelayedCallback::getExpiration() const { return mExpiration; } void DelayedCallback::run() const { mCallback(); } bool DelayedCallback::operator<(const DelayedCallback& other) const { return mExpiration < other.mExpiration; } bool DelayedCallback::operator>(const DelayedCallback& other) const { return mExpiration > other.mExpiration; } // ------------------------------------------------------------------------------------------------- CallbackScheduler::~CallbackScheduler() { { std::lock_guard<std::mutex> lock(mMutex); mFinished = true; } mCondition.notify_all(); if (mCallbackThread && mCallbackThread->joinable()) { mCallbackThread->join(); } } void CallbackScheduler::schedule(std::function<void()> callback, std::chrono::milliseconds delay) { { std::lock_guard<std::mutex> lock(mMutex); if (mCallbackThread == nullptr) { mCallbackThread = std::make_unique<std::thread>(&CallbackScheduler::loop, this); } mQueue.emplace(DelayedCallback(callback, delay)); } mCondition.notify_all(); } void CallbackScheduler::loop() { while (true) { std::lock_guard<std::mutex> lock(mMutex); if (mFinished) { // Destructor was called, so let the callback thread die. break; } while (!mQueue.empty() && mQueue.top().isExpired()) { mQueue.top().run(); mQueue.pop(); } if (mQueue.empty()) { // Wait until a new callback is scheduled. mCondition.wait(mMutex); } else { // Wait until next callback expires, or a new one is scheduled. mCondition.wait_until(mMutex, mQueue.top().getExpiration()); } } } // ------------------------------------------------------------------------------------------------- }; // namespace vibrator }; // namespace android
services/vibratorservice/VibratorHalWrapper.cpp +122 −70 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <utils/Log.h> #include <vibratorservice/VibratorCallbackScheduler.h> #include <vibratorservice/VibratorHalWrapper.h> using android::hardware::vibrator::CompositeEffect; Loading @@ -46,10 +47,12 @@ namespace vibrator { template <class T> HalResult<T> loadCached(const std::function<HalResult<T>()>& loadFn, std::optional<T>& cache) { if (cache.has_value()) { return HalResult<T>::ok(cache.value()); // Return copy of cached value. return HalResult<T>::ok(*cache); } HalResult<T> ret = loadFn(); if (ret.isOk()) { // Cache copy of returned value. cache.emplace(ret.value()); } return ret; Loading @@ -62,27 +65,6 @@ bool isStaticCastValid(Effect effect) { return castEffect >= *iter.begin() && castEffect <= *std::prev(iter.end()); } template <class I, class T> using perform_fn = hardware::Return<void> (I::*)(T, V1_0::EffectStrength, V1_0::IVibrator::perform_cb); template <class I, class T> HalResult<milliseconds> perform(perform_fn<I, T> performFn, sp<I> handle, T effect, EffectStrength strength) { V1_0::Status status; int32_t lengthMs; V1_0::IVibrator::perform_cb effectCallback = [&status, &lengthMs](V1_0::Status retStatus, uint32_t retLengthMs) { status = retStatus; lengthMs = retLengthMs; }; V1_0::EffectStrength effectStrength = static_cast<V1_0::EffectStrength>(strength); auto result = std::invoke(performFn, handle, effect, effectStrength, effectCallback); return HalResult<milliseconds>::fromReturn(result, status, milliseconds(lengthMs)); } // ------------------------------------------------------------------------------------------------- template <typename T> Loading Loading @@ -179,7 +161,7 @@ HalResult<void> HalResult<void>::fromReturn(hardware::Return<R>& ret) { class HalCallbackWrapper : public Aidl::BnVibratorCallback { public: HalCallbackWrapper(const std::function<void()>& completionCallback) HalCallbackWrapper(std::function<void()> completionCallback) : mCompletionCallback(completionCallback) {} binder::Status onComplete() override { Loading @@ -200,8 +182,17 @@ HalResult<void> AidlHalWrapper::ping() { HalResult<void> AidlHalWrapper::on(milliseconds timeout, const std::function<void()>& completionCallback) { auto cb = new HalCallbackWrapper(completionCallback); return HalResult<void>::fromStatus(mHandle->on(timeout.count(), cb)); HalResult<Capabilities> capabilities = getCapabilities(); bool supportsCallback = capabilities.isOk() && static_cast<int32_t>(capabilities.value() & Capabilities::ON_CALLBACK); auto cb = supportsCallback ? new HalCallbackWrapper(completionCallback) : nullptr; auto ret = HalResult<void>::fromStatus(mHandle->on(timeout.count(), cb)); if (!supportsCallback && ret.isOk()) { mCallbackScheduler->schedule(completionCallback, timeout); } return ret; } HalResult<void> AidlHalWrapper::off() { Loading @@ -227,39 +218,56 @@ HalResult<void> AidlHalWrapper::alwaysOnDisable(int32_t id) { HalResult<Capabilities> AidlHalWrapper::getCapabilities() { std::lock_guard<std::mutex> lock(mCapabilitiesMutex); static auto loadFn = [this]() { int32_t capabilities = 0; auto result = mHandle->getCapabilities(&capabilities); return HalResult<Capabilities>::fromStatus(result, static_cast<Capabilities>(capabilities)); }; return loadCached<Capabilities>(loadFn, mCapabilities); return loadCached<Capabilities>(std::bind(&AidlHalWrapper::getCapabilitiesInternal, this), mCapabilities); } HalResult<std::vector<Effect>> AidlHalWrapper::getSupportedEffects() { std::lock_guard<std::mutex> lock(mSupportedEffectsMutex); static auto loadFn = [this]() { std::vector<Effect> supportedEffects; auto result = mHandle->getSupportedEffects(&supportedEffects); return HalResult<std::vector<Effect>>::fromStatus(result, supportedEffects); }; return loadCached<std::vector<Effect>>(loadFn, mSupportedEffects); return loadCached<std::vector<Effect>>(std::bind(&AidlHalWrapper::getSupportedEffectsInternal, this), mSupportedEffects); } HalResult<milliseconds> AidlHalWrapper::performEffect( Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) { HalResult<Capabilities> capabilities = getCapabilities(); bool supportsCallback = capabilities.isOk() && static_cast<int32_t>(capabilities.value() & Capabilities::PERFORM_CALLBACK); auto cb = supportsCallback ? new HalCallbackWrapper(completionCallback) : nullptr; int32_t lengthMs; auto cb = new HalCallbackWrapper(completionCallback); auto result = mHandle->perform(effect, strength, cb, &lengthMs); return HalResult<milliseconds>::fromStatus(result, milliseconds(lengthMs)); milliseconds length = milliseconds(lengthMs); auto ret = HalResult<milliseconds>::fromStatus(result, length); if (!supportsCallback && ret.isOk()) { mCallbackScheduler->schedule(completionCallback, length); } return ret; } HalResult<void> AidlHalWrapper::performComposedEffect( const std::vector<CompositeEffect>& primitiveEffects, const std::function<void()>& completionCallback) { // This method should always support callbacks, so no need to double check. auto cb = new HalCallbackWrapper(completionCallback); return HalResult<void>::fromStatus(mHandle->compose(primitiveEffects, cb)); } HalResult<Capabilities> AidlHalWrapper::getCapabilitiesInternal() { int32_t capabilities = 0; auto result = mHandle->getCapabilities(&capabilities); return HalResult<Capabilities>::fromStatus(result, static_cast<Capabilities>(capabilities)); } HalResult<std::vector<Effect>> AidlHalWrapper::getSupportedEffectsInternal() { std::vector<Effect> supportedEffects; auto result = mHandle->getSupportedEffects(&supportedEffects); return HalResult<std::vector<Effect>>::fromStatus(result, supportedEffects); } // ------------------------------------------------------------------------------------------------- HalResult<void> HidlHalWrapperV1_0::ping() { Loading @@ -267,10 +275,14 @@ HalResult<void> HidlHalWrapperV1_0::ping() { return HalResult<void>::fromReturn(result); } HalResult<void> HidlHalWrapperV1_0::on(milliseconds timeout, const std::function<void()>&) { HalResult<void> HidlHalWrapperV1_0::on(milliseconds timeout, const std::function<void()>& completionCallback) { auto result = mHandleV1_0->on(timeout.count()); auto status = result.withDefault(V1_0::Status::UNKNOWN_ERROR); return HalResult<void>::fromStatus(status); auto ret = HalResult<void>::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR)); if (ret.isOk()) { mCallbackScheduler->schedule(completionCallback, timeout); } return ret; } HalResult<void> HidlHalWrapperV1_0::off() { Loading Loading @@ -309,11 +321,10 @@ HalResult<std::vector<Effect>> HidlHalWrapperV1_0::getSupportedEffects() { return HalResult<std::vector<Effect>>::unsupported(); } HalResult<milliseconds> HidlHalWrapperV1_0::performEffect(Effect effect, EffectStrength strength, const std::function<void()>&) { HalResult<milliseconds> HidlHalWrapperV1_0::performEffect( Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) { if (isStaticCastValid<V1_0::Effect>(effect)) { V1_0::Effect e = static_cast<V1_0::Effect>(effect); return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength); return performInternalV1_0(effect, strength, completionCallback); } ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s", Loading @@ -334,17 +345,44 @@ HalResult<Capabilities> HidlHalWrapperV1_0::getCapabilitiesInternal() { return HalResult<Capabilities>::fromReturn(result, capabilities); } template <class I, class T> HalResult<milliseconds> HidlHalWrapperV1_0::performInternal( perform_fn<I, T> performFn, sp<I> handle, T effect, EffectStrength strength, const std::function<void()>& completionCallback) { V1_0::Status status; int32_t lengthMs; auto effectCallback = [&status, &lengthMs](V1_0::Status retStatus, uint32_t retLengthMs) { status = retStatus; lengthMs = retLengthMs; }; V1_0::EffectStrength effectStrength = static_cast<V1_0::EffectStrength>(strength); auto result = std::invoke(performFn, handle, effect, effectStrength, effectCallback); milliseconds length = milliseconds(lengthMs); auto ret = HalResult<milliseconds>::fromReturn(result, status, length); if (ret.isOk()) { mCallbackScheduler->schedule(completionCallback, length); } return ret; } HalResult<milliseconds> HidlHalWrapperV1_0::performInternalV1_0( Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) { V1_0::Effect e = static_cast<V1_0::Effect>(effect); return performInternal(&V1_0::IVibrator::perform, mHandleV1_0, e, strength, completionCallback); } // ------------------------------------------------------------------------------------------------- HalResult<milliseconds> HidlHalWrapperV1_1::performEffect(Effect effect, EffectStrength strength, const std::function<void()>&) { HalResult<milliseconds> HidlHalWrapperV1_1::performEffect( Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) { if (isStaticCastValid<V1_0::Effect>(effect)) { V1_0::Effect e = static_cast<V1_0::Effect>(effect); return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength); return performInternalV1_0(effect, strength, completionCallback); } if (isStaticCastValid<V1_1::Effect_1_1>(effect)) { V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect); return perform(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength); return performInternalV1_1(effect, strength, completionCallback); } ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s", Loading @@ -352,21 +390,25 @@ HalResult<milliseconds> HidlHalWrapperV1_1::performEffect(Effect effect, EffectS return HalResult<milliseconds>::unsupported(); } HalResult<milliseconds> HidlHalWrapperV1_1::performInternalV1_1( Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) { V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect); return performInternal(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength, completionCallback); } // ------------------------------------------------------------------------------------------------- HalResult<milliseconds> HidlHalWrapperV1_2::performEffect(Effect effect, EffectStrength strength, const std::function<void()>&) { HalResult<milliseconds> HidlHalWrapperV1_2::performEffect( Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) { if (isStaticCastValid<V1_0::Effect>(effect)) { V1_0::Effect e = static_cast<V1_0::Effect>(effect); return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength); return performInternalV1_0(effect, strength, completionCallback); } if (isStaticCastValid<V1_1::Effect_1_1>(effect)) { V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect); return perform(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength); return performInternalV1_1(effect, strength, completionCallback); } if (isStaticCastValid<V1_2::Effect>(effect)) { V1_2::Effect e = static_cast<V1_2::Effect>(effect); return perform(&V1_2::IVibrator::perform_1_2, mHandleV1_2, e, strength); return performInternalV1_2(effect, strength, completionCallback); } ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s", Loading @@ -374,6 +416,13 @@ HalResult<milliseconds> HidlHalWrapperV1_2::performEffect(Effect effect, EffectS return HalResult<milliseconds>::unsupported(); } HalResult<milliseconds> HidlHalWrapperV1_2::performInternalV1_2( Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) { V1_2::Effect e = static_cast<V1_2::Effect>(effect); return performInternal(&V1_2::IVibrator::perform_1_2, mHandleV1_2, e, strength, completionCallback); } // ------------------------------------------------------------------------------------------------- HalResult<void> HidlHalWrapperV1_3::setExternalControl(bool enabled) { Loading @@ -381,23 +430,19 @@ HalResult<void> HidlHalWrapperV1_3::setExternalControl(bool enabled) { return HalResult<void>::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR)); } HalResult<milliseconds> HidlHalWrapperV1_3::performEffect(Effect effect, EffectStrength strength, const std::function<void()>&) { HalResult<milliseconds> HidlHalWrapperV1_3::performEffect( Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) { if (isStaticCastValid<V1_0::Effect>(effect)) { V1_0::Effect e = static_cast<V1_0::Effect>(effect); return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength); return performInternalV1_0(effect, strength, completionCallback); } if (isStaticCastValid<V1_1::Effect_1_1>(effect)) { V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect); return perform(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength); return performInternalV1_1(effect, strength, completionCallback); } if (isStaticCastValid<V1_2::Effect>(effect)) { V1_2::Effect e = static_cast<V1_2::Effect>(effect); return perform(&V1_2::IVibrator::perform_1_2, mHandleV1_2, e, strength); return performInternalV1_2(effect, strength, completionCallback); } if (isStaticCastValid<V1_3::Effect>(effect)) { V1_3::Effect e = static_cast<V1_3::Effect>(effect); return perform(&V1_3::IVibrator::perform_1_3, mHandleV1_3, e, strength); return performInternalV1_3(effect, strength, completionCallback); } ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s", Loading @@ -418,6 +463,13 @@ HalResult<Capabilities> HidlHalWrapperV1_3::getCapabilitiesInternal() { return HalResult<Capabilities>::fromReturn(result, capabilities); } HalResult<milliseconds> HidlHalWrapperV1_3::performInternalV1_3( Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) { V1_3::Effect e = static_cast<V1_3::Effect>(effect); return performInternal(&V1_3::IVibrator::perform_1_3, mHandleV1_3, e, strength, completionCallback); } // ------------------------------------------------------------------------------------------------- }; // namespace vibrator Loading
services/vibratorservice/include/vibratorservice/VibratorCallbackScheduler.h 0 → 100644 +82 −0 Original line number Diff line number Diff line /* * 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. */ #ifndef ANDROID_VIBRATOR_CALLBACK_SCHEDULER_H #define ANDROID_VIBRATOR_CALLBACK_SCHEDULER_H #include <android-base/thread_annotations.h> #include <chrono> #include <condition_variable> #include <queue> #include <thread> namespace android { namespace vibrator { // Wrapper for a callback to be executed after a delay. class DelayedCallback { public: using Timestamp = std::chrono::time_point<std::chrono::steady_clock>; DelayedCallback(std::function<void()> callback, std::chrono::milliseconds delay) : mCallback(callback), mExpiration(std::chrono::steady_clock::now() + delay) {} ~DelayedCallback() = default; void run() const; bool isExpired() const; Timestamp getExpiration() const; // Compare by expiration time, where A < B when A expires first. bool operator<(const DelayedCallback& other) const; bool operator>(const DelayedCallback& other) const; private: std::function<void()> mCallback; Timestamp mExpiration; }; // Schedules callbacks to be executed after a delay. class CallbackScheduler { public: CallbackScheduler() : mCallbackThread(nullptr), mFinished(false) {} virtual ~CallbackScheduler(); virtual void schedule(std::function<void()> callback, std::chrono::milliseconds delay); private: std::condition_variable_any mCondition; std::mutex mMutex; // Lazily instantiated only at the first time this scheduler is used. std::unique_ptr<std::thread> mCallbackThread; // Used to quit the callback thread when this instance is being destroyed. bool mFinished GUARDED_BY(mMutex); // Priority queue with reverse comparator, so tasks that expire first will be on top. std::priority_queue<DelayedCallback, std::vector<DelayedCallback>, std::greater<DelayedCallback>> mQueue GUARDED_BY(mMutex); void loop(); }; }; // namespace vibrator }; // namespace android #endif // ANDROID_VIBRATOR_CALLBACK_SCHEDULER_H
services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h +59 −11 File changed.Preview size limit exceeded, changes collapsed. Show changes