diff options
author | Chase Wu <chasewu@google.com> | 2023-01-04 17:03:36 +0800 |
---|---|---|
committer | Chase Wu <chasewu@google.com> | 2023-01-10 16:17:23 +0800 |
commit | bcd846dcba14eb4df5eedf7a48fb8d78051fa99a (patch) | |
tree | 444326570a6d35e0615a527102cc48624aa3a4a9 | |
parent | 0aaebb34f1bf6deaae986d5063cf28b46b22fc58 (diff) |
[DO NOT MERGE] cs40l25: add state polling timeout
Replacing the infinite vibe_state checking to prevent the abnormal non-stop
symptom which would cause HAL stuck on the checking step.
Even if there is a vibration currently playing, we should stop
the current vibration and play the new one.
We can assume this because the Framework will handle
all the prioritization of requests before invoking HAL APIs.
Bug: 250074997
Test: Use previous non-stop FW to test it
Change-Id: I5dfc0cd4eb581d4db23094e9c73ce8e08ad85ea6
-rw-r--r-- | vibrator/cs40l25/Android.bp | 2 | ||||
-rw-r--r-- | vibrator/cs40l25/Hardware.h | 4 | ||||
-rw-r--r-- | vibrator/cs40l25/Vibrator.cpp | 54 | ||||
-rw-r--r-- | vibrator/cs40l25/Vibrator.h | 6 | ||||
-rw-r--r-- | vibrator/cs40l25/android.hardware.vibrator-service.cs40l25.rc | 1 | ||||
-rw-r--r-- | vibrator/cs40l25/tests/mocks.h | 2 | ||||
-rw-r--r-- | vibrator/cs40l25/tests/test-vibrator.cpp | 46 |
7 files changed, 90 insertions, 25 deletions
diff --git a/vibrator/cs40l25/Android.bp b/vibrator/cs40l25/Android.bp index 13d59ad..d968eda 100644 --- a/vibrator/cs40l25/Android.bp +++ b/vibrator/cs40l25/Android.bp @@ -110,7 +110,7 @@ cc_binary { srcs: ["service.cpp"], shared_libs: ["android.hardware.vibrator-impl.cs40l25"], cflags: [ - "-DLOG_TAG=\"android.hardware.vibrator-cs40l25\"", + "-DLOG_TAG=\"Vibrator\"", ], proprietary: true, } diff --git a/vibrator/cs40l25/Hardware.h b/vibrator/cs40l25/Hardware.h index 167e382..e222279 100644 --- a/vibrator/cs40l25/Hardware.h +++ b/vibrator/cs40l25/Hardware.h @@ -72,7 +72,9 @@ class HwApi : public Vibrator::HwApi, private HwApiBase { bool setGpioFallScale(uint32_t value) override { return set(value, &mGpioFallScale); } bool setGpioRiseIndex(uint32_t value) override { return set(value, &mGpioRiseIndex); } bool setGpioRiseScale(uint32_t value) override { return set(value, &mGpioRiseScale); } - bool pollVibeState(bool value) override { return poll(value, &mVibeState); } + bool pollVibeState(uint32_t value, int32_t timeoutMs) override { + return poll(value, &mVibeState, timeoutMs); + } bool setClabEnable(bool value) override { return set(value, &mClabEnable); } bool getAvailablePwleSegments(uint32_t *value) override { return get(value, &mAvailablePwleSegments); diff --git a/vibrator/cs40l25/Vibrator.cpp b/vibrator/cs40l25/Vibrator.cpp index ba4efad..b868cfd 100644 --- a/vibrator/cs40l25/Vibrator.cpp +++ b/vibrator/cs40l25/Vibrator.cpp @@ -65,7 +65,6 @@ static constexpr uint32_t WAVEFORM_LOW_TICK_INDEX = 10; static constexpr uint32_t WAVEFORM_UNSAVED_TRIGGER_QUEUE_INDEX = 65529; static constexpr uint32_t WAVEFORM_TRIGGER_QUEUE_INDEX = 65534; - static constexpr uint32_t VOLTAGE_GLOBAL_SCALE_LEVEL = 5; static constexpr uint8_t VOLTAGE_SCALE_MAX = 100; @@ -77,6 +76,7 @@ static constexpr float AMP_ATTENUATE_STEP_SIZE = 0.125f; static constexpr float EFFECT_FREQUENCY_KHZ = 48.0f; static constexpr auto ASYNC_COMPLETION_TIMEOUT = std::chrono::milliseconds(100); +static constexpr auto POLLING_TIMEOUT = 20; static constexpr int32_t COMPOSE_DELAY_MAX_MS = 10000; static constexpr int32_t COMPOSE_SIZE_MAX = 127; @@ -306,6 +306,7 @@ ndk::ScopedAStatus Vibrator::getCapabilities(int32_t *_aidl_return) { ndk::ScopedAStatus Vibrator::off() { ATRACE_NAME("Vibrator::off"); + ALOGD("Vibrator::off"); setGlobalAmplitude(false); mHwApi->setF0Offset(0); if (!mHwApi->setActivate(0)) { @@ -319,6 +320,7 @@ ndk::ScopedAStatus Vibrator::off() { ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs, const std::shared_ptr<IVibratorCallback> &callback) { ATRACE_NAME("Vibrator::on"); + ALOGD("Vibrator::on"); const uint32_t index = timeoutMs < WAVEFORM_LONG_VIBRATION_THRESHOLD_MS ? WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX : WAVEFORM_LONG_VIBRATION_EFFECT_INDEX; @@ -334,6 +336,7 @@ ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength, const std::shared_ptr<IVibratorCallback> &callback, int32_t *_aidl_return) { ATRACE_NAME("Vibrator::perform"); + ALOGD("Vibrator::perform"); return performEffect(effect, strength, callback, _aidl_return); } @@ -443,6 +446,7 @@ ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive, ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> &composite, const std::shared_ptr<IVibratorCallback> &callback) { ATRACE_NAME("Vibrator::compose"); + ALOGD("Vibrator::compose"); std::ostringstream effectBuilder; std::string effectQueue; @@ -450,6 +454,11 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> &composi return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } + // Reset the mTotalDuration + { + const std::scoped_lock<std::mutex> lock(mTotalDurationMutex); + mTotalDuration = 0; + } for (auto &e : composite) { if (e.scale < 0.0f || e.scale > 1.0f) { return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); @@ -460,6 +469,10 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> &composi return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } effectBuilder << e.delayMs << ","; + { + const std::scoped_lock<std::mutex> lock(mTotalDurationMutex); + mTotalDuration += e.delayMs; + } } if (e.primitive != CompositePrimitive::NOOP) { ndk::ScopedAStatus status; @@ -471,6 +484,10 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> &composi } effectBuilder << effectIndex << "." << intensityToVolLevel(e.scale, effectIndex) << ","; + { + const std::scoped_lock<std::mutex> lock(mTotalDurationMutex); + mTotalDuration += mEffectDurations[effectIndex]; + } } } @@ -497,9 +514,17 @@ ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex, return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } + ALOGD("Vibrator::on"); mHwApi->setEffectIndex(effectIndex); mHwApi->setDuration(timeoutMs); mHwApi->setActivate(1); + // Using the mToalDuration for composed effect. + // For composed effect, we set the UINT32_MAX to the duration sysfs node, + // but it not a practical way to use it to monitor the total duration time. + if (timeoutMs != UINT32_MAX) { + const std::scoped_lock<std::mutex> lock(mTotalDurationMutex); + mTotalDuration = timeoutMs; + } mActiveId = effectIndex; @@ -897,7 +922,10 @@ ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &compo totalDuration += MAX_COLD_START_LATENCY_MS; mHwApi->setDuration(totalDuration); - + { + const std::scoped_lock<std::mutex> lock(mTotalDurationMutex); + mTotalDuration = totalDuration; + } mHwApi->setActivate(1); mAsyncHandle = std::async(&Vibrator::waitForComplete, this, callback); @@ -993,6 +1021,10 @@ ndk::ScopedAStatus Vibrator::getSimpleDetails(Effect effect, EffectStrength stre volLevel = intensityToVolLevel(intensity, effectIndex); timeMs = mEffectDurations[effectIndex] + MAX_COLD_START_LATENCY_MS; + { + const std::scoped_lock<std::mutex> lock(mTotalDurationMutex); + mTotalDuration = timeMs; + } *outEffectIndex = effectIndex; *outTimeMs = timeMs; @@ -1037,6 +1069,10 @@ ndk::ScopedAStatus Vibrator::getCompoundDetails(Effect effect, EffectStrength st } effectBuilder << thisEffectIndex << "." << thisVolLevel; timeMs += thisTimeMs; + { + const std::scoped_lock<std::mutex> lock(mTotalDurationMutex); + mTotalDuration = timeMs; + } break; default: @@ -1155,7 +1191,19 @@ ndk::ScopedAStatus Vibrator::performEffect(uint32_t effectIndex, uint32_t volLev } void Vibrator::waitForComplete(std::shared_ptr<IVibratorCallback> &&callback) { - mHwApi->pollVibeState(false); + ALOGD("Vibrator::waitForComplete"); + uint32_t duration; + { + const std::scoped_lock<std::mutex> lock(mTotalDurationMutex); + duration = ((mTotalDuration + POLLING_TIMEOUT) < UINT32_MAX) + ? mTotalDuration + POLLING_TIMEOUT + : UINT32_MAX; + } + if (!mHwApi->pollVibeState(false, duration)) { + ALOGE("Timeout(%u)! Fail to poll STOP state", duration); + } else { + ALOGD("Vibrator::waitForComplete: Get STOP! Set active to 0."); + } mHwApi->setActivate(false); if (callback) { diff --git a/vibrator/cs40l25/Vibrator.h b/vibrator/cs40l25/Vibrator.h index 70543e3..7b6bf2c 100644 --- a/vibrator/cs40l25/Vibrator.h +++ b/vibrator/cs40l25/Vibrator.h @@ -89,9 +89,9 @@ class Vibrator : public BnVibrator { // Indicates the number of 0.125-dB steps of attenuation to apply to // waveforms triggered in response to a GPIO1 rising edge. virtual bool setGpioRiseScale(uint32_t value) = 0; - // Blocks until vibrator reaches desired state + // Blocks until timeout or vibrator reaches desired state // (true = enabled, false = disabled). - virtual bool pollVibeState(bool value) = 0; + virtual bool pollVibeState(uint32_t value, int32_t timeoutMs = -1) = 0; // Enables/disables closed-loop active braking. virtual bool setClabEnable(bool value) = 0; // Reports the number of available PWLE segments. @@ -232,6 +232,8 @@ class Vibrator : public BnVibrator { bool mIsChirpEnabled; std::vector<float> mBandwidthAmplitudeMap; bool mGenerateBandwidthAmplitudeMapDone; + uint32_t mTotalDuration{0}; + std::mutex mTotalDurationMutex; }; } // namespace vibrator diff --git a/vibrator/cs40l25/android.hardware.vibrator-service.cs40l25.rc b/vibrator/cs40l25/android.hardware.vibrator-service.cs40l25.rc index f373d31..1025de9 100644 --- a/vibrator/cs40l25/android.hardware.vibrator-service.cs40l25.rc +++ b/vibrator/cs40l25/android.hardware.vibrator-service.cs40l25.rc @@ -71,6 +71,7 @@ service vendor.vibrator.cs40l25 /vendor/bin/hw/android.hardware.vibrator-service device/pwle_ramp_down device/q_stored device/redc_stored + device/vibe_state state " diff --git a/vibrator/cs40l25/tests/mocks.h b/vibrator/cs40l25/tests/mocks.h index efcef52..edd65ca 100644 --- a/vibrator/cs40l25/tests/mocks.h +++ b/vibrator/cs40l25/tests/mocks.h @@ -44,7 +44,7 @@ class MockApi : public ::aidl::android::hardware::vibrator::Vibrator::HwApi { MOCK_METHOD1(setGpioFallScale, bool(uint32_t value)); MOCK_METHOD1(setGpioRiseIndex, bool(uint32_t value)); MOCK_METHOD1(setGpioRiseScale, bool(uint32_t value)); - MOCK_METHOD1(pollVibeState, bool(bool value)); + MOCK_METHOD2(pollVibeState, bool(uint32_t value, int32_t timeoutMs)); MOCK_METHOD1(setClabEnable, bool(bool value)); MOCK_METHOD1(getAvailablePwleSegments, bool(uint32_t *value)); MOCK_METHOD0(hasPwle, bool()); diff --git a/vibrator/cs40l25/tests/test-vibrator.cpp b/vibrator/cs40l25/tests/test-vibrator.cpp index 348322e..49d12c4 100644 --- a/vibrator/cs40l25/tests/test-vibrator.cpp +++ b/vibrator/cs40l25/tests/test-vibrator.cpp @@ -68,8 +68,8 @@ static EffectScale Scale(float intensity); static constexpr uint32_t CAL_VERSION = 1; static constexpr std::array<EffectLevel, 6> V_LEVELS{40, 50, 60, 70, 80, 90}; -static constexpr std::array<EffectDuration, 10> EFFECT_DURATIONS{0, 0, 15, 0, 50, - 100, 150, 200, 250, 8}; +static constexpr std::array<EffectDuration, 10> EFFECT_DURATIONS{0, 0, 11, 0, 300, + 132, 150, 500, 101, 5}; // Constants With Prescribed Values @@ -84,6 +84,10 @@ static constexpr EffectIndex QUEUE_INDEX{65534}; static const EffectScale ON_GLOBAL_SCALE{levelToScale(V_LEVELS[5])}; static const EffectIndex ON_EFFECT_INDEX{0}; +static constexpr uint32_t WAVEFORM_DOUBLE_CLICK_SILENCE_MS = 100; +static constexpr int8_t MAX_COLD_START_LATENCY_MS = 6; // I2C Transaction + DSP Return-From-Standby +static constexpr int8_t MAX_PAUSE_TIMING_ERROR_MS = 1; // ALERT Irq Handling +static constexpr auto POLLING_TIMEOUT = 20; static const std::map<EffectTuple, EffectScale> EFFECT_SCALE{ {{Effect::CLICK, EffectStrength::LIGHT}, Scale(0.7f * 0.5f)}, @@ -102,13 +106,16 @@ static const std::map<EffectTuple, EffectScale> EFFECT_SCALE{ static const std::map<EffectTuple, EffectQueue> EFFECT_QUEUE{ {{Effect::DOUBLE_CLICK, EffectStrength::LIGHT}, - Queue(QueueEffect{EFFECT_INDEX.at(Effect::CLICK), Level(0.7f * 0.5f)}, 100, + Queue(QueueEffect{EFFECT_INDEX.at(Effect::CLICK), Level(0.7f * 0.5f)}, + WAVEFORM_DOUBLE_CLICK_SILENCE_MS, QueueEffect{EFFECT_INDEX.at(Effect::CLICK), Level(1.0f * 0.5f)})}, {{Effect::DOUBLE_CLICK, EffectStrength::MEDIUM}, - Queue(QueueEffect{EFFECT_INDEX.at(Effect::CLICK), Level(0.7f * 0.7f)}, 100, + Queue(QueueEffect{EFFECT_INDEX.at(Effect::CLICK), Level(0.7f * 0.7f)}, + WAVEFORM_DOUBLE_CLICK_SILENCE_MS, QueueEffect{EFFECT_INDEX.at(Effect::CLICK), Level(1.0f * 0.7f)})}, {{Effect::DOUBLE_CLICK, EffectStrength::STRONG}, - Queue(QueueEffect{EFFECT_INDEX.at(Effect::CLICK), Level(0.7f * 1.0f)}, 100, + Queue(QueueEffect{EFFECT_INDEX.at(Effect::CLICK), Level(0.7f * 1.0f)}, + WAVEFORM_DOUBLE_CLICK_SILENCE_MS, QueueEffect{EFFECT_INDEX.at(Effect::CLICK), Level(1.0f * 1.0f)})}, }; @@ -468,16 +475,17 @@ TEST_P(EffectsTest, perform) { }; ExpectationSet eSetup; - Expectation eActivate, ePoll; + Expectation eActivate, ePollStop; if (scale != EFFECT_SCALE.end()) { EffectIndex index = EFFECT_INDEX.at(effect); - duration = EFFECT_DURATIONS[index]; + duration = EFFECT_DURATIONS[index] + MAX_COLD_START_LATENCY_MS; eSetup += EXPECT_CALL(*mMockApi, setEffectIndex(index)).WillOnce(DoDefault()); eSetup += EXPECT_CALL(*mMockApi, setEffectScale(scale->second)).WillOnce(Return(true)); } else if (queue != EFFECT_QUEUE.end()) { - duration = std::get<1>(queue->second); + duration = std::get<1>(queue->second) + MAX_COLD_START_LATENCY_MS * 2 + + MAX_PAUSE_TIMING_ERROR_MS; eSetup += EXPECT_CALL(*mMockApi, setEffectIndex(QUEUE_INDEX)).WillOnce(DoDefault()); eSetup += EXPECT_CALL(*mMockApi, setEffectQueue(std::get<0>(queue->second))) @@ -490,11 +498,12 @@ TEST_P(EffectsTest, perform) { if (duration) { eSetup += EXPECT_CALL(*mMockApi, setDuration(Ge(duration))).WillOnce(Return(true)); eActivate = EXPECT_CALL(*mMockApi, setActivate(true)).After(eSetup).WillOnce(Return(true)); - ePoll = EXPECT_CALL(*mMockApi, pollVibeState(false)) - .After(eActivate) - .WillOnce(Return(true)); - EXPECT_CALL(*mMockApi, setActivate(false)).After(ePoll).WillOnce(Return(true)); - EXPECT_CALL(*callback, onComplete()).After(ePoll).WillOnce(complete); + ePollStop = EXPECT_CALL(*mMockApi, pollVibeState(false, duration + POLLING_TIMEOUT)) + .After(eActivate) + .WillOnce(DoDefault()); + + EXPECT_CALL(*mMockApi, setActivate(false)).After(ePollStop).WillOnce(Return(true)); + EXPECT_CALL(*callback, onComplete()).After(ePollStop).WillOnce(complete); } int32_t lengthMs; @@ -589,8 +598,9 @@ TEST_P(ComposeTest, compose) { auto param = GetParam(); auto composite = param.composite; auto queue = std::get<0>(param.queue); + auto duration = std::get<1>(param.queue); ExpectationSet eSetup; - Expectation eActivate, ePoll; + Expectation eActivate, ePollStop; auto callback = ndk::SharedRefBase::make<MockVibratorCallback>(); std::promise<void> promise; std::future<void> future{promise.get_future()}; @@ -604,9 +614,11 @@ TEST_P(ComposeTest, compose) { eSetup += EXPECT_CALL(*mMockApi, setEffectScale(0)).WillOnce(Return(true)); eSetup += EXPECT_CALL(*mMockApi, setDuration(UINT32_MAX)).WillOnce(Return(true)); eActivate = EXPECT_CALL(*mMockApi, setActivate(true)).After(eSetup).WillOnce(Return(true)); - ePoll = EXPECT_CALL(*mMockApi, pollVibeState(false)).After(eActivate).WillOnce(Return(true)); - EXPECT_CALL(*mMockApi, setActivate(false)).After(ePoll).WillOnce(Return(true)); - EXPECT_CALL(*callback, onComplete()).After(ePoll).WillOnce(complete); + ePollStop = EXPECT_CALL(*mMockApi, pollVibeState(false, duration + POLLING_TIMEOUT)) + .After(eActivate) + .WillOnce(Return(true)); + EXPECT_CALL(*mMockApi, setActivate(false)).After(ePollStop).WillOnce(Return(true)); + EXPECT_CALL(*callback, onComplete()).After(ePollStop).WillOnce(complete); EXPECT_EQ(EX_NONE, mVibrator->compose(composite, callback).getExceptionCode()); |