From 3584a679552b6002f4aef1673ff5f2ba234894d5 Mon Sep 17 00:00:00 2001 From: Chase Wu Date: Tue, 25 Oct 2022 22:14:22 +0800 Subject: [PATCH] cs40l26: Add vibrator manager support Bug: 181615889 Test: Manual type and trigger a long/short vibration Test: cmd vibrator_manager synced xxxx Test: cmd vibrator_manager sequential -v 0 xxxx Test: atest VtsHalVibratorManagerTargetTest \ VtsHalVibratorTargetTest android.os.cts.VibratorTest \ android.os.cts.VibratorManagerTest android.os.cts.VibrationEffectTest \ android.os.cts.VibrationAttributesTest \ android.os.cts.CombinedVibrationTest \ Signed-off-by: Chase Wu Change-Id: Ib93e8eb4a0de9269116e07f76b66a77b58915211 --- vibrator/cs40l26/Android.bp | 48 +++- vibrator/cs40l26/Hardware.h | 11 + vibrator/cs40l26/VibMgrHwApi.h | 123 ++++++++++ vibrator/cs40l26/Vibrator.cpp | 156 +++++++++++-- vibrator/cs40l26/Vibrator.h | 19 ++ vibrator/cs40l26/VibratorManager.cpp | 210 ++++++++++++++++++ vibrator/cs40l26/VibratorManager.h | 83 +++++++ vibrator/cs40l26/VibratorSync.cpp | 39 ++++ vibrator/cs40l26/VibratorSync.h | 46 ++++ vibrator/cs40l26/aidl/Android.bp | 13 ++ .../hardware/vibrator/IVibratorSync.aidl | 24 ++ .../vibrator/IVibratorSyncCallback.aidl | 21 ++ ...vibrator-service.cs40l26-stereo-private.rc | 14 ++ ...ibrator-service.cs40l26-stereo-private.xml | 7 + vibrator/cs40l26/device-stereo.mk | 5 +- vibrator/cs40l26/service-stereo.cpp | 82 +++++++ vibrator/cs40l26/service.cpp | 7 + vibrator/cs40l26/tests/mocks.h | 1 + 18 files changed, 876 insertions(+), 33 deletions(-) create mode 100644 vibrator/cs40l26/VibMgrHwApi.h create mode 100644 vibrator/cs40l26/VibratorManager.cpp create mode 100644 vibrator/cs40l26/VibratorManager.h create mode 100644 vibrator/cs40l26/VibratorSync.cpp create mode 100644 vibrator/cs40l26/VibratorSync.h create mode 100644 vibrator/cs40l26/aidl/Android.bp create mode 100644 vibrator/cs40l26/aidl/android/hardware/vibrator/IVibratorSync.aidl create mode 100644 vibrator/cs40l26/aidl/android/hardware/vibrator/IVibratorSyncCallback.aidl create mode 100644 vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-stereo-private.rc create mode 100644 vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-stereo-private.xml create mode 100644 vibrator/cs40l26/service-stereo.cpp diff --git a/vibrator/cs40l26/Android.bp b/vibrator/cs40l26/Android.bp index 0d3b9f4..7857580 100644 --- a/vibrator/cs40l26/Android.bp +++ b/vibrator/cs40l26/Android.bp @@ -21,7 +21,6 @@ cc_defaults { name: "android.hardware.vibrator-defaults.cs40l26-private", cflags: [ "-DATRACE_TAG=(ATRACE_TAG_VIBRATOR | ATRACE_TAG_HAL)", - "-DLOG_TAG=\"android.hardware.vibrator-cs40l26\"", ], shared_libs: [ "libbinder", @@ -34,13 +33,14 @@ cc_defaults { "PixelVibratorBinaryDefaultsPrivate", "android.hardware.vibrator-defaults.cs40l26-private", ], - include_dirs: [ - "external/tinyalsa/include", - ], shared_libs: [ + "android.hardware.vibrator.cs40l26-private-cpp", "libcutils", "libtinyalsa", ], + include_dirs: [ + "external/tinyalsa/include", + ], } cc_defaults { @@ -53,12 +53,19 @@ cc_defaults { "android.hardware.vibrator-impl.cs40l26-private", "libtinyalsa", ], + shared_libs: [ + "android.hardware.vibrator.cs40l26-private-cpp", + ], } cc_library { name: "android.hardware.vibrator-impl.cs40l26-private", defaults: ["VibratorHalCs40l26BinaryDefaultsPrivate"], - srcs: ["Vibrator.cpp"], + srcs: [ + "Vibrator.cpp", + "VibratorSync.cpp", + "VibratorManager.cpp", + ], export_include_dirs: ["."], vendor_available: true, visibility: [":__subpackages__"], @@ -70,7 +77,12 @@ cc_binary { init_rc: ["android.hardware.vibrator-service.cs40l26-private.rc"], vintf_fragments: ["android.hardware.vibrator-service.cs40l26-private.xml"], srcs: ["service.cpp"], - shared_libs: ["android.hardware.vibrator-impl.cs40l26-private"], + shared_libs: [ + "android.hardware.vibrator-impl.cs40l26-private", + ], + cflags: [ + "-DLOG_TAG=\"android.hardware.vibrator-cs40l26-private\"", + ], proprietary: true, } @@ -80,7 +92,27 @@ cc_binary { init_rc: ["android.hardware.vibrator-service.cs40l26-dual-private.rc"], vintf_fragments: ["android.hardware.vibrator-service.cs40l26-dual-private.xml"], srcs: ["service.cpp"], - shared_libs: ["android.hardware.vibrator-impl.cs40l26-private"], - cflags: ["-DVIBRATOR_NAME=\"dual\""], + shared_libs: [ + "android.hardware.vibrator-impl.cs40l26-private", + ], + cflags: [ + "-DVIBRATOR_NAME=\"dual\"", + "-DLOG_TAG=\"android.hardware.vibrator-cs40l26-dual-private\"", + ], + proprietary: true, +} + +cc_binary { + name: "android.hardware.vibrator-service.cs40l26-stereo-private", + defaults: ["VibratorHalCs40l26BinaryDefaultsPrivate"], + init_rc: ["android.hardware.vibrator-service.cs40l26-stereo-private.rc"], + vintf_fragments: ["android.hardware.vibrator-service.cs40l26-stereo-private.xml"], + srcs: ["service-stereo.cpp"], + shared_libs: [ + "android.hardware.vibrator-impl.cs40l26-private", + ], + cflags: [ + "-DLOG_TAG=\"android.hardware.vibrator-cs40l26-stereo-private\"", + ], proprietary: true, } diff --git a/vibrator/cs40l26/Hardware.h b/vibrator/cs40l26/Hardware.h index ae052ba..9cf831c 100644 --- a/vibrator/cs40l26/Hardware.h +++ b/vibrator/cs40l26/Hardware.h @@ -250,6 +250,17 @@ class HwApi : public Vibrator::HwApi, private HwApiBase { } return true; } + void clearTrigBtn(int fd, struct ff_effect *effect, int8_t id) override { + if ((*effect).trigger.button != 0x00) { + (*effect).trigger.button = 0x00; + if (id < WAVEFORM_MAX_PHYSICAL_INDEX) { + /* Clear the trigger pin setting */ + if ((ioctl(fd, EVIOCSFF, effect) < 0)) { + ALOGE("OFF: Failed to edit effect %d (%d): %s", id, errno, strerror(errno)); + } + } + } + } void debug(int fd) override { HwApiBase::debug(fd); } diff --git a/vibrator/cs40l26/VibMgrHwApi.h b/vibrator/cs40l26/VibMgrHwApi.h new file mode 100644 index 0000000..f263a18 --- /dev/null +++ b/vibrator/cs40l26/VibMgrHwApi.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2021 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. + */ +#pragma once + +#include +#include +#include + +#include + +#include "VibratorManager.h" +#include "utils.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace vibrator { + +class VibMgrHwApi : public VibratorManager::HwApi { + private: + const uint32_t DEBUG_GPI_PIN = UINT16_MAX; + const uint32_t DEBUG_GPI_PIN_SHIFT = UINT16_MAX; + std::string mPropertyPrefix; + uint32_t mGPIOPin; + uint32_t mGPIOShift; + struct gpiohandle_request mRq; + + public: + static std::unique_ptr Create() { + auto hwapi = std::unique_ptr(new VibMgrHwApi()); + return hwapi; + } + bool getGPIO() override { + auto propertyPrefix = std::getenv("PROPERTY_PREFIX"); + + if (propertyPrefix != NULL) { + mPropertyPrefix = std::string(propertyPrefix); + } else { + ALOGE("GetGPIO: Failed get property prefix!"); + return false; + } + mGPIOPin = utils::getProperty(mPropertyPrefix + "gpio.num", DEBUG_GPI_PIN); + if (mGPIOPin == DEBUG_GPI_PIN) { + ALOGE("GetGPIO: Fail to get the GPIO num: %s", strerror(errno)); + return false; + } + mGPIOShift = utils::getProperty(mPropertyPrefix + "gpio.shift", DEBUG_GPI_PIN_SHIFT); + + if (mGPIOShift == DEBUG_GPI_PIN_SHIFT) { + ALOGE("GetGPIO: Fail to get the GPIO shift num: %s", strerror(errno)); + return false; + } + + return true; + } + bool initGPIO() override { + const auto gpio_dev = std::string() + "/dev/gpiochip" + std::to_string(mGPIOPin); + int fd = open(gpio_dev.c_str(), O_RDONLY); + if (fd < 0) { + ALOGE("InitGPIO: Unabled to open gpio dev: %s", strerror(errno)); + return false; + } + + mRq.lineoffsets[0] = mGPIOShift; + mRq.lines = 1; + mRq.flags = GPIOHANDLE_REQUEST_OUTPUT; + + int ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &mRq); + close(fd); + if (ret == -1) { + ALOGE("InitGPIO: Unable to line handle from ioctl : %s", strerror(errno)); + close(fd); + return false; + } + // Reset gpio status to LOW + struct gpiohandle_data data; + data.values[0] = 0; + + ret = ioctl(mRq.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data); + if (ret == -1) { + ALOGE("InitGPIO: Unable to set line value using ioctl : %s", strerror(errno)); + close(mRq.fd); + return false; + } + return true; + } + bool setTrigger(bool value) override { + struct gpiohandle_data data; + data.values[0] = value; + + int ret = ioctl(mRq.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data); + if (ret == -1) { + ALOGE("SetTrigger: Unable to set line value using ioctl : %s", strerror(errno)); + close(mRq.fd); + return false; + } + close(mRq.fd); + + return true; + } + void debug(int fd) override { ALOGD("Debug: %d", fd); } + + private: + VibMgrHwApi() { ALOGD("Constructor"); } +}; + +} // namespace vibrator +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/vibrator/cs40l26/Vibrator.cpp b/vibrator/cs40l26/Vibrator.cpp index 88914d8..765be3b 100644 --- a/vibrator/cs40l26/Vibrator.cpp +++ b/vibrator/cs40l26/Vibrator.cpp @@ -54,6 +54,7 @@ static constexpr uint32_t MAX_TIME_MS = UINT16_MAX; static constexpr auto ASYNC_COMPLETION_TIMEOUT = std::chrono::milliseconds(100); static constexpr auto POLLING_TIMEOUT = 20; +static constexpr auto POLLING_TIMEOUT_IN_SYNC = 100; static constexpr int32_t COMPOSE_DELAY_MAX_MS = 10000; /* nsections is 8 bits. Need to preserve 1 section for the first delay before the first effect. */ @@ -89,6 +90,16 @@ static constexpr float PWLE_FREQUENCY_MAX_HZ = 1000.00; static constexpr float PWLE_BW_MAP_SIZE = 1 + ((PWLE_FREQUENCY_MAX_HZ - PWLE_FREQUENCY_MIN_HZ) / PWLE_FREQUENCY_RESOLUTION_HZ); +/* + * [15] Edge, 0:Falling, 1:Rising + * [14:12] GPI_NUM, 1:GPI1 (with CS40L26A, 1 is the only supported GPI) + * [8] BANK, 0:ROM, 1:RAM + * [7] USE_BUZZGEN, 0:Not buzzgen, 1:buzzgen + * [6:0] WAVEFORM_INDEX + * 0x9100 = 1001 0001 0000 0000: Rising + GPI1 + ROM + Not buzzgen + */ +static constexpr uint32_t GPIO_TRIGGER_CONFIG = 0x9100; + static uint16_t amplitudeToScale(float amplitude, float maximum) { float ratio = 100; /* Unit: % */ if (maximum != 0) @@ -341,7 +352,10 @@ Vibrator::Vibrator(std::unique_ptr hwapi, std::unique_ptr hwcal) mHwCal->getClickVolLevels(&mClickEffectVol); mHwCal->getLongVolLevels(&mLongEffectVol); } else { - ALOGD("Unsupported calibration version: %u!", calVer); + ALOGW("Unsupported calibration version! Using the default calibration value"); + mHwCal->getTickVolLevels(&mTickEffectVol); + mHwCal->getClickVolLevels(&mClickEffectVol); + mHwCal->getLongVolLevels(&mLongEffectVol); } mHwApi->setF0CompEnable(mHwCal->isF0CompEnabled()); @@ -364,7 +378,6 @@ Vibrator::Vibrator(std::unique_ptr hwapi, std::unique_ptr hwcal) } mSupportedPrimitives = defaultSupportedPrimitives; } - mHwApi->setMinOnOffInterval(MIN_ON_OFF_INTERVAL_US); } @@ -406,6 +419,8 @@ ndk::ScopedAStatus Vibrator::off() { ALOGE("Failed to clean up the composed effect %d", mActiveId); ret = false; } + + mHwApi->clearTrigBtn(mInputFd, &mFfEffects[mActiveId], mActiveId); } else { ALOGV("Vibrator is already off"); } @@ -425,7 +440,14 @@ ndk::ScopedAStatus Vibrator::off() { ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs, const std::shared_ptr &callback) { + std::scoped_lock lock(mApiMutex); ATRACE_NAME("Vibrator::on"); + + if (isBusy()) { + ALOGD("Vibrator::on, isBusy"); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + if (timeoutMs > MAX_TIME_MS) { return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } @@ -445,6 +467,7 @@ ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs, ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength, const std::shared_ptr &callback, int32_t *_aidl_return) { + std::scoped_lock lock(mApiMutex); ATRACE_NAME("Vibrator::perform"); return performEffect(effect, strength, callback, _aidl_return); } @@ -456,7 +479,9 @@ ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector *_aidl_retu } ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) { + std::scoped_lock lock(mApiMutex); ATRACE_NAME("Vibrator::setAmplitude"); + if (amplitude <= 0.0f || amplitude > 1.0f) { return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } @@ -470,7 +495,13 @@ ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) { } ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) { + std::scoped_lock lock(mApiMutex); ATRACE_NAME("Vibrator::setExternalControl"); + + if (isSynced()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + setGlobalAmplitude(enabled); if (mHasHapticAlsaDevice || mConfigHapticAlsaDeviceDone || hasHapticAlsaDevice()) { @@ -523,6 +554,7 @@ ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive, ndk::ScopedAStatus Vibrator::compose(const std::vector &composite, const std::shared_ptr &callback) { + std::scoped_lock lock(mApiMutex); ATRACE_NAME("Vibrator::compose"); uint16_t size; uint16_t nextEffectDelay; @@ -635,6 +667,9 @@ ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex, dspmem return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } int errorStatus; + if (isSynced()) { + mFfEffects[effectIndex].trigger.button = GPIO_TRIGGER_CONFIG | effectIndex; + } if (!mHwApi->uploadOwtEffect(mInputFd, ch->head, dspmem_chunk_bytes(ch), &mFfEffects[effectIndex], &effectIndex, &errorStatus)) { delete ch; @@ -647,22 +682,36 @@ ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex, dspmem effectIndex == WAVEFORM_LONG_VIBRATION_EFFECT_INDEX) { /* Update duration for long/short vibration. */ mFfEffects[effectIndex].replay.length = static_cast(timeoutMs); + if (isSynced()) { + mFfEffects[effectIndex].trigger.button = GPIO_TRIGGER_CONFIG | effectIndex; + } if (!mHwApi->setFFEffect(mInputFd, &mFfEffects[effectIndex], static_cast(timeoutMs))) { ALOGE("Failed to edit effect %d (%d): %s", effectIndex, errno, strerror(errno)); return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } } - - const std::scoped_lock lock(mActiveId_mutex); - mActiveId = effectIndex; - /* Play the event now. */ - if (!mHwApi->setFFPlay(mInputFd, effectIndex, true)) { - ALOGE("Failed to play effect %d (%d): %s", effectIndex, errno, strerror(errno)); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + { + const std::scoped_lock lock(mActiveId_mutex); + mActiveId = effectIndex; + if (isSynced() && + (effectIndex == WAVEFORM_CLICK_INDEX || effectIndex == WAVEFORM_LIGHT_TICK_INDEX)) { + mFfEffects[effectIndex].trigger.button = GPIO_TRIGGER_CONFIG | effectIndex; + if (!mHwApi->setFFEffect(mInputFd, &mFfEffects[effectIndex], mFfEffects[effectIndex].replay.length)) { + ALOGE("Failed to edit effect %d (%d): %s", effectIndex, errno, strerror(errno)); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + } else if (!isSynced()) { + // /* Play the event now. */ + if (!mHwApi->setFFPlay(mInputFd, effectIndex, true)) { + ALOGE("Failed to play effect %d (%d): %s", effectIndex, errno, strerror(errno)); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + } } mAsyncHandle = std::async(&Vibrator::waitForComplete, this, callback); + return ndk::ScopedAStatus::ok(); } @@ -999,6 +1048,39 @@ bool Vibrator::isUnderExternalControl() { return mIsUnderExternalControl; } +// BnVibratorSync APIs + +Status Vibrator::prepareSynced(const sp &callback) { + std::scoped_lock lock(mApiMutex); + ATRACE_NAME("Vibrator::prepareSynced"); + + if (isBusy() || isSynced() || isUnderExternalControl()) { + ALOGE("Vibrator::prepareSynced, isBusy or isSynced"); + return Status::fromExceptionCode(EX_ILLEGAL_STATE); + } + + mSyncedCallback = callback; + + return Status::ok(); +} + +Status Vibrator::cancelSynced() { + std::scoped_lock lock(mApiMutex); + ATRACE_NAME("Vibrator::cancelSynced"); + + if (!isSynced()) { + ALOGE("Vibrator::cancelSynced, isSynced"); + return Status::fromExceptionCode(EX_ILLEGAL_STATE); + } + + off(); + mSyncedCallback = nullptr; + + return Status::ok(); +} + +// BnCInterface APIs + binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) { if (fd < 0) { ALOGE("Called debug() with invalid fd."); @@ -1022,14 +1104,15 @@ binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) { dprintf(fd, " FF effect:\n"); dprintf(fd, " Physical waveform:\n"); - dprintf(fd, "\tId\tIndex\tt ->\tt'\n"); + dprintf(fd, "\tId\tIndex\tt ->\tt'\ttrigger button\n"); for (uint8_t effectId = 0; effectId < WAVEFORM_MAX_PHYSICAL_INDEX; effectId++) { - dprintf(fd, "\t%d\t%d\t%d\t%d\n", mFfEffects[effectId].id, + dprintf(fd, "\t%d\t%d\t%d\t%d\t%X\n", mFfEffects[effectId].id, mFfEffects[effectId].u.periodic.custom_data[1], mEffectDurations[effectId], - mFfEffects[effectId].replay.length); + mFfEffects[effectId].replay.length, mFfEffects[effectId].trigger.button); } + dprintf(fd, " OWT waveform:\n"); - dprintf(fd, "\tId\tBytes\tData\n"); + dprintf(fd, "\tId\tBytes\tData\ttrigger button\n"); for (uint8_t effectId = WAVEFORM_MAX_PHYSICAL_INDEX; effectId < WAVEFORM_MAX_INDEX; effectId++) { uint32_t numBytes = mFfEffects[effectId].u.periodic.custom_len * 2; @@ -1042,7 +1125,8 @@ binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) { i)) << " "; } - dprintf(fd, "\t%d\t%d\t{%s}\n", mFfEffects[effectId].id, numBytes, ss.str().c_str()); + dprintf(fd, "\t%d\t%d\t{%s}\t%X\n", mFfEffects[effectId].id, numBytes, ss.str().c_str(), + mFfEffects[effectId].trigger.button); } dprintf(fd, "\n"); @@ -1271,17 +1355,26 @@ ndk::ScopedAStatus Vibrator::performEffect(uint32_t effectIndex, uint32_t volLev } void Vibrator::waitForComplete(std::shared_ptr &&callback) { - if (!mHwApi->pollVibeState(VIBE_STATE_HAPTIC, POLLING_TIMEOUT)) { - ALOGW("Failed to get state \"Haptic\""); - } - mHwApi->pollVibeState(VIBE_STATE_STOPPED); + ALOGD("Callback status in waitForComplete(): mSync: %d, callBack: %d", isSynced(), + (callback != nullptr)); - const std::scoped_lock lock(mActiveId_mutex); - if ((mActiveId >= WAVEFORM_MAX_PHYSICAL_INDEX) && - (!mHwApi->eraseOwtEffect(mInputFd, mActiveId, &mFfEffects))) { - ALOGE("Failed to clean up the composed effect %d", mActiveId); + if (!mHwApi->pollVibeState(VIBE_STATE_HAPTIC, + (mSyncedCallback) ? POLLING_TIMEOUT_IN_SYNC : POLLING_TIMEOUT)) { + ALOGV("Fail to get state \"Haptic\""); + } + + mHwApi->pollVibeState(VIBE_STATE_STOPPED); + { + const std::scoped_lock lock(mActiveId_mutex); + if ((mActiveId >= WAVEFORM_MAX_PHYSICAL_INDEX) && + (!mHwApi->eraseOwtEffect(mInputFd, mActiveId, &mFfEffects))) { + ALOGE("Failed to clean up the composed effect %d", mActiveId); + } + + mHwApi->clearTrigBtn(mInputFd, &mFfEffects[mActiveId], mActiveId); + + mActiveId = -1; } - mActiveId = -1; if (callback) { auto ret = callback->onComplete(); @@ -1289,6 +1382,13 @@ void Vibrator::waitForComplete(std::shared_ptr &&callback) { ALOGE("Failed completion callback: %d", ret.getExceptionCode()); } } + if (mSyncedCallback) { + auto ret = mSyncedCallback->onComplete(); + if (!ret.isOk()) { + ALOGE("Failed completion mSyncedCallback: %d", ret.exceptionCode()); + } + mSyncedCallback = nullptr; + } } uint32_t Vibrator::intensityToVolLevel(float intensity, uint32_t effectIndex) { @@ -1321,6 +1421,16 @@ uint32_t Vibrator::intensityToVolLevel(float intensity, uint32_t effectIndex) { return volLevel; } +bool Vibrator::isBusy() { + auto timeout = std::chrono::seconds::zero(); + auto status = mAsyncHandle.wait_for(timeout); + return status != std::future_status::ready; +} + +bool Vibrator::isSynced() { + return (mSyncedCallback != nullptr); +} + } // namespace vibrator } // namespace hardware } // namespace android diff --git a/vibrator/cs40l26/Vibrator.h b/vibrator/cs40l26/Vibrator.h index 220c974..578a86a 100644 --- a/vibrator/cs40l26/Vibrator.h +++ b/vibrator/cs40l26/Vibrator.h @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -29,6 +30,10 @@ namespace android { namespace hardware { namespace vibrator { +using ::android::sp; +using ::android::binder::Status; +using ::android::hardware::vibrator::IVibratorSyncCallback; + class Vibrator : public BnVibrator { public: // APIs for interfacing with the kernel driver. @@ -80,6 +85,8 @@ class Vibrator : public BnVibrator { int *status) = 0; // Erase OWT waveform virtual bool eraseOwtEffect(int fd, int8_t effectIndex, std::vector *effect) = 0; + // Erase trigger button information + virtual void clearTrigBtn(int fd, struct ff_effect *effect, int8_t id) = 0; // Emit diagnostic information to the given file. virtual void debug(int fd) = 0; }; @@ -121,6 +128,7 @@ class Vibrator : public BnVibrator { public: Vibrator(std::unique_ptr hwapi, std::unique_ptr hwcal); + // BnVibrator APIs ndk::ScopedAStatus getCapabilities(int32_t *_aidl_return) override; ndk::ScopedAStatus off() override; ndk::ScopedAStatus on(int32_t timeoutMs, @@ -152,6 +160,11 @@ class Vibrator : public BnVibrator { ndk::ScopedAStatus composePwle(const std::vector &composite, const std::shared_ptr &callback) override; + // BnVibratorSync APIs + Status prepareSynced(const sp &callback); + Status cancelSynced(); + + // BnCInterface APIs binder_status_t dump(int fd, const char **args, uint32_t numArgs) override; private: @@ -182,6 +195,9 @@ class Vibrator : public BnVibrator { bool hasHapticAlsaDevice(); bool enableHapticPcmAmp(struct pcm **haptic_pcm, bool enable, int card, int device); + bool isBusy(); + bool isSynced(); + std::unique_ptr mHwApi; std::unique_ptr mHwCal; uint32_t mF0Offset; @@ -203,6 +219,9 @@ class Vibrator : public BnVibrator { uint32_t mSupportedPrimitivesBits = 0x0; std::vector mSupportedPrimitives; bool mConfigHapticAlsaDeviceDone{false}; + // prevent concurrent execution of IVibrator and IVibratorSync APIs + sp mSyncedCallback; + std::recursive_mutex mApiMutex; }; } // namespace vibrator diff --git a/vibrator/cs40l26/VibratorManager.cpp b/vibrator/cs40l26/VibratorManager.cpp new file mode 100644 index 0000000..3552c2f --- /dev/null +++ b/vibrator/cs40l26/VibratorManager.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2021 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 "VibratorManager.h" + +#include +#include +#include + +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace vibrator { + +using ::android::sp; +using ::android::binder::Status; +using ::android::hardware::vibrator::BnVibratorSyncCallback; + +class VibratorSyncCallback : public BnVibratorSyncCallback { + public: + Status onComplete() override { + mPromise.set_value(); + return Status::ok(); + } + auto getFuture() { return mPromise.get_future(); } + + private: + std::promise mPromise; +}; + +VibratorManager::VibratorManager(std::unique_ptr hwapi, + const std::vector &&vibrators) + : mHwApi(std::move(hwapi)), mVibrators(std::move(vibrators)), mAsyncHandle(std::async([] {})) { + mGPIOStatus = mHwApi->getGPIO(); +} + +// BnVibratorManager APIs + +ndk::ScopedAStatus VibratorManager::getCapabilities(int32_t *_aidl_return) { + ATRACE_NAME("VibratorManager::getCapabilities"); + int32_t ret = + IVibratorManager::CAP_SYNC | IVibratorManager::CAP_PREPARE_ON | + IVibratorManager::CAP_PREPARE_PERFORM | IVibratorManager::CAP_PREPARE_COMPOSE | + IVibratorManager::CAP_MIXED_TRIGGER_ON | IVibratorManager::CAP_MIXED_TRIGGER_PERFORM | + IVibratorManager::CAP_MIXED_TRIGGER_COMPOSE | IVibratorManager::CAP_TRIGGER_CALLBACK; + + *_aidl_return = ret; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus VibratorManager::getVibratorIds(std::vector *_aidl_return) { + ATRACE_NAME("VibratorManager::getVibratorIds"); + _aidl_return->resize(mVibrators.size()); + std::iota(_aidl_return->begin(), _aidl_return->end(), 0); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus VibratorManager::getVibrator(int vibratorId, + std::shared_ptr *_aidl_return) { + ATRACE_NAME("VibratorManager::getVibrator"); + if (!mGPIOStatus) { + ALOGE("GetVibrator: GPIO status error"); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + if (vibratorId >= mVibrators.size()) { + ALOGE("GetVibrator: wrong requested vibrator ID"); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + std::tie(*_aidl_return, std::ignore) = mVibrators.at(vibratorId); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus VibratorManager::prepareSynced(const std::vector &ids) { + ATRACE_NAME("VibratorManager::prepareSynced"); + + if (!mGPIOStatus) { + ALOGE("GetVibrator: GPIO status error"); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + + if (ids.empty()) { + ALOGE("PrepareSynced: No vibrator could be synced"); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + + if (!mSyncContext.empty()) { + ALOGE("PrepareSynced: mSyncContext is not EMPTY!!!"); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + if (isBusy()) { + ALOGE("PrepareSynced: IS BUSY!!!"); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + + for (auto &id : ids) { + auto &[vib, ext] = mVibrators.at(id); + auto callback = sp::make(); + + ext->prepareSynced(callback); + + mSyncContext.emplace_back(id, callback->getFuture()); + } + if (mHwApi->initGPIO()) { + return ndk::ScopedAStatus::ok(); + } else { + ALOGE("PrepareSynced: GPIO status init fail"); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } +} + +ndk::ScopedAStatus VibratorManager::triggerSynced( + const std::shared_ptr &callback) { + ATRACE_NAME("VibratorManager::triggerSynced"); + if (isBusy()) { + ALOGE("TriggerSynced isBusy"); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + + mHwApi->setTrigger(true); + + doAsync([=]() { + { + std::shared_lock lock(mContextMutex); + for (auto &[id, future] : mSyncContext) { + future.wait(); + } + } + { + std::unique_lock lock(mContextMutex); + mSyncContext.clear(); + } + if (callback) { + auto ret = callback->onComplete(); + if (!ret.isOk()) { + ALOGE("Failed completion callback: %d", ret.getExceptionCode()); + } + ALOGD("Callback in MANAGER onComplete()"); + } + }); + + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus VibratorManager::cancelSynced() { + ATRACE_NAME("VibratorManager::cancelSynced"); + + mHwApi->setTrigger(false); + { + std::shared_lock lock(mContextMutex); + for (auto &[id, future] : mSyncContext) { + auto &[vib, ext] = mVibrators.at(id); + ext->cancelSynced(); + } + } + { + std::unique_lock lock(mContextMutex); + mSyncContext.clear(); + } + mAsyncHandle.wait(); + + return ndk::ScopedAStatus::ok(); +} + +// BnCInterface APIs + +binder_status_t VibratorManager::dump(int fd, const char ** /*args*/, uint32_t /*numArgs*/) { + if (fd < 0) { + ALOGE("Called debug() with invalid fd."); + return STATUS_OK; + } + + mHwApi->debug(fd); + + fsync(fd); + + return STATUS_OK; +} + +// Private Methods + +template +void VibratorManager::doAsync(Func &&func, Args &&...args) { + mAsyncHandle = std::async(func, std::forward(args)...); +} + +bool VibratorManager::isBusy() { + auto timeout = std::chrono::seconds::zero(); + auto status = mAsyncHandle.wait_for(timeout); + return status != std::future_status::ready; +} + +} // namespace vibrator +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/vibrator/cs40l26/VibratorManager.h b/vibrator/cs40l26/VibratorManager.h new file mode 100644 index 0000000..e518a20 --- /dev/null +++ b/vibrator/cs40l26/VibratorManager.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2021 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. + */ +#pragma once + +#include +#include +#include + +#include +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace vibrator { + +using ::android::hardware::vibrator::IVibratorSync; + +class VibratorManager : public BnVibratorManager { + public: + // APIs for interfacing with the kernel driver. + class HwApi { + public: + virtual ~HwApi() = default; + // Get the GPIO pin num and address shift information + virtual bool getGPIO() = 0; + // Init the GPIO function + virtual bool initGPIO() = 0; + // Trigger activation of the synchronized vibrators. + virtual bool setTrigger(bool value) = 0; + // Emit diagnostic information to the given file. + virtual void debug(int fd) = 0; + }; + + using VibratorTuple = std::tuple, ::android::sp>; + + public: + VibratorManager(std::unique_ptr hwapi, const std::vector &&vibrators); + + // BnVibratorManager APIs + ndk::ScopedAStatus getCapabilities(int32_t *_aidl_return); + ndk::ScopedAStatus getVibratorIds(std::vector *_aidl_return); + ndk::ScopedAStatus getVibrator(int vibratorId, std::shared_ptr *_aidl_return); + ndk::ScopedAStatus prepareSynced(const std::vector &ids) override; + ndk::ScopedAStatus triggerSynced(const std::shared_ptr &callback) override; + ndk::ScopedAStatus cancelSynced() override; + + // BnCInterface APIs + binder_status_t dump(int fd, const char **args, uint32_t numArgs) override; + + private: + template + void doAsync(Func &&func, Args &&...args); + bool isBusy(); + + private: + using SyncContext = std::tuple>; + + const std::unique_ptr mHwApi; + const std::vector mVibrators; + std::vector mSyncContext; + std::shared_mutex mContextMutex; + std::future mAsyncHandle; + bool mGPIOStatus; +}; + +} // namespace vibrator +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/vibrator/cs40l26/VibratorSync.cpp b/vibrator/cs40l26/VibratorSync.cpp new file mode 100644 index 0000000..437ee01 --- /dev/null +++ b/vibrator/cs40l26/VibratorSync.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 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 "VibratorSync.h" + +namespace android { +namespace hardware { +namespace vibrator { + +VibratorSync::VibratorSync(std::shared_ptr vibrator) : mVibrator(vibrator) { + ALOGE("VibratorSync constructor"); +} + +// BnVibratorSync APIs + +binder::Status VibratorSync::prepareSynced(const sp &callback) { + return mVibrator->prepareSynced(callback); +} + +binder::Status VibratorSync::cancelSynced() { + return mVibrator->cancelSynced(); +} + +} // namespace vibrator +} // namespace hardware +} // namespace android diff --git a/vibrator/cs40l26/VibratorSync.h b/vibrator/cs40l26/VibratorSync.h new file mode 100644 index 0000000..fd9195a --- /dev/null +++ b/vibrator/cs40l26/VibratorSync.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 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. + */ +#pragma once + +#include + +#include +#include +#include + +#include "Vibrator.h" + +namespace android { +namespace hardware { +namespace vibrator { + +using ::aidl::android::hardware::vibrator::Vibrator; + +class VibratorSync : public BnVibratorSync { + public: + VibratorSync(std::shared_ptr vibrator); + + // BnVibratorSync APIs + binder::Status prepareSynced(const android::sp &callback) override; + binder::Status cancelSynced() override; + + private: + std::shared_ptr mVibrator; +}; + +} // namespace vibrator +} // namespace hardware +} // namespace android diff --git a/vibrator/cs40l26/aidl/Android.bp b/vibrator/cs40l26/aidl/Android.bp new file mode 100644 index 0000000..2c3b4b9 --- /dev/null +++ b/vibrator/cs40l26/aidl/Android.bp @@ -0,0 +1,13 @@ +aidl_interface { + name: "android.hardware.vibrator.cs40l26-private", + srcs: [ + "android/hardware/vibrator/*.aidl" + ], + backend: { + java: { + enabled: false, + }, + }, + unstable: true, + vendor_available: true, +} diff --git a/vibrator/cs40l26/aidl/android/hardware/vibrator/IVibratorSync.aidl b/vibrator/cs40l26/aidl/android/hardware/vibrator/IVibratorSync.aidl new file mode 100644 index 0000000..5371b13 --- /dev/null +++ b/vibrator/cs40l26/aidl/android/hardware/vibrator/IVibratorSync.aidl @@ -0,0 +1,24 @@ +/* + * 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. + */ + +package android.hardware.vibrator; + +import android.hardware.vibrator.IVibratorSyncCallback; + +interface IVibratorSync { + void prepareSynced(in IVibratorSyncCallback callback); + void cancelSynced(); +} diff --git a/vibrator/cs40l26/aidl/android/hardware/vibrator/IVibratorSyncCallback.aidl b/vibrator/cs40l26/aidl/android/hardware/vibrator/IVibratorSyncCallback.aidl new file mode 100644 index 0000000..5281229 --- /dev/null +++ b/vibrator/cs40l26/aidl/android/hardware/vibrator/IVibratorSyncCallback.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2021 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. + */ + +package android.hardware.vibrator; + +interface IVibratorSyncCallback { + oneway void onComplete(); +} diff --git a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-stereo-private.rc b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-stereo-private.rc new file mode 100644 index 0000000..01642dd --- /dev/null +++ b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-stereo-private.rc @@ -0,0 +1,14 @@ +on property:vendor.all.modules.ready=1 + wait_for_prop init.svc.vendor.vibrator.cs40l26 running + wait_for_prop init.svc.vendor.vibrator.cs40l26-dual running + + enable vendor.vibrator.cs40l26-stereo + +service vendor.vibrator.cs40l26-stereo /vendor/bin/hw/android.hardware.vibrator-service.cs40l26-stereo-private + class hal + user root + group root + + setenv PROPERTY_PREFIX ro.vendor.vibrator.hal. + + disabled diff --git a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-stereo-private.xml b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-stereo-private.xml new file mode 100644 index 0000000..9056bd0 --- /dev/null +++ b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-stereo-private.xml @@ -0,0 +1,7 @@ + + + android.hardware.vibrator + 2 + IVibratorManager/default + + diff --git a/vibrator/cs40l26/device-stereo.mk b/vibrator/cs40l26/device-stereo.mk index 08e4787..e4bf496 100644 --- a/vibrator/cs40l26/device-stereo.mk +++ b/vibrator/cs40l26/device-stereo.mk @@ -1,6 +1,7 @@ PRODUCT_PACKAGES += \ - android.hardware.vibrator-service.cs40l26 \ - android.hardware.vibrator-service.cs40l26-dual \ + android.hardware.vibrator-service.cs40l26-private \ + android.hardware.vibrator-service.cs40l26-dual-private \ + android.hardware.vibrator-service.cs40l26-stereo-private \ BOARD_SEPOLICY_DIRS += \ device/google/felix-sepolicy/vibrator/common \ diff --git a/vibrator/cs40l26/service-stereo.cpp b/vibrator/cs40l26/service-stereo.cpp new file mode 100644 index 0000000..cd05035 --- /dev/null +++ b/vibrator/cs40l26/service-stereo.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2021 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 +#include +#include +#include +#include + +#include "VibMgrHwApi.h" +#include "VibratorManager.h" + +using ::aidl::android::hardware::vibrator::IVibrator; +using ::aidl::android::hardware::vibrator::VibMgrHwApi; +using ::aidl::android::hardware::vibrator::VibratorManager; +using ::android::ProcessState; +using ::android::String16; +using ::android::waitForService; +using ::android::hardware::vibrator::IVibratorSync; + +#if !defined(VIBRATOR_NAME) +#define VIBRATOR_NAME "default" +#endif + +using ndk::SharedRefBase; +using ndk::SpAIBinder; + +int main() { + auto hwapi = VibMgrHwApi::Create(); + if (!hwapi) { + return EXIT_FAILURE; + } + + const std::string vibratorInstances[] = { + "default", + "dual", + }; + std::vector vibrators; + + ProcessState::initWithDriver("/dev/vndbinder"); + + for (auto &instance : vibratorInstances) { + const auto svcName = std::string() + IVibrator::descriptor + "/" + instance; + const auto extName = std::stringstream() << IVibratorSync::descriptor << "/" << instance; + + SpAIBinder svcBinder; + svcBinder = SpAIBinder(AServiceManager_getService(svcName.c_str())); + auto svc = IVibrator::fromBinder(svcBinder); + + auto ext = waitForService(String16(extName.str().c_str())); + + vibrators.emplace_back(svc, ext); + } + + auto mgr = ndk::SharedRefBase::make(std::move(hwapi), std::move(vibrators)); + binder_status_t status; + + const std::string mgrInst = std::string() + VibratorManager::descriptor + "/" VIBRATOR_NAME; + status = AServiceManager_addService(mgr->asBinder().get(), mgrInst.c_str()); + LOG_ALWAYS_FATAL_IF(status != STATUS_OK); + + // Only used for callbacks + ProcessState::self()->setThreadPoolMaxThreadCount(1); + ProcessState::self()->startThreadPool(); + + ABinderProcess_setThreadPoolMaxThreadCount(0); + ABinderProcess_joinThreadPool(); + + return EXIT_FAILURE; // should not reach +} diff --git a/vibrator/cs40l26/service.cpp b/vibrator/cs40l26/service.cpp index 27173d9..fd76b19 100644 --- a/vibrator/cs40l26/service.cpp +++ b/vibrator/cs40l26/service.cpp @@ -21,6 +21,7 @@ #include "Hardware.h" #include "Vibrator.h" +#include "VibratorSync.h" using ::aidl::android::hardware::vibrator::HwApi; using ::aidl::android::hardware::vibrator::HwCal; @@ -29,6 +30,7 @@ using ::android::defaultServiceManager; using ::android::ProcessState; using ::android::sp; using ::android::String16; +using ::android::hardware::vibrator::VibratorSync; #if !defined(VIBRATOR_NAME) #define VIBRATOR_NAME "default" @@ -39,8 +41,13 @@ int main() { std::make_unique()); const auto svcName = std::string() + svc->descriptor + "/" + VIBRATOR_NAME; + auto ext = sp::make(svc); + const auto extName = std::stringstream() << ext->descriptor << "/" << VIBRATOR_NAME; + ProcessState::initWithDriver("/dev/vndbinder"); + defaultServiceManager()->addService(String16(extName.str().c_str()), ext); + auto svcBinder = svc->asBinder(); binder_status_t status = AServiceManager_addService(svcBinder.get(), svcName.c_str()); LOG_ALWAYS_FATAL_IF(status != STATUS_OK); diff --git a/vibrator/cs40l26/tests/mocks.h b/vibrator/cs40l26/tests/mocks.h index 21466a0..e497f2a 100644 --- a/vibrator/cs40l26/tests/mocks.h +++ b/vibrator/cs40l26/tests/mocks.h @@ -43,6 +43,7 @@ class MockApi : public ::aidl::android::hardware::vibrator::Vibrator::HwApi { bool(int fd, uint8_t *owtData, uint32_t numBytes, struct ff_effect *effect, uint32_t *outEffectIndex, int *status)); MOCK_METHOD3(eraseOwtEffect, bool(int fd, int8_t effectIndex, std::vector *effect)); + MOCK_METHOD3(clearTrigBtn, void(int fd, struct ff_effect *effect, int8_t index)); MOCK_METHOD1(debug, void(int fd)); ~MockApi() override { destructor(); };