Dynamic sensor manager -- implementation of basic sensor daemon
Library to handle dynamic sensor connection. There are two way to use this: as hal extension or standalone hal module. In hal extension mode: add libdynamic_sensor_ext in dependency of hal, instantiate DynamicSensorManager with appropriate parameters. Then for all sensor requests, if the handle is owned by dynamic sensor manager, forward the request. In standalone mode, add sensor.dynamic_sensor_hal into device make file. Usually, this also means multihal is necessary. Add sensor.dynamic_sensor_hal into multihal configuration file. A dummy sensor module is included for testing. Test: tested with cts dynamics sensor related test and demo app. also verified sensor basic operation with sensor logger. Change-Id: I16612935fc21b06c173aca875401ece37c6bde01
This commit is contained in:
parent
3623fbace2
commit
18082bd61f
10 changed files with 627 additions and 3 deletions
10
CleanSpec.mk
10
CleanSpec.mk
|
@ -47,3 +47,13 @@
|
|||
# ************************************************
|
||||
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
|
||||
# ************************************************
|
||||
|
||||
$(call add-clean-step, rm -f $(PRODUCT_OUT)/system/lib/libdynamic_sensor_ext.so)
|
||||
$(call add-clean-step, rm -f $(PRODUCT_OUT)/system/lib64/libdynamic_sensor_ext.so)
|
||||
$(call add-clean-step, rm -f $(PRODUCT_OUT)/system/lib/hw/sensors.dynamic_sensor_hal.so)
|
||||
$(call add-clean-step, rm -f $(PRODUCT_OUT)/system/lib64/hw/sensors.dynamic_sensor_hal.so)
|
||||
|
||||
# ************************************************
|
||||
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
|
||||
# ************************************************
|
||||
|
||||
|
|
|
@ -33,11 +33,15 @@ include $(CLEAR_VARS)
|
|||
LOCAL_MODULE := libdynamic_sensor_ext
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE_OWNER := google
|
||||
LOCAL_PROPRIETARY_MODULE := true
|
||||
|
||||
LOCAL_CFLAGS += $(COMMON_CFLAGS) -DLOG_TAG=\"DynamicSensorExt\"
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
BaseDynamicSensorDaemon.cpp \
|
||||
BaseSensorObject.cpp \
|
||||
ConnectionDetector.cpp \
|
||||
DummyDynamicAccelDaemon.cpp \
|
||||
DynamicSensorManager.cpp \
|
||||
RingBuffer.cpp
|
||||
|
||||
|
@ -58,11 +62,15 @@ LOCAL_MODULE := sensors.dynamic_sensor_hal
|
|||
LOCAL_MODULE_RELATIVE_PATH := hw
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE_OWNER := google
|
||||
LOCAL_PROPRIETARY_MODULE := true
|
||||
|
||||
LOCAL_CFLAGS += $(COMMON_CFLAGS) -DLOG_TAG=\"DynamicSensorHal\"
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
BaseDynamicSensorDaemon.cpp \
|
||||
BaseSensorObject.cpp \
|
||||
ConnectionDetector.cpp \
|
||||
DummyDynamicAccelDaemon.cpp \
|
||||
DynamicSensorManager.cpp \
|
||||
RingBuffer.cpp \
|
||||
sensors.cpp
|
||||
|
@ -70,7 +78,7 @@ LOCAL_SRC_FILES := \
|
|||
LOCAL_SHARED_LIBRARIES := \
|
||||
libcutils \
|
||||
libutils \
|
||||
liblog \
|
||||
liblog
|
||||
|
||||
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
|
||||
|
||||
|
|
56
modules/sensors/dynamic_sensor/BaseDynamicSensorDaemon.cpp
Normal file
56
modules/sensors/dynamic_sensor/BaseDynamicSensorDaemon.cpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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 "DynamicSensorManager.h"
|
||||
#include "utils/Log.h"
|
||||
|
||||
namespace android {
|
||||
namespace SensorHalExt {
|
||||
|
||||
bool BaseDynamicSensorDaemon::onConnectionChange(const std::string &deviceKey, bool connected) {
|
||||
bool ret = false;
|
||||
auto i = mDevices.find(deviceKey);
|
||||
if (connected) {
|
||||
if (i == mDevices.end()) {
|
||||
ALOGV("device %s is connected", deviceKey.c_str());
|
||||
BaseSensorObject* s = createSensor(deviceKey);
|
||||
if (s) {
|
||||
mDevices.emplace(deviceKey, sp<BaseSensorObject>(s));
|
||||
mManager.registerSensor(s);
|
||||
ALOGV("device %s is registered", deviceKey.c_str());
|
||||
ret = true;
|
||||
}
|
||||
} else {
|
||||
ALOGD("device %s already added and is connected again, ignore", deviceKey.c_str());
|
||||
}
|
||||
} else {
|
||||
ALOGV("device %s is disconnected", deviceKey.c_str());
|
||||
if (i != mDevices.end()) {
|
||||
mManager.unregisterSensor(i->second.get());
|
||||
mDevices.erase(i);
|
||||
ALOGV("device %s is unregistered", deviceKey.c_str());
|
||||
ret = true;
|
||||
} else {
|
||||
ALOGD("device not found in registry");
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
} // namespace SensorHalExt
|
||||
} // namespace android
|
||||
|
|
@ -17,7 +17,11 @@
|
|||
#ifndef ANDROID_SENSORHAL_EXT_BASE_DYNAMIC_SENSOR_DAEMON_H
|
||||
#define ANDROID_SENSORHAL_EXT_BASE_DYNAMIC_SENSOR_DAEMON_H
|
||||
|
||||
#include "BaseSensorObject.h"
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace android {
|
||||
namespace SensorHalExt {
|
||||
|
@ -28,8 +32,13 @@ class BaseDynamicSensorDaemon : public RefBase {
|
|||
public:
|
||||
BaseDynamicSensorDaemon(DynamicSensorManager& manager) : mManager(manager) {}
|
||||
virtual ~BaseDynamicSensorDaemon() = default;
|
||||
|
||||
virtual bool onConnectionChange(const std::string &deviceKey, bool connected);
|
||||
protected:
|
||||
DynamicSensorManager& mManager;
|
||||
virtual BaseSensorObject * createSensor(const std::string &deviceKey) = 0;
|
||||
|
||||
DynamicSensorManager &mManager;
|
||||
std::unordered_map<std::string, sp<BaseSensorObject> > mDevices;
|
||||
};
|
||||
|
||||
} // namespace SensorHalExt
|
||||
|
|
215
modules/sensors/dynamic_sensor/ConnectionDetector.cpp
Normal file
215
modules/sensors/dynamic_sensor/ConnectionDetector.cpp
Normal file
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* 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 "ConnectionDetector.h"
|
||||
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace android {
|
||||
namespace SensorHalExt {
|
||||
|
||||
// SocketConnectionDetector functions
|
||||
SocketConnectionDetector::SocketConnectionDetector(BaseDynamicSensorDaemon *d, int port)
|
||||
: ConnectionDetector(d) {
|
||||
// initialize socket that accept connection to localhost:port
|
||||
mListenFd = ::socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (mListenFd < 0) {
|
||||
ALOGE("Cannot open socket");
|
||||
return;
|
||||
}
|
||||
|
||||
struct sockaddr_in serverAddress = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = htons(port),
|
||||
.sin_addr = {
|
||||
.s_addr = htonl(INADDR_LOOPBACK)
|
||||
}
|
||||
};
|
||||
|
||||
::bind(mListenFd, (struct sockaddr*)&serverAddress, sizeof(serverAddress));
|
||||
if (::listen(mListenFd, 0) != NO_ERROR) {
|
||||
ALOGE("Cannot listen to port %d", port);
|
||||
mListenFd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
std::ostringstream s;
|
||||
s << "socket:" << port;
|
||||
mDevice = s.str();
|
||||
|
||||
run("ddad_socket");
|
||||
}
|
||||
|
||||
SocketConnectionDetector::~SocketConnectionDetector() {
|
||||
if (mListenFd >= 0) {
|
||||
requestExitAndWait();
|
||||
}
|
||||
}
|
||||
|
||||
int SocketConnectionDetector::waitForConnection() {
|
||||
return ::accept(mListenFd, nullptr, nullptr);
|
||||
}
|
||||
|
||||
void SocketConnectionDetector::waitForDisconnection(int connFd) {
|
||||
char buffer[16];
|
||||
while (::read(connFd, buffer, sizeof(buffer)) > 0) {
|
||||
// discard data but response something to denote thread alive
|
||||
::write(connFd, ".", 1);
|
||||
}
|
||||
// read failure means disconnection
|
||||
::close(connFd);
|
||||
}
|
||||
|
||||
bool SocketConnectionDetector::threadLoop() {
|
||||
while (!Thread::exitPending()) {
|
||||
// block waiting for connection
|
||||
int connFd = waitForConnection();
|
||||
|
||||
if (connFd < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
ALOGV("Received connection, register dynamic accel sensor");
|
||||
mDaemon->onConnectionChange(mDevice, true);
|
||||
|
||||
waitForDisconnection(connFd);
|
||||
ALOGV("Connection break, unregister dynamic accel sensor");
|
||||
mDaemon->onConnectionChange(mDevice, false);
|
||||
}
|
||||
mDaemon->onConnectionChange(mDevice, false);
|
||||
ALOGD("SocketConnectionDetector thread exited");
|
||||
return false;
|
||||
}
|
||||
|
||||
// FileConnectionDetector functions
|
||||
FileConnectionDetector::FileConnectionDetector (
|
||||
BaseDynamicSensorDaemon *d, const std::string &path, const std::string ®ex)
|
||||
: ConnectionDetector(d), mPath(path), mRegex(regex) {
|
||||
mInotifyFd = ::inotify_init1(IN_NONBLOCK);
|
||||
if (mInotifyFd < 0) {
|
||||
ALOGE("Cannot init inotify");
|
||||
return;
|
||||
}
|
||||
|
||||
int wd = ::inotify_add_watch(mInotifyFd, path.c_str(), IN_CREATE | IN_DELETE | IN_MOVED_FROM);
|
||||
if (wd < 0) {
|
||||
::close(mInotifyFd);
|
||||
mInotifyFd = -1;
|
||||
ALOGE("Cannot setup watch on dir %s", path.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
mPollFd.fd = wd;
|
||||
mPollFd.events = POLLIN;
|
||||
|
||||
run("ddad_file");
|
||||
}
|
||||
|
||||
FileConnectionDetector::~FileConnectionDetector() {
|
||||
if (mInotifyFd) {
|
||||
requestExitAndWait();
|
||||
::close(mInotifyFd);
|
||||
}
|
||||
}
|
||||
|
||||
bool FileConnectionDetector::matches(const std::string &name) const {
|
||||
return std::regex_match(name, mRegex);
|
||||
}
|
||||
|
||||
std::string FileConnectionDetector::getFullName(const std::string name) const {
|
||||
return mPath + name;
|
||||
}
|
||||
|
||||
void FileConnectionDetector::processExistingFiles() const {
|
||||
auto dirp = ::opendir(mPath.c_str());
|
||||
struct dirent *dp;
|
||||
while ((dp = ::readdir(dirp)) != NULL) {
|
||||
const std::string name(dp->d_name);
|
||||
if (matches(name)) {
|
||||
mDaemon->onConnectionChange(getFullName(name), true /*connected*/);
|
||||
}
|
||||
}
|
||||
::closedir(dirp);
|
||||
}
|
||||
|
||||
bool FileConnectionDetector::threadLoop() {
|
||||
struct {
|
||||
struct inotify_event e;
|
||||
uint8_t padding[NAME_MAX + 1];
|
||||
} ev;
|
||||
|
||||
processExistingFiles();
|
||||
|
||||
while (!Thread::exitPending()) {
|
||||
int pollNum = ::poll(&mPollFd, 1, -1);
|
||||
if (pollNum == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
ALOGE("inotify poll error: %s", ::strerror(errno));
|
||||
}
|
||||
|
||||
if (pollNum > 0) {
|
||||
if (! (mPollFd.revents & POLLIN)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Inotify events are available */
|
||||
while (true) {
|
||||
/* Read some events. */
|
||||
ssize_t len = ::read(mInotifyFd, &ev, sizeof ev);
|
||||
if (len == -1 && errno != EAGAIN) {
|
||||
ALOGE("read error: %s", ::strerror(errno));
|
||||
requestExit();
|
||||
break;
|
||||
}
|
||||
|
||||
/* If the nonblocking read() found no events to read, then
|
||||
it returns -1 with errno set to EAGAIN. In that case,
|
||||
we exit the loop. */
|
||||
if (len <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (ev.e.len && !(ev.e.mask & IN_ISDIR)) {
|
||||
const std::string name(ev.e.name);
|
||||
ALOGV("device %s state changed", name.c_str());
|
||||
if (matches(name)) {
|
||||
if (ev.e.mask & IN_CREATE) {
|
||||
mDaemon->onConnectionChange(getFullName(name), true /* connected*/);
|
||||
}
|
||||
|
||||
if (ev.e.mask & IN_DELETE || ev.e.mask & IN_MOVED_FROM) {
|
||||
mDaemon->onConnectionChange(getFullName(name), false /* connected*/);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ALOGD("FileConnectionDetection thread exited");
|
||||
return false;
|
||||
}
|
||||
} // namespace SensorHalExt
|
||||
} // namespace android
|
81
modules/sensors/dynamic_sensor/ConnectionDetector.h
Normal file
81
modules/sensors/dynamic_sensor/ConnectionDetector.h
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_SENSORHAL_EXT_CONNECTION_DETECTOR_H
|
||||
#define ANDROID_SENSORHAL_EXT_CONNECTION_DETECTOR_H
|
||||
|
||||
#include "BaseDynamicSensorDaemon.h"
|
||||
#include <utils/Thread.h>
|
||||
|
||||
#include <regex>
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
namespace android {
|
||||
namespace SensorHalExt {
|
||||
|
||||
// Abstraction of connection detector: an entity that calls
|
||||
// BaseDynamicSensorDaemon::onConnectionChange() when necessary.
|
||||
class ConnectionDetector : virtual public RefBase {
|
||||
public:
|
||||
ConnectionDetector(BaseDynamicSensorDaemon *d) : mDaemon(d) { }
|
||||
virtual ~ConnectionDetector() = default;
|
||||
protected:
|
||||
BaseDynamicSensorDaemon* mDaemon;
|
||||
};
|
||||
|
||||
// Open a socket that listen to localhost:port and notify sensor daemon of connection and
|
||||
// disconnection event when socket is connected or disconnected, respectively. Only one concurrent
|
||||
// client is accepted.
|
||||
class SocketConnectionDetector : public ConnectionDetector, public Thread {
|
||||
public:
|
||||
SocketConnectionDetector(BaseDynamicSensorDaemon *d, int port);
|
||||
virtual ~SocketConnectionDetector();
|
||||
private:
|
||||
// implement virtual of Thread
|
||||
virtual bool threadLoop();
|
||||
int waitForConnection();
|
||||
static void waitForDisconnection(int connFd);
|
||||
|
||||
int mListenFd;
|
||||
std::string mDevice;
|
||||
};
|
||||
|
||||
// Detect file change under path and notify sensor daemon of connection and disconnection event when
|
||||
// file is created in or removed from the directory, respectively.
|
||||
class FileConnectionDetector : public ConnectionDetector, public Thread {
|
||||
public:
|
||||
FileConnectionDetector(
|
||||
BaseDynamicSensorDaemon *d, const std::string &path, const std::string ®ex);
|
||||
virtual ~FileConnectionDetector();
|
||||
private:
|
||||
// implement virtual of Thread
|
||||
virtual bool threadLoop();
|
||||
|
||||
bool matches(const std::string &name) const;
|
||||
void processExistingFiles() const;
|
||||
std::string getFullName(const std::string name) const;
|
||||
|
||||
std::string mPath;
|
||||
std::regex mRegex;
|
||||
int mInotifyFd;
|
||||
struct pollfd mPollFd;
|
||||
};
|
||||
|
||||
} // namespace SensorHalExt
|
||||
} // namespace android
|
||||
|
||||
#endif // ANDROID_SENSORHAL_EXT_DYNAMIC_SENSOR_DAEMON_H
|
171
modules/sensors/dynamic_sensor/DummyDynamicAccelDaemon.cpp
Normal file
171
modules/sensors/dynamic_sensor/DummyDynamicAccelDaemon.cpp
Normal file
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* 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 "BaseSensorObject.h"
|
||||
#include "ConnectionDetector.h"
|
||||
#include "DummyDynamicAccelDaemon.h"
|
||||
#include "DynamicSensorManager.h"
|
||||
|
||||
#include <cutils/properties.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/SystemClock.h>
|
||||
#include <utils/misc.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <algorithm> //std::max
|
||||
|
||||
#define SYSPROP_PREFIX "dynamic_sensor.dummy"
|
||||
#define FILE_NAME_BASE "dummy_accel_file"
|
||||
#define FILE_NAME_REGEX ("^" FILE_NAME_BASE "[0-9]$")
|
||||
|
||||
namespace android {
|
||||
namespace SensorHalExt {
|
||||
|
||||
DummyDynamicAccelDaemon::DummyDynamicAccelDaemon(DynamicSensorManager& manager)
|
||||
: BaseDynamicSensorDaemon(manager) {
|
||||
char property[PROPERTY_VALUE_MAX+1];
|
||||
|
||||
property_get(SYSPROP_PREFIX ".file", property, "");
|
||||
if (strcmp(property, "") != 0) {
|
||||
mFileDetector = new FileConnectionDetector(
|
||||
this, std::string(property), std::string(FILE_NAME_REGEX));
|
||||
}
|
||||
|
||||
property_get(SYSPROP_PREFIX ".socket", property, "");
|
||||
if (strcmp(property, "") != 0) {
|
||||
mSocketDetector = new SocketConnectionDetector(this, atoi(property));
|
||||
}
|
||||
}
|
||||
|
||||
BaseSensorObject * DummyDynamicAccelDaemon::createSensor(const std::string &deviceKey) {
|
||||
if (deviceKey.compare(0, 1, "/") == 0) {
|
||||
// file detector result, deviceKey is file absolute path
|
||||
size_t start = std::max(static_cast<size_t>(0),
|
||||
deviceKey.length() - (::strlen(FILE_NAME_BASE) + 1));
|
||||
return new DummySensor(deviceKey.substr(start));
|
||||
|
||||
} else if (deviceKey.compare(0, ::strlen("socket:"), "socket:") == 0) {
|
||||
return new DummySensor(deviceKey);
|
||||
} else {
|
||||
// unknown deviceKey
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
DummyDynamicAccelDaemon::DummySensor::DummySensor(const std::string &name) : mRunState(false) {
|
||||
mSensorName = "Dummy Accel - " + name;
|
||||
mSensor = (struct sensor_t) {
|
||||
mSensorName.c_str(),
|
||||
"DemoSense, Inc.",
|
||||
1, // version
|
||||
-1, // handle, dummy number here
|
||||
SENSOR_TYPE_ACCELEROMETER,
|
||||
9.8 * 8.0f, // maxRange
|
||||
9.8 * 8.0f / 32768.0f, // resolution
|
||||
0.5f, // power
|
||||
(int32_t)(1.0E6f / 50), // minDelay
|
||||
0, // fifoReservedEventCount
|
||||
0, // fifoMaxEventCount
|
||||
SENSOR_STRING_TYPE_ACCELEROMETER,
|
||||
"", // requiredPermission
|
||||
(long)(1.0E6f / 50), // maxDelay
|
||||
SENSOR_FLAG_CONTINUOUS_MODE,
|
||||
{ NULL, NULL }
|
||||
};
|
||||
mRunLock.lock();
|
||||
run("DummySensor");
|
||||
}
|
||||
|
||||
DummyDynamicAccelDaemon::DummySensor::~DummySensor() {
|
||||
requestExitAndWait();
|
||||
// unlock mRunLock so thread can be unblocked
|
||||
mRunLock.unlock();
|
||||
}
|
||||
|
||||
const sensor_t* DummyDynamicAccelDaemon::DummySensor::getSensor() const {
|
||||
return &mSensor;
|
||||
}
|
||||
|
||||
void DummyDynamicAccelDaemon::DummySensor::getUuid(uint8_t* uuid) const {
|
||||
// at maximum, there will be always one instance, so we can hardcode
|
||||
size_t hash = std::hash<std::string>()(mSensorName);
|
||||
memset(uuid, 'x', 16);
|
||||
memcpy(uuid, &hash, sizeof(hash));
|
||||
}
|
||||
|
||||
int DummyDynamicAccelDaemon::DummySensor::enable(bool enable) {
|
||||
std::lock_guard<std::mutex> lk(mLock);
|
||||
if (mRunState != enable) {
|
||||
if (enable) {
|
||||
mRunLock.unlock();
|
||||
} else {
|
||||
mRunLock.lock();
|
||||
}
|
||||
mRunState = enable;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DummyDynamicAccelDaemon::DummySensor::batch(nsecs_t, nsecs_t) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DummyDynamicAccelDaemon::DummySensor::waitUntilNextSample() {
|
||||
// block when disabled (mRunLock locked)
|
||||
mRunLock.lock();
|
||||
mRunLock.unlock();
|
||||
|
||||
if (!Thread::exitPending()) {
|
||||
// sleep 20 ms (50Hz)
|
||||
usleep(20000);
|
||||
}
|
||||
}
|
||||
|
||||
bool DummyDynamicAccelDaemon::DummySensor::threadLoop() {
|
||||
// designated intialization will leave the unspecified fields zeroed
|
||||
sensors_event_t event = {
|
||||
.version = sizeof(event),
|
||||
.sensor = -1,
|
||||
.type = SENSOR_TYPE_ACCELEROMETER,
|
||||
};
|
||||
|
||||
int64_t startTimeNs = elapsedRealtimeNano();
|
||||
|
||||
ALOGI("Dynamic Dummy Accel started for sensor %s", mSensorName.c_str());
|
||||
while (!Thread::exitPending()) {
|
||||
waitUntilNextSample();
|
||||
|
||||
if (Thread::exitPending()) {
|
||||
break;
|
||||
}
|
||||
int64_t nowTimeNs = elapsedRealtimeNano();
|
||||
float t = (nowTimeNs - startTimeNs) / 1e9f;
|
||||
|
||||
event.data[0] = 2 * ::sin(3 * M_PI * t);
|
||||
event.data[1] = 3 * ::cos(3 * M_PI * t);
|
||||
event.data[2] = 1.5 * ::sin(6 * M_PI * t);
|
||||
event.timestamp = nowTimeNs;
|
||||
generateEvent(event);
|
||||
}
|
||||
|
||||
ALOGI("Dynamic Dummy Accel thread ended for sensor %s", mSensorName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace SensorHalExt
|
||||
} // namespace android
|
||||
|
73
modules/sensors/dynamic_sensor/DummyDynamicAccelDaemon.h
Normal file
73
modules/sensors/dynamic_sensor/DummyDynamicAccelDaemon.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_SENSORHAL_EXT_DUMMY_DYNAMIC_ACCEL_DAEMON_H
|
||||
#define ANDROID_SENSORHAL_EXT_DUMMY_DYNAMIC_ACCEL_DAEMON_H
|
||||
|
||||
#include "BaseDynamicSensorDaemon.h"
|
||||
#include "BaseSensorObject.h"
|
||||
|
||||
#include <hardware/sensors.h>
|
||||
#include <utils/Thread.h>
|
||||
#include <mutex>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace android {
|
||||
namespace SensorHalExt {
|
||||
|
||||
class ConnectionDetector;
|
||||
|
||||
/**
|
||||
* This daemon simulates dynamic sensor connection without the need of actually connect peripheral
|
||||
* to Android. It is for debugging and testing. It can handle one concurrent connections at maximum.
|
||||
*/
|
||||
class DummyDynamicAccelDaemon : public BaseDynamicSensorDaemon {
|
||||
public:
|
||||
DummyDynamicAccelDaemon(DynamicSensorManager& manager);
|
||||
virtual ~DummyDynamicAccelDaemon() = default;
|
||||
private:
|
||||
class DummySensor : public BaseSensorObject, public Thread {
|
||||
public:
|
||||
DummySensor(const std::string &name);
|
||||
~DummySensor();
|
||||
virtual const sensor_t* getSensor() const;
|
||||
virtual void getUuid(uint8_t* uuid) const;
|
||||
virtual int enable(bool enable);
|
||||
virtual int batch(nsecs_t sample_period, nsecs_t batch_period);
|
||||
private:
|
||||
// implement Thread function
|
||||
virtual bool threadLoop() override;
|
||||
|
||||
void waitUntilNextSample();
|
||||
|
||||
sensor_t mSensor;
|
||||
std::string mSensorName;
|
||||
|
||||
std::mutex mLock;
|
||||
std::mutex mRunLock;
|
||||
bool mRunState;
|
||||
};
|
||||
// implement BaseDynamicSensorDaemon function
|
||||
BaseSensorObject * createSensor(const std::string &deviceKey) override;
|
||||
|
||||
sp<ConnectionDetector> mFileDetector;
|
||||
sp<ConnectionDetector> mSocketDetector;
|
||||
};
|
||||
} // namespace SensorHalExt
|
||||
} // namespace android
|
||||
|
||||
#endif // ANDROID_SENSORHAL_EXT_DYNAMIC_SENSOR_DAEMON_H
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "BaseDynamicSensorDaemon.h"
|
||||
#include "BaseSensorObject.h"
|
||||
#include "DummyDynamicAccelDaemon.h"
|
||||
#include "DynamicSensorManager.h"
|
||||
|
||||
#include <utils/Log.h>
|
||||
|
@ -29,6 +30,7 @@ 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));
|
||||
return m;
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,6 @@ private:
|
|||
|
||||
static int FlushWrapper(struct sensors_poll_device_1 *dev, int handle);
|
||||
|
||||
// default ~16 million handles for dynamic sensor use, can be overriden by system property
|
||||
static constexpr int32_t kDynamicHandleBase = 0x10000;
|
||||
static constexpr int32_t kDynamicHandleEnd = 0x1000000;
|
||||
static constexpr int32_t kMaxDynamicHandleCount = kDynamicHandleEnd - kDynamicHandleBase;
|
||||
|
|
Loading…
Reference in a new issue