/* * 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 #include #include static bool readEvent(int fd, struct input_event *event) { int rc; rc = read(fd, event, sizeof(struct input_event)); if (rc != sizeof(struct input_event)) { ALOGE("failed to read event from fd, err: %d", rc); return false; } return true; } static bool readBool(int fd, bool seek) { char c; int rc; if (seek) { rc = lseek(fd, 0, SEEK_SET); if (rc) { ALOGE("failed to seek: %d", rc); return false; } } rc = read(fd, &c, sizeof(c)); if (rc != 1) { ALOGE("failed to read bool: %d", rc); return false; } return c != '0'; } 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) { std::lock_guard lock(mRunMutex); if (mIsEnabled != enable) { 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) { 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) { std::lock_guard lock(mRunMutex); if (mMode != mode) { 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; } OneShotSensor::OneShotSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(sensorHandle, callback) { mSensorInfo.minDelay = -1; mSensorInfo.maxDelay = 0; mSensorInfo.flags |= SensorFlagBits::ONE_SHOT_MODE; } #define INPUT_DT2W_SENSOR_PATH "/dev/input/event10" #define INPUT_TOUCHSCREEN_PATH "/dev/input/event11" #define GESTURE_PATH "/sys/class/touchscreen/primary/gesture" InputEventDT2WSensor::InputEventDT2WSensor( int32_t sensorHandle, ISensorsEventCallback* callback) : OneShotSensor(sensorHandle, callback) { mSensorInfo.name = "DT2W sensor"; mSensorInfo.type = static_cast(static_cast(SensorType::DEVICE_PRIVATE_BASE) + 1); mSensorInfo.typeAsString = "org.lineageos.sensor.dt2w"; mSensorInfo.maxRange = 2048.0f; mSensorInfo.resolution = 1.0f; mSensorInfo.power = 0; mSensorInfo.flags |= SensorFlagBits::WAKE_UP; std::ofstream mGestureEnable; mGestureEnable.open(GESTURE_PATH); if(!mGestureEnable) { ALOGE("could not open gesture path"); mStopThread = true; return; } mGestureEnable << "49" << std::flush; int rc; rc = pipe(mWaitPipeFd); if (rc < 0) { mWaitPipeFd[0] = -1; mWaitPipeFd[1] = -1; ALOGE("failed to open wait pipe: %d", rc); } mPollFds[0] = open(INPUT_DT2W_SENSOR_PATH, O_RDONLY | O_NONBLOCK); if (mPollFds[0] < 0) { ALOGE("failed to open poll fd: %d", mPollFds[0]); } mPollFds[1] = open(INPUT_TOUCHSCREEN_PATH, O_RDONLY | O_NONBLOCK); if (mPollFds[1] < 0) { ALOGE("failed to open poll fd: %d", mPollFds[1]); } if (mWaitPipeFd[0] < 0 || mWaitPipeFd[1] < 0 || mPollFds[0] < 0 || mPollFds[1] < 0) { mStopThread = true; return; } mPolls[0] = { .fd = mWaitPipeFd[0], .events = POLLIN, }; mPolls[1] = { .fd = mPollFds[0], .events = POLLIN, }; mPolls[2] = { .fd = mPollFds[1], .events = POLLIN, }; } InputEventDT2WSensor::~InputEventDT2WSensor() { interruptPoll(); } void InputEventDT2WSensor::activate(bool enable) { std::lock_guard lock(mRunMutex); if (mIsEnabled != enable) { mIsEnabled = enable; interruptPoll(); mWaitCV.notify_all(); } } void InputEventDT2WSensor::setOperationMode(OperationMode mode) { Sensor::setOperationMode(mode); interruptPoll(); } void InputEventDT2WSensor::run() { std::unique_lock runLock(mRunMutex); long old_time = 0; long new_time = 0; int old_x = 0; int new_x = 0; int old_y = 0; int new_y = 0; while (!mStopThread) { if (!mIsEnabled || mMode == OperationMode::DATA_INJECTION) { mWaitCV.wait(runLock, [&] { return ((mIsEnabled && mMode == OperationMode::NORMAL) || mStopThread); }); } else { // Cannot hold lock while polling. runLock.unlock(); int rc = poll(mPolls, 3, -1); runLock.lock(); struct input_event event; if (rc < 0) { ALOGE("failed to poll: %d", rc); mStopThread = true; continue; } if((mPolls[1].revents == mPolls[1].events) && readEvent(mPolls[1].fd, &event)) { if(event.type == EV_KEY && event.value == 1 && event.code == KEY_F4) { mIsEnabled = false; mCallback->postEvents(readEvents(), isWakeUpSensor()); } } else if((mPolls[2].revents == mPolls[2].events) && readEvent(mPolls[2].fd, &event)) { if(event.type == EV_KEY && event.value == 1) { // Touchscreen down/up old_time = new_time; new_time = event.time.tv_sec * 1000000 + event.time.tv_usec; if((new_time - old_time < 200000) && // 200ms (abs(sqrt(pow(old_x, 2) + pow(old_y, 2)) - sqrt(pow(new_x, 2) + pow(new_y, 2))) < 500)) { mIsEnabled = false; mCallback->postEvents(readEvents(), isWakeUpSensor()); } } else if(event.type == EV_ABS) { // send order: touch pos x -> touch y -> down/up if(event.code == ABS_MT_POSITION_X) { old_x = new_x; new_x = event.value; } else if (event.code == ABS_MT_POSITION_Y) { old_y = new_y; new_y = event.value; } } } else if (mPolls[0].revents == mPolls[0].events) { readBool(mWaitPipeFd[0], false /* seek */); } } } } void InputEventDT2WSensor::interruptPoll() { if (mWaitPipeFd[1] < 0) return; char c = '1'; write(mWaitPipeFd[1], &c, sizeof(c)); } std::vector InputEventDT2WSensor::readEvents() { std::vector events; Event event; event.sensorHandle = mSensorInfo.sensorHandle; event.sensorType = mSensorInfo.type; event.timestamp = ::android::elapsedRealtimeNano(); event.u.data[0] = 0; event.u.data[1] = 0; events.push_back(event); return events; } } // namespace implementation } // namespace subhal } // namespace V2_1 } // namespace sensors } // namespace hardware } // namespace android