summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbelgin <contact@belgin.ro>2021-09-26 23:14:29 +0300
committerDenis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>2021-09-27 22:39:25 +0200
commit055142135f6dba5ff872347fb5551ea9c23baada (patch)
treeb9a3479b6f806a5f8625e7b7139c6c04c51655a4
parente7f29640047b2eb9562a56e39b2caa76aa79a0b8 (diff)
downloaddevice_samsung_midas_common-055142135f6dba5ff872347fb5551ea9c23baada.tar.gz
device_samsung_midas_common-055142135f6dba5ff872347fb5551ea9c23baada.tar.bz2
device_samsung_midas_common-055142135f6dba5ff872347fb5551ea9c23baada.zip
Implemented the AIDL HAL for the vibrator service.
This should work on all Midas devices. I only tested it on i9300 though. This implementation was written from scratch by looking at the vibrator API in the aidl interface files to see what needed to be implemented. TODO: - Move this implementation in hardware/replicant. - When the device goes back in sleep and is then waken up, the vibrations are really low in amplitude. Signed-off-by: belgin <contact@belgin.ro> GNUtoo: Add TODO in commit message, add more infos about origin Signed-off-by: Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
-rw-r--r--midas.mk3
-rw-r--r--sepolicy/file_contexts1
-rw-r--r--sepolicy/vibrator.te2
-rw-r--r--vibrator/Android.bp14
-rw-r--r--vibrator/vibrator.cpp242
-rw-r--r--vibrator/vibrator.rc5
-rw-r--r--vibrator/vibrator.xml6
7 files changed, 271 insertions, 2 deletions
diff --git a/midas.mk b/midas.mk
index 6212b1e..beaf0f5 100644
--- a/midas.mk
+++ b/midas.mk
@@ -209,8 +209,7 @@ PRODUCT_COPY_FILES += \
############
# HAL packages
-PRODUCT_PACKAGES += \
- android.hardware.vibrator@1.0-impl \
+PRODUCT_PACKAGES += vibrator-midas
########
# VNDK #
diff --git a/sepolicy/file_contexts b/sepolicy/file_contexts
index c156bd4..8803b06 100644
--- a/sepolicy/file_contexts
+++ b/sepolicy/file_contexts
@@ -1,3 +1,4 @@
/(vendor|system/vendor)/bin/hw/android\.hardware\.gatekeeper@1\.0-service\.software u:object_r:hal_gatekeeper_default_exec:s0
/(vendor|system/vendor)/bin/hw/lights-midas u:object_r:hal_light_default_exec:s0
+/(vendor|system/vendor)/bin/hw/vibrator-midas u:object_r:hal_vibrator_default_exec:s0
diff --git a/sepolicy/vibrator.te b/sepolicy/vibrator.te
new file mode 100644
index 0000000..dc82ec3
--- /dev/null
+++ b/sepolicy/vibrator.te
@@ -0,0 +1,2 @@
+allow hal_vibrator_default input_device:dir r_dir_perms;
+allow hal_vibrator_default input_device:chr_file rw_file_perms;
diff --git a/vibrator/Android.bp b/vibrator/Android.bp
new file mode 100644
index 0000000..4ae92c0
--- /dev/null
+++ b/vibrator/Android.bp
@@ -0,0 +1,14 @@
+cc_binary {
+ name: "vibrator-midas",
+ relative_install_path: "hw",
+ init_rc: ["vibrator.rc"],
+ vintf_fragments: ["vibrator.xml"],
+ vendor: true,
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "android.hardware.vibrator-ndk_platform",
+ ],
+
+ srcs: ["vibrator.cpp"],
+}
diff --git a/vibrator/vibrator.cpp b/vibrator/vibrator.cpp
new file mode 100644
index 0000000..72be201
--- /dev/null
+++ b/vibrator/vibrator.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2021 Belgin Știrbu
+ *
+ * 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.
+ */
+
+#define LOG_TAG "midas-vibrator"
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <linux/input.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <thread>
+
+#include <aidl/android/hardware/vibrator/BnVibrator.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using ::aidl::android::hardware::vibrator::BnVibrator;
+using ::aidl::android::hardware::vibrator::IVibrator;
+using ::aidl::android::hardware::vibrator::IVibratorCallback;
+using ::aidl::android::hardware::vibrator::Effect;
+using ::aidl::android::hardware::vibrator::CompositeEffect;
+using ::aidl::android::hardware::vibrator::EffectStrength;
+using ::aidl::android::hardware::vibrator::CompositePrimitive;
+using ::ndk::ScopedAStatus;
+using ::ndk::SharedRefBase;
+
+struct Vibrator : public BnVibrator {
+public:
+ Vibrator()
+ {
+ int ret;
+
+ std::string dev_input("/dev/input/");
+
+ DIR *directory = opendir(dev_input.c_str());
+ if (!directory) {
+ LOG(ERROR) << "Failed to open " << dev_input << " " << strerror(errno);
+ return;
+ }
+
+ struct dirent *entry;
+ while ((entry = readdir(directory))) {
+ auto target = dev_input + entry->d_name;
+ if (entry->d_type != DT_CHR)
+ continue;
+
+ fd = open(target.c_str(), O_RDWR);
+ if (fd < 0) {
+ LOG(ERROR) << "Failed to open " << target << " " << strerror(errno);
+ continue;
+ }
+
+ unsigned char features[FF_RUMBLE / 8 + 1];
+ ret = ioctl(fd, EVIOCGBIT(EV_FF, sizeof(features)), &features);
+ if (ret < 0) {
+ LOG(ERROR) << "EVIOCGBIT failed: " << strerror(ret);
+ close(fd);
+ continue;
+ }
+ if (ret != sizeof(features)) {
+ LOG(ERROR) << "EVIOCGBIT did not retrieve all feature bits";
+ close(fd);
+ continue;
+ }
+
+ if (!(features[FF_RUMBLE / 8] & (1 << (FF_RUMBLE % 8)))) {
+ close(fd);
+ continue;
+ }
+
+ LOG(INFO) << "Using " << target << " with FF_RUMBLE support";
+ closedir(directory);
+
+ return;
+ }
+
+ LOG(ERROR) << "Failed to find an input device with FF_RUMBLE support";
+ closedir(directory);
+ exit(1);
+ }
+
+ ScopedAStatus getCapabilities(int32_t* _aidl_return) override {
+ *_aidl_return = IVibrator::CAP_ON_CALLBACK;
+ LOG(DEBUG) << "Vibrator reporting capabilities: " << *_aidl_return;
+ return ScopedAStatus::ok();
+ }
+
+ ScopedAStatus playEffect(bool on)
+ {
+ LOG(INFO) << (on ? "Playing" : "Stopping") << " effect " << effect_id;
+
+ if (effect_id == -1)
+ return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+
+ struct input_event ie;
+ ie.type = EV_FF;
+ ie.code = effect_id;
+ ie.value = on;
+
+ LOG(DEBUG) << (on ? "Playing" : "Stopping") << " effect " << effect_id;
+
+ if (write(fd, &ie, sizeof(ie)) != sizeof(ie)) {
+ LOG(ERROR) << "Failed to turn " << on ? "on" : "off";
+ return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
+ return ScopedAStatus::ok();
+ }
+
+ ScopedAStatus on(int32_t timeoutMs,
+ const std::shared_ptr<IVibratorCallback>& callback) override {
+ int ret;
+ struct ff_effect effect {
+ .type = FF_RUMBLE,
+ .id = (int16_t)effect_id,
+ .u.rumble.strong_magnitude = 0xFFFF,
+ .replay.length = (uint16_t)timeoutMs,
+ };
+
+ LOG(DEBUG) << "Enabling for " << timeoutMs << "ms";
+
+ ret = ioctl(fd, EVIOCSFF, &effect);
+ if (ret < 0) {
+ LOG(ERROR) << "Failed to write ff_effect: " << strerror(ret);
+ return ScopedAStatus::fromExceptionCode(EX_SERVICE_SPECIFIC);
+ }
+
+ effect_id = effect.id;
+
+ playEffect(true);
+
+ 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 ScopedAStatus::ok();
+ }
+
+ ScopedAStatus off() override
+ {
+ return playEffect(false);
+ }
+
+ ScopedAStatus setAmplitude(float /* amplitude */) override
+ {
+ return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
+ ScopedAStatus perform(Effect /*effect*/,
+ EffectStrength /*es*/,
+ const std::shared_ptr<IVibratorCallback>& /*callback*/,
+ int32_t* /*_aidl_return*/) override {
+ return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
+ ScopedAStatus getSupportedEffects(std::vector<Effect>* /*_aidl_return*/) override {
+ return ScopedAStatus::ok();
+ }
+
+ ndk::ScopedAStatus setExternalControl(bool /*enabled*/) override {
+ return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
+ ScopedAStatus getPrimitiveDuration(CompositePrimitive /*primitive*/,
+ int32_t* /*durationMs*/) override {
+ return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
+ ScopedAStatus compose(const std::vector<CompositeEffect>& /*composite*/,
+ const std::shared_ptr<IVibratorCallback>& /*callback*/) override {
+ return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
+ ScopedAStatus alwaysOnEnable(int32_t /*id*/, Effect /*effect*/, EffectStrength /*strength*/) override {
+ return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
+ ScopedAStatus alwaysOnDisable(int32_t /*id*/) override {
+ return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
+ ScopedAStatus getCompositionDelayMax(int32_t* /*maxDelayMs*/) {
+ return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
+ ScopedAStatus getCompositionSizeMax(int32_t* /*maxSize*/) {
+ return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
+ ScopedAStatus getSupportedAlwaysOnEffects(std::vector<Effect>* /*_aidl_return*/) override {
+ return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
+ ScopedAStatus getSupportedPrimitives(std::vector<CompositePrimitive>* /*supported*/) override {
+ return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
+private:
+ int fd = -1;
+ uint16_t effect_id = -1;
+};
+
+int main()
+{
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+ std::shared_ptr<Vibrator> vibrator = SharedRefBase::make<Vibrator>();
+
+ const std::string instance = std::string() + Vibrator::descriptor + "/default";
+ binder_status_t status = AServiceManager_addService(vibrator->asBinder().get(), instance.c_str());
+
+ if (status != STATUS_OK) {
+ LOG(ERROR) << "Could not register" << instance;
+ // should abort, but don't want crash loop for local testing
+ }
+
+ ABinderProcess_joinThreadPool();
+
+ return 1; // should not reach
+}
diff --git a/vibrator/vibrator.rc b/vibrator/vibrator.rc
new file mode 100644
index 0000000..6778420
--- /dev/null
+++ b/vibrator/vibrator.rc
@@ -0,0 +1,5 @@
+service vendor.vibrator-midas /vendor/bin/hw/vibrator-midas
+ class hal
+ user system
+ group system input
+ shutdown critical
diff --git a/vibrator/vibrator.xml b/vibrator/vibrator.xml
new file mode 100644
index 0000000..49b11ec
--- /dev/null
+++ b/vibrator/vibrator.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>