| /* |
| * 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 "BaseDynamicSensorDaemon.h" |
| #include "BaseSensorObject.h" |
| #include "DummyDynamicAccelDaemon.h" |
| #include "HidRawSensorDaemon.h" |
| #include "DynamicSensorManager.h" |
| |
| #include <utils/Log.h> |
| #include <utils/SystemClock.h> |
| |
| #include <cassert> |
| |
| namespace android { |
| namespace SensorHalExt { |
| |
| DynamicSensorManager* DynamicSensorManager::createInstance( |
| int handleBase, int handleCount, SensorEventCallback *callback) { |
| auto m = new DynamicSensorManager(handleBase, handleBase + handleCount - 1, callback); |
| m->mDaemonVector.push_back(new DummyDynamicAccelDaemon(*m)); |
| m->mDaemonVector.push_back(new HidRawSensorDaemon(*m)); |
| return m; |
| } |
| |
| DynamicSensorManager::DynamicSensorManager( |
| int handleBase, int handleMax, SensorEventCallback* callback) : |
| mHandleRange(handleBase, handleMax), |
| mCallback(callback), |
| mFifo(callback ? 0 : kFifoSize), |
| mNextHandle(handleBase+1) { |
| assert(handleBase > 0 && handleMax > handleBase + 1); // handleBase is reserved |
| |
| mMetaSensor = (const sensor_t) { |
| "Dynamic Sensor Manager", |
| "Google", |
| 1, // version |
| handleBase, // handle |
| SENSOR_TYPE_DYNAMIC_SENSOR_META, |
| 1, // maxRange |
| 1, // resolution |
| 1e-6f, // power, very small number instead of 0 |
| // to avoid sigularity in app |
| (int32_t)(1000), // minDelay |
| 0, // fifoReservedEventCount |
| 0, // fifoMaxEventCount |
| SENSOR_STRING_TYPE_DYNAMIC_SENSOR_META, |
| "", // requiredPermission |
| (long)(1000), // maxDelay |
| SENSOR_FLAG_SPECIAL_REPORTING_MODE | SENSOR_FLAG_WAKE_UP, |
| { NULL, NULL } |
| }; |
| } |
| |
| DynamicSensorManager::~DynamicSensorManager() { |
| // free all daemons first |
| mDaemonVector.clear(); |
| } |
| |
| bool DynamicSensorManager::owns(int handle) const { |
| return handle >= mHandleRange.first && handle < mHandleRange.second; |
| } |
| |
| int DynamicSensorManager::activate(int handle, bool enable) { |
| if (handle == mHandleRange.first) { |
| // ignored |
| return 0; |
| } |
| |
| // in case there is a pending report, now it is time to remove it as it is no longer necessary. |
| { |
| std::lock_guard<std::mutex> lk(mLock); |
| mPendingReport.erase(handle); |
| } |
| |
| return operateSensor(handle, |
| [&enable] (sp<BaseSensorObject> s)->int { |
| return s->enable(enable); |
| }); |
| } |
| |
| int DynamicSensorManager::batch(int handle, nsecs_t sample_period, nsecs_t batch_period) { |
| if (handle == mHandleRange.first) { |
| // ignored |
| return 0; |
| } |
| return operateSensor(handle, |
| [&sample_period, &batch_period] (sp<BaseSensorObject> s)->int { |
| return s->batch(sample_period, batch_period); |
| }); |
| } |
| |
| int DynamicSensorManager::setDelay(int handle, nsecs_t sample_period) { |
| return batch(handle, sample_period, 0); |
| } |
| |
| int DynamicSensorManager::flush(int handle) { |
| if (handle == mHandleRange.first) { |
| // submit a flush complete here |
| static const sensors_event_t event = { |
| .type = SENSOR_TYPE_META_DATA, |
| .sensor = mHandleRange.first, |
| .timestamp = TIMESTAMP_AUTO_FILL, // timestamp will be filled at dispatcher |
| }; |
| submitEvent(nullptr, event); |
| return 0; |
| } |
| return operateSensor(handle, [] (sp<BaseSensorObject> s)->int {return s->flush();}); |
| } |
| |
| int DynamicSensorManager::poll(sensors_event_t * data, int count) { |
| assert(mCallback == nullptr); |
| std::lock_guard<std::mutex> lk(mFifoLock); |
| return mFifo.read(data, count); |
| } |
| |
| bool DynamicSensorManager::registerSensor(sp<BaseSensorObject> sensor) { |
| std::lock_guard<std::mutex> lk(mLock); |
| if (mReverseMap.find(sensor.get()) != mReverseMap.end()) { |
| ALOGE("trying to add the same sensor twice, ignore"); |
| return false; |
| } |
| int handle = getNextAvailableHandle(); |
| if (handle < 0) { |
| ALOGE("Running out of handle, quit."); |
| return false; |
| } |
| |
| // these emplace will always be successful |
| mMap.emplace(handle, sensor); |
| mReverseMap.emplace(sensor.get(), handle); |
| sensor->setEventCallback(this); |
| |
| auto entry = mPendingReport.emplace( |
| std::piecewise_construct, |
| std::forward_as_tuple(handle), |
| std::forward_as_tuple(handle, sensor)); |
| if (entry.second) { |
| submitEvent(nullptr, entry.first->second.generateConnectionEvent(mHandleRange.first)); |
| } |
| return entry.second; |
| } |
| |
| void DynamicSensorManager::unregisterSensor(sp<BaseSensorObject> sensor) { |
| std::lock_guard<std::mutex> lk(mLock); |
| auto i = mReverseMap.find(sensor.get()); |
| if (i == mReverseMap.end()) { |
| ALOGE("cannot remove a non-exist sensor"); |
| return; |
| } |
| int handle = i->second; |
| mReverseMap.erase(i); |
| mMap.erase(handle); |
| |
| // will not clean up mPendingReport here, it will be cleaned up when at first activate call. |
| // sensorservice is guranteed to call activate upon arrival of dynamic sensor meta connection |
| // event. |
| |
| // send disconnection event |
| sensors_event_t event; |
| ConnectionReport::fillDisconnectionEvent(&event, mHandleRange.first, handle); |
| submitEvent(nullptr, event); |
| } |
| |
| int DynamicSensorManager::submitEvent(sp<BaseSensorObject> source, const sensors_event_t &e) { |
| int handle; |
| if (source == nullptr) { |
| handle = mHandleRange.first; |
| } else { |
| std::lock_guard<std::mutex> lk(mLock); |
| auto i = mReverseMap.find(source.get()); |
| if (i == mReverseMap.end()) { |
| ALOGE("cannot submit event for sensor that has not been registered"); |
| return NAME_NOT_FOUND; |
| } |
| handle = i->second; |
| } |
| |
| // making a copy of events, prepare for editing |
| sensors_event_t event = e; |
| event.version = sizeof(event); |
| |
| // special case of flush complete |
| if (event.type == SENSOR_TYPE_META_DATA) { |
| event.sensor = 0; |
| event.meta_data.sensor = handle; |
| } else { |
| event.sensor = handle; |
| } |
| |
| // set timestamp if it is default value |
| if (event.timestamp == TIMESTAMP_AUTO_FILL) { |
| event.timestamp = elapsedRealtimeNano(); |
| } |
| |
| if (mCallback) { |
| // extention mode, calling callback directly |
| int ret; |
| |
| ret = mCallback->submitEvent(nullptr, event); |
| if (ret < 0) { |
| ALOGE("DynamicSensorManager callback failed, ret: %d", ret); |
| } |
| } else { |
| // standalone mode, add event to internal buffer for poll() to pick up |
| std::lock_guard<std::mutex> lk(mFifoLock); |
| if (mFifo.write(&event, 1) < 0) { |
| ALOGE("DynamicSensorManager fifo full"); |
| } |
| } |
| return 0; |
| } |
| |
| int DynamicSensorManager::getNextAvailableHandle() { |
| if (mNextHandle == mHandleRange.second) { |
| return -1; |
| } |
| return mNextHandle++; |
| } |
| |
| const sensor_t& DynamicSensorManager::getDynamicMetaSensor() const { |
| return mMetaSensor; |
| } |
| |
| DynamicSensorManager::ConnectionReport::ConnectionReport( |
| int handle, sp<BaseSensorObject> sensor) : |
| mSensor(*(sensor->getSensor())), |
| mName(mSensor.name), |
| mVendor(mSensor.vendor), |
| mPermission(mSensor.requiredPermission), |
| mStringType(mSensor.stringType), |
| mGenerated(false) { |
| mSensor.name = mName.c_str(); |
| mSensor.vendor = mVendor.c_str(); |
| mSensor.requiredPermission = mPermission.c_str(); |
| mSensor.stringType = mStringType.c_str(); |
| mSensor.handle = handle; |
| memset(&mEvent, 0, sizeof(mEvent)); |
| mEvent.version = sizeof(mEvent); |
| sensor->getUuid(mUuid); |
| ALOGV("Connection report init: name = %s, handle = %d", mSensor.name, mSensor.handle); |
| } |
| |
| DynamicSensorManager::ConnectionReport::~ConnectionReport() { |
| ALOGV("Connection report dtor: name = %s, handle = %d", mSensor.name, mSensor.handle); |
| } |
| |
| const sensors_event_t& DynamicSensorManager::ConnectionReport:: |
| generateConnectionEvent(int metaHandle) { |
| if (!mGenerated) { |
| mEvent.sensor = metaHandle; |
| mEvent.type = SENSOR_TYPE_DYNAMIC_SENSOR_META; |
| mEvent.timestamp = elapsedRealtimeNano(); |
| mEvent.dynamic_sensor_meta = |
| (dynamic_sensor_meta_event_t) {true, mSensor.handle, &mSensor, {0}}; |
| memcpy(&mEvent.dynamic_sensor_meta.uuid, &mUuid, sizeof(mEvent.dynamic_sensor_meta.uuid)); |
| mGenerated = true; |
| } |
| return mEvent; |
| } |
| |
| void DynamicSensorManager::ConnectionReport:: |
| fillDisconnectionEvent(sensors_event_t* event, int metaHandle, int handle) { |
| memset(event, 0, sizeof(sensors_event_t)); |
| event->version = sizeof(sensors_event_t); |
| event->sensor = metaHandle; |
| event->type = SENSOR_TYPE_DYNAMIC_SENSOR_META; |
| event->timestamp = elapsedRealtimeNano(); |
| event->dynamic_sensor_meta.connected = false; |
| event->dynamic_sensor_meta.handle = handle; |
| } |
| |
| } // namespace SensorHalExt |
| } // namespace android |