universal7904: Import vibrator AIDL service hal
* from hardware/samsung
* rebranded to universal7904
Change-Id: I223cd5d0399fe84a6e5a243a0b02633cadd14777
diff --git a/aidl/vibrator/Android.bp b/aidl/vibrator/Android.bp
new file mode 100644
index 0000000..c1294bb
--- /dev/null
+++ b/aidl/vibrator/Android.bp
@@ -0,0 +1,22 @@
+//
+// Copyright (C) 2021 The LineageOS Project
+//
+// SPDX-License-Identifier: Apache-2.0
+//
+
+cc_binary {
+ name: "android.hardware.vibrator-service.universal7904",
+ relative_install_path: "hw",
+ init_rc: ["android.hardware.vibrator-service.universal7904.rc"],
+ vintf_fragments: ["android.hardware.vibrator-service.universal7904.xml"],
+ srcs: [
+ "Vibrator.cpp",
+ "service.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "android.hardware.vibrator-V2-ndk",
+ ],
+ vendor: true,
+}
diff --git a/aidl/vibrator/Vibrator.cpp b/aidl/vibrator/Vibrator.cpp
new file mode 100644
index 0000000..0f64702
--- /dev/null
+++ b/aidl/vibrator/Vibrator.cpp
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2021 The LineageOS Project
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "Vibrator.h"
+
+#include <android-base/logging.h>
+
+#include <cmath>
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <thread>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace vibrator {
+
+static std::map<Effect, int> CP_TRIGGER_EFFECTS {
+ { Effect::CLICK, 10 },
+ { Effect::DOUBLE_CLICK, 14 },
+ { Effect::HEAVY_CLICK, 23 },
+ { Effect::TEXTURE_TICK, 50 },
+ { Effect::TICK, 50 }
+};
+
+/*
+ * Write value to path and close file.
+ */
+template <typename T>
+static ndk::ScopedAStatus writeNode(const std::string& path, const T& value) {
+ std::ofstream node(path);
+ if (!node) {
+ LOG(ERROR) << "Failed to open: " << path;
+ return ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_ERROR);
+ }
+
+ LOG(DEBUG) << "writeNode node: " << path << " value: " << value;
+
+ node << value << std::endl;
+ if (!node) {
+ LOG(ERROR) << "Failed to write: " << value;
+ return ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_ERROR);
+ }
+
+ return ndk::ScopedAStatus::ok();
+}
+
+static bool nodeExists(const std::string& path) {
+ std::ofstream f(path.c_str());
+ return f.good();
+}
+
+Vibrator::Vibrator() {
+ mIsTimedOutVibrator = nodeExists(VIBRATOR_TIMEOUT_PATH);
+ mHasTimedOutIntensity = nodeExists(VIBRATOR_INTENSITY_PATH);
+ mHasTimedOutEffect = nodeExists(VIBRATOR_CP_TRIGGER_PATH);
+}
+
+ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) {
+ *_aidl_return = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
+ IVibrator::CAP_EXTERNAL_CONTROL /*| IVibrator::CAP_COMPOSE_EFFECTS |
+ IVibrator::CAP_ALWAYS_ON_CONTROL*/;
+
+ if (mHasTimedOutIntensity) {
+ *_aidl_return = *_aidl_return | IVibrator::CAP_AMPLITUDE_CONTROL |
+ IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL;
+ }
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::off() {
+ return activate(0);
+}
+
+ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs, const std::shared_ptr<IVibratorCallback>& callback) {
+ ndk::ScopedAStatus status;
+
+ if (mHasTimedOutEffect)
+ writeNode(VIBRATOR_CP_TRIGGER_PATH, 0); // Clear all effects
+
+ status = activate(timeoutMs);
+
+ if (callback != nullptr) {
+ std::thread([=] {
+ LOG(DEBUG) << "Starting on on another thread";
+ usleep(timeoutMs * 1000);
+ LOG(DEBUG) << "Notifying on complete";
+ if (!callback->onComplete().isOk()) {
+ LOG(ERROR) << "Failed to call onComplete";
+ }
+ }).detach();
+ }
+
+ return status;
+}
+
+ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength, const std::shared_ptr<IVibratorCallback>& callback, int32_t* _aidl_return) {
+ ndk::ScopedAStatus status;
+ uint32_t amplitude = strengthToAmplitude(strength, &status);
+ uint32_t ms = 1000;
+
+ if (!status.isOk())
+ return status;
+
+ activate(0);
+ setAmplitude(amplitude);
+
+ if (mHasTimedOutEffect && CP_TRIGGER_EFFECTS.find(effect) != CP_TRIGGER_EFFECTS.end()) {
+ writeNode(VIBRATOR_CP_TRIGGER_PATH, CP_TRIGGER_EFFECTS[effect]);
+ } else {
+ if (mHasTimedOutEffect)
+ writeNode(VIBRATOR_CP_TRIGGER_PATH, 0); // Clear previous effect
+
+ ms = effectToMs(effect, &status);
+
+ if (!status.isOk())
+ return status;
+ }
+
+ status = activate(ms);
+
+ if (callback != nullptr) {
+ std::thread([=] {
+ LOG(DEBUG) << "Starting perform on another thread";
+ usleep(ms * 1000);
+ LOG(DEBUG) << "Notifying perform complete";
+ callback->onComplete();
+ }).detach();
+ }
+
+ *_aidl_return = ms;
+ return status;
+}
+
+ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect>* _aidl_return) {
+ *_aidl_return = {Effect::CLICK, Effect::DOUBLE_CLICK, Effect::HEAVY_CLICK,
+ Effect::TICK, Effect::TEXTURE_TICK, Effect::THUD, Effect::POP,
+ Effect::RINGTONE_1, Effect::RINGTONE_2, Effect::RINGTONE_3,
+ Effect::RINGTONE_4, Effect::RINGTONE_5, Effect::RINGTONE_6,
+ Effect::RINGTONE_7, Effect::RINGTONE_7, Effect::RINGTONE_8,
+ Effect::RINGTONE_9, Effect::RINGTONE_10, Effect::RINGTONE_11,
+ Effect::RINGTONE_12, Effect::RINGTONE_13, Effect::RINGTONE_14,
+ Effect::RINGTONE_15};
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) {
+ uint32_t intensity;
+
+ if (amplitude == 0) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ LOG(DEBUG) << "Setting amplitude: " << (uint32_t)amplitude;
+
+ intensity = std::lround((amplitude - 1) * INTENSITY_MAX / 254.0);
+ if (intensity > INTENSITY_MAX) {
+ intensity = INTENSITY_MAX;
+ }
+
+ if (intensity == 0) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ LOG(DEBUG) << "Setting intensity: " << intensity;
+
+ if (mHasTimedOutIntensity) {
+ return writeNode(VIBRATOR_INTENSITY_PATH, intensity);
+ }
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) {
+ if (mEnabled) {
+ LOG(WARNING) << "Setting external control while the vibrator is enabled is "
+ "unsupported!";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
+ LOG(INFO) << "ExternalControl: " << mExternalControl << " -> " << enabled;
+ mExternalControl = enabled;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t* /*_aidl_return*/) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t* /*_aidl_return*/) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector<CompositePrimitive>* /*_aidl_return*/) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive /*primitive*/, int32_t* /*_aidl_return*/) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>& /*composite*/, const std::shared_ptr<IVibratorCallback>& /*callback*/) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect>* /*_aidl_return*/) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t /*id*/, Effect /*effect*/, EffectStrength /*strength*/) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t /*id*/) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Vibrator::getResonantFrequency(float* /*_aidl_return*/) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Vibrator::getQFactor(float* /*_aidl_return*/) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Vibrator::getFrequencyResolution(float* /*_aidl_return*/) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Vibrator::getFrequencyMinimum(float* /*_aidl_return*/) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Vibrator::getBandwidthAmplitudeMap(std::vector<float>* /*_aidl_return*/) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Vibrator::getPwlePrimitiveDurationMax(int32_t* /*_aidl_return*/) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Vibrator::getPwleCompositionSizeMax(int32_t* /*_aidl_return*/) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Vibrator::getSupportedBraking(std::vector<Braking>* /*_aidl_return*/) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle>& /*composite*/, const std::shared_ptr<IVibratorCallback>& /*callback*/) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Vibrator::activate(uint32_t timeoutMs) {
+ std::lock_guard<std::mutex> lock{mMutex};
+ if (!mIsTimedOutVibrator) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
+ return writeNode(VIBRATOR_TIMEOUT_PATH, timeoutMs);
+}
+
+uint8_t Vibrator::strengthToAmplitude(EffectStrength strength, ndk::ScopedAStatus* status) {
+ *status = ndk::ScopedAStatus::ok();
+
+ switch (strength) {
+ case EffectStrength::LIGHT:
+ return 64;
+ case EffectStrength::MEDIUM:
+ return 128;
+ case EffectStrength::STRONG:
+ return 255;
+ }
+
+ *status = ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ return 0;
+}
+
+uint32_t Vibrator::effectToMs(Effect effect, ndk::ScopedAStatus* status) {
+ *status = ndk::ScopedAStatus::ok();
+ switch (effect) {
+ case Effect::CLICK:
+ return 10;
+ case Effect::DOUBLE_CLICK:
+ return 15;
+ case Effect::TICK:
+ case Effect::TEXTURE_TICK:
+ case Effect::THUD:
+ case Effect::POP:
+ return 5;
+ case Effect::HEAVY_CLICK:
+ return 10;
+ case Effect::RINGTONE_1:
+ case Effect::RINGTONE_2:
+ case Effect::RINGTONE_3:
+ case Effect::RINGTONE_4:
+ case Effect::RINGTONE_5:
+ case Effect::RINGTONE_6:
+ case Effect::RINGTONE_7:
+ case Effect::RINGTONE_8:
+ case Effect::RINGTONE_9:
+ case Effect::RINGTONE_10:
+ case Effect::RINGTONE_11:
+ case Effect::RINGTONE_12:
+ case Effect::RINGTONE_13:
+ case Effect::RINGTONE_14:
+ case Effect::RINGTONE_15:
+ return 30000;
+ }
+ *status = ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ return 0;
+}
+
+} // namespace vibrator
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/aidl/vibrator/Vibrator.h b/aidl/vibrator/Vibrator.h
new file mode 100644
index 0000000..785ad9d
--- /dev/null
+++ b/aidl/vibrator/Vibrator.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 The LineageOS Project
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/vibrator/BnVibrator.h>
+
+#define INTENSITY_MIN 1000
+#define INTENSITY_MAX 10000
+#define INTENSITY_DEFAULT INTENSITY_MAX
+
+#define VIBRATOR_TIMEOUT_PATH "/sys/class/timed_output/vibrator/enable"
+#define VIBRATOR_INTENSITY_PATH "/sys/class/timed_output/vibrator/intensity"
+#define VIBRATOR_CP_TRIGGER_PATH "/sys/class/timed_output/vibrator/cp_trigger_index"
+
+using ::aidl::android::hardware::vibrator::IVibratorCallback;
+using ::aidl::android::hardware::vibrator::Braking;
+using ::aidl::android::hardware::vibrator::Effect;
+using ::aidl::android::hardware::vibrator::EffectStrength;
+using ::aidl::android::hardware::vibrator::CompositeEffect;
+using ::aidl::android::hardware::vibrator::CompositePrimitive;
+using ::aidl::android::hardware::vibrator::PrimitivePwle;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace vibrator {
+
+class Vibrator : public BnVibrator {
+public:
+ Vibrator();
+ ndk::ScopedAStatus getCapabilities(int32_t* _aidl_return) override;
+ ndk::ScopedAStatus off() override;
+ ndk::ScopedAStatus on(int32_t timeoutMs, const std::shared_ptr<IVibratorCallback>& callback) override;
+ ndk::ScopedAStatus perform(Effect effect, EffectStrength strength, const std::shared_ptr<IVibratorCallback>& callback, int32_t* _aidl_return) override;
+ ndk::ScopedAStatus getSupportedEffects(std::vector<Effect>* _aidl_return) override;
+ ndk::ScopedAStatus setAmplitude(float amplitude) override;
+ ndk::ScopedAStatus setExternalControl(bool enabled) override;
+ ndk::ScopedAStatus getCompositionDelayMax(int32_t* _aidl_return) override;
+ ndk::ScopedAStatus getCompositionSizeMax(int32_t* _aidl_return) override;
+ ndk::ScopedAStatus getSupportedPrimitives(std::vector<CompositePrimitive>* _aidl_return) override;
+ ndk::ScopedAStatus getPrimitiveDuration(CompositePrimitive primitive, int32_t* _aidl_return) override;
+ ndk::ScopedAStatus compose(const std::vector<CompositeEffect>& composite, const std::shared_ptr<IVibratorCallback>& callback) override;
+ ndk::ScopedAStatus getSupportedAlwaysOnEffects(std::vector<Effect>* _aidl_return) override;
+ ndk::ScopedAStatus alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) override;
+ ndk::ScopedAStatus alwaysOnDisable(int32_t id) override;
+ ndk::ScopedAStatus getResonantFrequency(float* _aidl_return) override;
+ ndk::ScopedAStatus getQFactor(float* _aidl_return) override;
+ ndk::ScopedAStatus getFrequencyResolution(float* _aidl_return) override;
+ ndk::ScopedAStatus getFrequencyMinimum(float* _aidl_return) override;
+ ndk::ScopedAStatus getBandwidthAmplitudeMap(std::vector<float>* _aidl_return) override;
+ ndk::ScopedAStatus getPwlePrimitiveDurationMax(int32_t* _aidl_return) override;
+ ndk::ScopedAStatus getPwleCompositionSizeMax(int32_t* _aidl_return) override;
+ ndk::ScopedAStatus getSupportedBraking(std::vector<Braking>* _aidl_return) override;
+ ndk::ScopedAStatus composePwle(const std::vector<PrimitivePwle>& composite, const std::shared_ptr<IVibratorCallback>& callback) override;
+
+private:
+ ndk::ScopedAStatus activate(uint32_t ms);
+ static uint32_t effectToMs(Effect effect, ndk::ScopedAStatus* status);
+ static uint8_t strengthToAmplitude(EffectStrength strength, ndk::ScopedAStatus* status);
+
+ bool mEnabled{false};
+ bool mExternalControl{false};
+ std::mutex mMutex;
+
+ bool mIsTimedOutVibrator;
+ bool mHasTimedOutIntensity;
+ bool mHasTimedOutEffect;
+};
+
+} // namespace vibrator
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/aidl/vibrator/android.hardware.vibrator-service.universal7904.rc b/aidl/vibrator/android.hardware.vibrator-service.universal7904.rc
new file mode 100644
index 0000000..a54361b
--- /dev/null
+++ b/aidl/vibrator/android.hardware.vibrator-service.universal7904.rc
@@ -0,0 +1,10 @@
+on init
+ chown system system /sys/class/timed_output/vibrator/cp_trigger_index
+ chown system system /sys/class/timed_output/vibrator/enable
+ chown system system /sys/class/timed_output/vibrator/intensity
+
+service vendor.vibrator-default /vendor/bin/hw/android.hardware.vibrator-service.universal7904
+ class hal
+ user system
+ group system
+ shutdown critical
diff --git a/aidl/vibrator/android.hardware.vibrator-service.universal7904.xml b/aidl/vibrator/android.hardware.vibrator-service.universal7904.xml
new file mode 100644
index 0000000..49b11ec
--- /dev/null
+++ b/aidl/vibrator/android.hardware.vibrator-service.universal7904.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.vibrator</name>
+ <fqname>IVibrator/default</fqname>
+ </hal>
+</manifest>
diff --git a/aidl/vibrator/service.cpp b/aidl/vibrator/service.cpp
new file mode 100644
index 0000000..db782c8
--- /dev/null
+++ b/aidl/vibrator/service.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2021 The LineageOS Project
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "Vibrator.h"
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <android-base/logging.h>
+
+using ::aidl::android::hardware::vibrator::Vibrator;
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+ std::shared_ptr<Vibrator> vibrator = ndk::SharedRefBase::make<Vibrator>();
+
+ const std::string instance = std::string() + Vibrator::descriptor + "/default";
+ binder_status_t status = AServiceManager_addService(vibrator->asBinder().get(), instance.c_str());
+ CHECK(status == STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
diff --git a/sepolicy/vendor/file_contexts b/sepolicy/vendor/file_contexts
index 6353be3..b8b4a8c 100644
--- a/sepolicy/vendor/file_contexts
+++ b/sepolicy/vendor/file_contexts
@@ -44,3 +44,4 @@
/(vendor|system/vendor)/bin/main_abox u:object_r:abox_exec:s0
/(vendor|system/vendor)/bin/hw/android\.hardware\.camera\.provider@[0-9]\.[0-9]-service_64\.universal7904 u:object_r:hal_camera_default_exec:s0
+/(vendor|system/vendor)/bin/hw/android\.hardware\.vibrator-service\.universal7904 u:object_r:hal_vibrator_default_exec:s0
diff --git a/universal7904-common.mk b/universal7904-common.mk
index 53ff6a6..01ef42b 100644
--- a/universal7904-common.mk
+++ b/universal7904-common.mk
@@ -260,7 +260,7 @@
# Vibrator
PRODUCT_PACKAGES += \
- android.hardware.vibrator-service.samsung
+ android.hardware.vibrator-service.universal7904
# VNDK
PRODUCT_PACKAGES += \