diff --git a/common.mk b/common.mk index 974baa9..2ea8581 100644 --- a/common.mk +++ b/common.mk @@ -381,7 +381,8 @@ PRODUCT_PACKAGES += \ # Sensors PRODUCT_PACKAGES += \ android.hardware.sensors@2.1-service.samsung-multihal \ - android.hardware.sensors@2.0-ScopedWakelock.vendor + android.hardware.sensors@2.0-ScopedWakelock.vendor \ + sensors.samsung PRODUCT_COPY_FILES += \ $(COMMON_PATH)/sensors/hals.conf:$(TARGET_COPY_OUT_VENDOR)/etc/sensors/hals.conf diff --git a/sensors/.clang-format b/sensors/.clang-format new file mode 100644 index 0000000..ae4a451 --- /dev/null +++ b/sensors/.clang-format @@ -0,0 +1,11 @@ +BasedOnStyle: Google +AccessModifierOffset: -2 +AllowShortFunctionsOnASingleLine: Inline +ColumnLimit: 100 +CommentPragmas: NOLINT:.* +DerivePointerAlignment: false +IndentWidth: 4 +PointerAlignment: Left +TabWidth: 4 +UseTab: Never +PenaltyExcessCharacter: 32 diff --git a/sensors/Android.bp b/sensors/Android.bp new file mode 100644 index 0000000..2ce7f2e --- /dev/null +++ b/sensors/Android.bp @@ -0,0 +1,35 @@ +// +// Copyright (C) 2022 The LineageOS Project +// +// SPDX-License-Identifier: Apache-2.0 +// + +cc_library_shared { + name: "sensors.samsung", + defaults: ["hidl_defaults"], + srcs: [ + "Sensor.cpp", + "SensorsSubHal.cpp", + ], + shared_libs: [ + "android.hardware.sensors@1.0", + "android.hardware.sensors@2.0", + "android.hardware.sensors@2.0-ScopedWakelock", + "android.hardware.sensors@2.1", + "libcutils", + "libfmq", + "libhardware", + "libhidlbase", + "liblog", + "libpower", + "libutils", + ], + static_libs: [ + "android.hardware.sensors@1.0-convert", + "android.hardware.sensors@2.X-multihal", + ], + cflags: [ + "-DLOG_TAG=\"sensors.samsung\"", + ], + vendor: true, +} diff --git a/sensors/Sensor.cpp b/sensors/Sensor.cpp new file mode 100644 index 0000000..f59bf0c --- /dev/null +++ b/sensors/Sensor.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2019 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 "Sensor.h" + +#include +#include + +#include + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_1 { +namespace subhal { +namespace implementation { + +using ::android::hardware::sensors::V1_0::MetaDataEventType; +using ::android::hardware::sensors::V1_0::OperationMode; +using ::android::hardware::sensors::V1_0::Result; +using ::android::hardware::sensors::V1_0::SensorFlagBits; +using ::android::hardware::sensors::V1_0::SensorStatus; +using ::android::hardware::sensors::V2_1::Event; +using ::android::hardware::sensors::V2_1::SensorInfo; +using ::android::hardware::sensors::V2_1::SensorType; + +Sensor::Sensor(int32_t sensorHandle, ISensorsEventCallback* callback) + : mIsEnabled(false), + mSamplingPeriodNs(0), + mLastSampleTimeNs(0), + mCallback(callback), + mMode(OperationMode::NORMAL) { + mSensorInfo.sensorHandle = sensorHandle; + mSensorInfo.vendor = "The LineageOS Project"; + mSensorInfo.version = 1; + constexpr float kDefaultMaxDelayUs = 1000 * 1000; + mSensorInfo.maxDelay = kDefaultMaxDelayUs; + mSensorInfo.fifoReservedEventCount = 0; + mSensorInfo.fifoMaxEventCount = 0; + mSensorInfo.requiredPermission = ""; + mSensorInfo.flags = 0; + mRunThread = std::thread(startThread, this); +} + +Sensor::~Sensor() { + // Ensure that lock is unlocked before calling mRunThread.join() or a + // deadlock will occur. + { + std::unique_lock lock(mRunMutex); + mStopThread = true; + mIsEnabled = false; + mWaitCV.notify_all(); + } + mRunThread.join(); +} + +const SensorInfo& Sensor::getSensorInfo() const { + return mSensorInfo; +} + +void Sensor::batch(int32_t samplingPeriodNs) { + samplingPeriodNs = + std::clamp(samplingPeriodNs, mSensorInfo.minDelay * 1000, mSensorInfo.maxDelay * 1000); + + if (mSamplingPeriodNs != samplingPeriodNs) { + mSamplingPeriodNs = samplingPeriodNs; + // Wake up the 'run' thread to check if a new event should be generated now + mWaitCV.notify_all(); + } +} + +void Sensor::activate(bool enable) { + if (mIsEnabled != enable) { + std::unique_lock lock(mRunMutex); + mIsEnabled = enable; + mWaitCV.notify_all(); + } +} + +Result Sensor::flush() { + // Only generate a flush complete event if the sensor is enabled and if the sensor is not a + // one-shot sensor. + if (!mIsEnabled || (mSensorInfo.flags & static_cast(SensorFlagBits::ONE_SHOT_MODE))) { + return Result::BAD_VALUE; + } + + // Note: If a sensor supports batching, write all of the currently batched events for the sensor + // to the Event FMQ prior to writing the flush complete event. + Event ev; + ev.sensorHandle = mSensorInfo.sensorHandle; + ev.sensorType = SensorType::META_DATA; + ev.u.meta.what = MetaDataEventType::META_DATA_FLUSH_COMPLETE; + std::vector evs{ev}; + mCallback->postEvents(evs, isWakeUpSensor()); + + return Result::OK; +} + +void Sensor::startThread(Sensor* sensor) { + sensor->run(); +} + +void Sensor::run() { + std::unique_lock runLock(mRunMutex); + constexpr int64_t kNanosecondsInSeconds = 1000 * 1000 * 1000; + + while (!mStopThread) { + if (!mIsEnabled || mMode == OperationMode::DATA_INJECTION) { + mWaitCV.wait(runLock, [&] { + return ((mIsEnabled && mMode == OperationMode::NORMAL) || mStopThread); + }); + } else { + timespec curTime; + clock_gettime(CLOCK_REALTIME, &curTime); + int64_t now = (curTime.tv_sec * kNanosecondsInSeconds) + curTime.tv_nsec; + int64_t nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs; + + if (now >= nextSampleTime) { + mLastSampleTimeNs = now; + nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs; + mCallback->postEvents(readEvents(), isWakeUpSensor()); + } + + mWaitCV.wait_for(runLock, std::chrono::nanoseconds(nextSampleTime - now)); + } + } +} + +bool Sensor::isWakeUpSensor() { + return mSensorInfo.flags & static_cast(SensorFlagBits::WAKE_UP); +} + +std::vector Sensor::readEvents() { + std::vector events; + Event event; + event.sensorHandle = mSensorInfo.sensorHandle; + event.sensorType = mSensorInfo.type; + event.timestamp = ::android::elapsedRealtimeNano(); + event.u.vec3.x = 0; + event.u.vec3.y = 0; + event.u.vec3.z = 0; + event.u.vec3.status = SensorStatus::ACCURACY_HIGH; + events.push_back(event); + return events; +} + +void Sensor::setOperationMode(OperationMode mode) { + if (mMode != mode) { + std::unique_lock lock(mRunMutex); + mMode = mode; + mWaitCV.notify_all(); + } +} + +bool Sensor::supportsDataInjection() const { + return mSensorInfo.flags & static_cast(SensorFlagBits::DATA_INJECTION); +} + +Result Sensor::injectEvent(const Event& event) { + Result result = Result::OK; + if (event.sensorType == SensorType::ADDITIONAL_INFO) { + // When in OperationMode::NORMAL, SensorType::ADDITIONAL_INFO is used to push operation + // environment data into the device. + } else if (!supportsDataInjection()) { + result = Result::INVALID_OPERATION; + } else if (mMode == OperationMode::DATA_INJECTION) { + mCallback->postEvents(std::vector{event}, isWakeUpSensor()); + } else { + result = Result::BAD_VALUE; + } + return result; +} + +} // namespace implementation +} // namespace subhal +} // namespace V2_1 +} // namespace sensors +} // namespace hardware +} // namespace android diff --git a/sensors/Sensor.h b/sensors/Sensor.h new file mode 100644 index 0000000..7923820 --- /dev/null +++ b/sensors/Sensor.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2019 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 +#include + +using ::android::hardware::sensors::V1_0::OperationMode; +using ::android::hardware::sensors::V1_0::Result; +using ::android::hardware::sensors::V2_1::Event; +using ::android::hardware::sensors::V2_1::SensorInfo; +using ::android::hardware::sensors::V2_1::SensorType; + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_1 { +namespace subhal { +namespace implementation { + +class ISensorsEventCallback { + public: + virtual ~ISensorsEventCallback(){}; + virtual void postEvents(const std::vector& events, bool wakeup) = 0; +}; + +class Sensor { + public: + Sensor(int32_t sensorHandle, ISensorsEventCallback* callback); + virtual ~Sensor(); + + const SensorInfo& getSensorInfo() const; + void batch(int32_t samplingPeriodNs); + virtual void activate(bool enable); + Result flush(); + + void setOperationMode(OperationMode mode); + bool supportsDataInjection() const; + Result injectEvent(const Event& event); + + protected: + void run(); + virtual std::vector readEvents(); + static void startThread(Sensor* sensor); + + bool isWakeUpSensor(); + + bool mIsEnabled; + int64_t mSamplingPeriodNs; + int64_t mLastSampleTimeNs; + SensorInfo mSensorInfo; + + std::atomic_bool mStopThread; + std::condition_variable mWaitCV; + std::mutex mRunMutex; + std::thread mRunThread; + + ISensorsEventCallback* mCallback; + + OperationMode mMode; +}; + +} // namespace implementation +} // namespace subhal +} // namespace V2_1 +} // namespace sensors +} // namespace hardware +} // namespace android diff --git a/sensors/SensorsSubHal.cpp b/sensors/SensorsSubHal.cpp new file mode 100644 index 0000000..6cbcb56 --- /dev/null +++ b/sensors/SensorsSubHal.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2019 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 "SensorsSubHal.h" + +#include +#include + +using ::android::hardware::sensors::V2_1::implementation::ISensorsSubHal; +using ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHal; + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_1 { +namespace subhal { +namespace implementation { + +using ::android::hardware::Void; +using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock; + +SensorsSubHal::SensorsSubHal() : mCallback(nullptr), mNextHandle(1) {} + +Return SensorsSubHal::getSensorsList_2_1(ISensors::getSensorsList_2_1_cb _hidl_cb) { + std::vector sensors; + for (const auto& sensor : mSensors) { + sensors.push_back(sensor.second->getSensorInfo()); + } + _hidl_cb(sensors); + return Void(); +} + +Return SensorsSubHal::setOperationMode(OperationMode mode) { + for (auto sensor : mSensors) { + sensor.second->setOperationMode(mode); + } + mCurrentOperationMode = mode; + return Result::OK; +} + +Return SensorsSubHal::activate(int32_t sensorHandle, bool enabled) { + auto sensor = mSensors.find(sensorHandle); + if (sensor != mSensors.end()) { + sensor->second->activate(enabled); + return Result::OK; + } + return Result::BAD_VALUE; +} + +Return SensorsSubHal::batch(int32_t sensorHandle, int64_t samplingPeriodNs, + int64_t /* maxReportLatencyNs */) { + auto sensor = mSensors.find(sensorHandle); + if (sensor != mSensors.end()) { + sensor->second->batch(samplingPeriodNs); + return Result::OK; + } + return Result::BAD_VALUE; +} + +Return SensorsSubHal::flush(int32_t sensorHandle) { + auto sensor = mSensors.find(sensorHandle); + if (sensor != mSensors.end()) { + return sensor->second->flush(); + } + return Result::BAD_VALUE; +} + +Return SensorsSubHal::injectSensorData_2_1(const Event& event) { + auto sensor = mSensors.find(event.sensorHandle); + if (sensor != mSensors.end()) { + return sensor->second->injectEvent(event); + } + + return Result::BAD_VALUE; +} + +Return SensorsSubHal::registerDirectChannel(const SharedMemInfo& /* mem */, + ISensors::registerDirectChannel_cb _hidl_cb) { + _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */); + return Return(); +} + +Return SensorsSubHal::unregisterDirectChannel(int32_t /* channelHandle */) { + return Result::INVALID_OPERATION; +} + +Return SensorsSubHal::configDirectReport(int32_t /* sensorHandle */, + int32_t /* channelHandle */, RateLevel /* rate */, + ISensors::configDirectReport_cb _hidl_cb) { + _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */); + return Return(); +} + +Return SensorsSubHal::debug(const hidl_handle& fd, const hidl_vec& args) { + if (fd.getNativeHandle() == nullptr || fd->numFds < 1) { + ALOGE("%s: missing fd for writing", __FUNCTION__); + return Void(); + } + + FILE* out = fdopen(dup(fd->data[0]), "w"); + + if (args.size() != 0) { + fprintf(out, + "Note: sub-HAL %s currently does not support args. Input arguments are " + "ignored.\n", + getName().c_str()); + } + + std::ostringstream stream; + stream << "Available sensors:" << std::endl; + for (auto sensor : mSensors) { + SensorInfo info = sensor.second->getSensorInfo(); + stream << "Name: " << info.name << std::endl; + stream << "Min delay: " << info.minDelay << std::endl; + stream << "Flags: " << info.flags << std::endl; + } + stream << std::endl; + + fprintf(out, "%s", stream.str().c_str()); + + fclose(out); + return Return(); +} + +Return SensorsSubHal::initialize(const sp& halProxyCallback) { + mCallback = halProxyCallback; + setOperationMode(OperationMode::NORMAL); + return Result::OK; +} + +void SensorsSubHal::postEvents(const std::vector& events, bool wakeup) { + ScopedWakelock wakelock = mCallback->createScopedWakelock(wakeup); + mCallback->postEvents(events, std::move(wakelock)); +} + +} // namespace implementation +} // namespace subhal +} // namespace V2_1 +} // namespace sensors +} // namespace hardware +} // namespace android + +ISensorsSubHal* sensorsHalGetSubHal_2_1(uint32_t* version) { + static SensorsSubHal subHal; + *version = SUB_HAL_2_1_VERSION; + return &subHal; +} diff --git a/sensors/SensorsSubHal.h b/sensors/SensorsSubHal.h new file mode 100644 index 0000000..6dccd42 --- /dev/null +++ b/sensors/SensorsSubHal.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2019 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 "Sensor.h" +#include "V2_1/SubHal.h" + +namespace android { +namespace hardware { +namespace sensors { +namespace V2_1 { +namespace subhal { +namespace implementation { + +using ::android::hardware::sensors::V1_0::OperationMode; +using ::android::hardware::sensors::V1_0::RateLevel; +using ::android::hardware::sensors::V1_0::Result; +using ::android::hardware::sensors::V1_0::SharedMemInfo; +using ::android::hardware::sensors::V2_1::Event; +using ::android::hardware::sensors::V2_1::implementation::IHalProxyCallback; +using ::android::hardware::sensors::V2_1::implementation::ISensorsSubHal; + +class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback { + public: + SensorsSubHal(); + + Return getSensorsList_2_1(ISensors::getSensorsList_2_1_cb _hidl_cb); + Return injectSensorData_2_1(const Event& event); + Return initialize(const sp& halProxyCallback); + + virtual Return setOperationMode(OperationMode mode); + + OperationMode getOperationMode() const { return mCurrentOperationMode; } + + Return activate(int32_t sensorHandle, bool enabled); + + Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, int64_t maxReportLatencyNs); + + Return flush(int32_t sensorHandle); + + Return registerDirectChannel(const SharedMemInfo& mem, + ISensors::registerDirectChannel_cb _hidl_cb); + + Return unregisterDirectChannel(int32_t channelHandle); + + Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate, + ISensors::configDirectReport_cb _hidl_cb); + + Return debug(const hidl_handle& fd, const hidl_vec& args); + + const std::string getName() { return "FakeSubHal"; } + + void postEvents(const std::vector& events, bool wakeup) override; + + protected: + template + void AddSensor() { + std::shared_ptr sensor = + std::make_shared(mNextHandle++ /* sensorHandle */, this /* callback */); + mSensors[sensor->getSensorInfo().sensorHandle] = sensor; + } + + std::map> mSensors; + + sp mCallback; + + private: + OperationMode mCurrentOperationMode = OperationMode::NORMAL; + + int32_t mNextHandle; +}; + +} // namespace implementation +} // namespace subhal +} // namespace V2_1 +} // namespace sensors +} // namespace hardware +} // namespace android diff --git a/sensors/hals.conf b/sensors/hals.conf index 03fbb56..ae2f725 100644 --- a/sensors/hals.conf +++ b/sensors/hals.conf @@ -1,2 +1,3 @@ sensors.ssc.so sensors.grip.so +sensors.samsung.so