summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChase Wu <chasewu@google.com>2023-01-04 17:03:36 +0800
committerChase Wu <chasewu@google.com>2023-01-10 16:17:23 +0800
commitbcd846dcba14eb4df5eedf7a48fb8d78051fa99a (patch)
tree444326570a6d35e0615a527102cc48624aa3a4a9
parent0aaebb34f1bf6deaae986d5063cf28b46b22fc58 (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.bp2
-rw-r--r--vibrator/cs40l25/Hardware.h4
-rw-r--r--vibrator/cs40l25/Vibrator.cpp54
-rw-r--r--vibrator/cs40l25/Vibrator.h6
-rw-r--r--vibrator/cs40l25/android.hardware.vibrator-service.cs40l25.rc1
-rw-r--r--vibrator/cs40l25/tests/mocks.h2
-rw-r--r--vibrator/cs40l25/tests/test-vibrator.cpp46
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());