/* * Copyright (C) 2017 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 "ASensorEventQueue.h" #include "ALooper.h" #define LOG_TAG "libsensorndkbridge" #include #include using aidl::android::hardware::sensors::SensorInfo; using android::BAD_VALUE; using android::Mutex; using android::OK; ASensorEventQueue::ASensorEventQueue(ALooper* looper, ALooper_callbackFunc callback, void* data) : mLooper(looper), mCallback(callback), mData(data), mRequestAdditionalInfo(false), mValid(true) {} void ASensorEventQueue::setImpl(const std::shared_ptr& queueImpl) { mQueueImpl = queueImpl; } int ASensorEventQueue::registerSensor( ASensorRef sensor, int32_t samplingPeriodUs, int64_t maxBatchReportLatencyUs) { ndk::ScopedAStatus ret = mQueueImpl->enableSensor(reinterpret_cast(sensor)->sensorHandle, samplingPeriodUs, maxBatchReportLatencyUs); if (!ret.isOk()) { return BAD_VALUE; } return OK; } int ASensorEventQueue::enableSensor(ASensorRef sensor) { static constexpr int32_t SENSOR_DELAY_NORMAL = 200000; return registerSensor( sensor, SENSOR_DELAY_NORMAL, 0 /* maxBatchReportLatencyUs */); } int ASensorEventQueue::setEventRate( ASensorRef sensor, int32_t samplingPeriodUs) { // Technically this is not supposed to enable the sensor but using this // API without enabling the sensor first is a no-op, so... return registerSensor( sensor, samplingPeriodUs, 0 /* maxBatchReportLatencyUs */); } int ASensorEventQueue::requestAdditionalInfoEvents(bool enable) { mRequestAdditionalInfo = enable; return OK; } int ASensorEventQueue::disableSensor(ASensorRef sensor) { ndk::ScopedAStatus ret = mQueueImpl->disableSensor(reinterpret_cast(sensor)->sensorHandle); return ret.isOk() ? OK : BAD_VALUE; } ssize_t ASensorEventQueue::getEvents(ASensorEvent *events, size_t count) { // XXX Should this block if there aren't any events in the queue? Mutex::Autolock autoLock(mLock); static_assert( sizeof(ASensorEvent) == sizeof(sensors_event_t), "mismatched size"); size_t copy = std::min(count, mQueue.size()); for (size_t i = 0; i < copy; ++i) { reinterpret_cast(events)[i] = mQueue[i]; } mQueue.erase(mQueue.begin(), mQueue.begin() + copy); LOG(VERBOSE) << "ASensorEventQueue::getEvents() returned " << copy << " events."; return copy; } int ASensorEventQueue::hasEvents() const { return !mQueue.empty(); } ndk::ScopedAStatus ASensorEventQueue::onEvent(const Event& event) { LOG(VERBOSE) << "ASensorEventQueue::onEvent"; if (static_cast(event.sensorType) != ASENSOR_TYPE_ADDITIONAL_INFO || mRequestAdditionalInfo.load()) { { // Only lock the mutex in this block to avoid the following deadlock scenario: // // ASensorEventQueue::onEvent is called which grabs ASensorEventQueue::mLock followed // by ALooper::mLock via ALooper::signalSensorEvents. // // Meanwhile // // ASensorEventQueue::dispatchCallback is invoked from ALooper::pollOnce which has // has ALooper::mLock locked and the dispatched callback invokes // ASensorEventQueue::getEvents which would try to grab ASensorEventQueue::mLock // resulting in a deadlock. Mutex::Autolock autoLock(mLock); mQueue.emplace_back(); sensors_event_t* sensorEvent = &mQueue[mQueue.size() - 1]; android::hardware::sensors::implementation::convertToSensorEvent(event, sensorEvent); } Mutex::Autolock autoLock(mValidLock); if (mValid) { mLooper->signalSensorEvents(this->ref()); } } return ndk::ScopedAStatus::ok(); } void ASensorEventQueue::dispatchCallback() { if (mCallback != NULL) { int res = (*mCallback)(-1 /* fd */, ALOOPER_EVENT_INPUT, mData); if (res == 0) { mCallback = NULL; mData = NULL; } } } void ASensorEventQueue::invalidate() { { // Only lock within this context to avoid locking while calling invalidateSensorQueue which // also holds a lock. This is safe to do because mValid can't be made true after it's false // so onEvent will never signal new sensor events after mValid is false. Mutex::Autolock autoLock(mValidLock); mValid = false; } mLooper->invalidateSensorQueue(this->ref()); setImpl(nullptr); }