Merge "consumerir.default: remove unneeded dependency." into oc-dev
diff --git a/CleanSpec.mk b/CleanSpec.mk
index b84e1b6..1c64bfc 100644
--- a/CleanSpec.mk
+++ b/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
+# ************************************************
+
diff --git a/modules/sensors/dynamic_sensor/Android.mk b/modules/sensors/dynamic_sensor/Android.mk
index 07bc5e8..38a658a 100644
--- a/modules/sensors/dynamic_sensor/Android.mk
+++ b/modules/sensors/dynamic_sensor/Android.mk
@@ -33,11 +33,15 @@
 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_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_SHARED_LIBRARIES := \
     libcutils \
     libutils \
-    liblog \
+    liblog
 
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
 
diff --git a/modules/sensors/dynamic_sensor/BaseDynamicSensorDaemon.cpp b/modules/sensors/dynamic_sensor/BaseDynamicSensorDaemon.cpp
new file mode 100644
index 0000000..f5f642c
--- /dev/null
+++ b/modules/sensors/dynamic_sensor/BaseDynamicSensorDaemon.cpp
@@ -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
+
diff --git a/modules/sensors/dynamic_sensor/BaseDynamicSensorDaemon.h b/modules/sensors/dynamic_sensor/BaseDynamicSensorDaemon.h
index 29cf7a4..b698b7d 100644
--- a/modules/sensors/dynamic_sensor/BaseDynamicSensorDaemon.h
+++ b/modules/sensors/dynamic_sensor/BaseDynamicSensorDaemon.h
@@ -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 @@
 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
diff --git a/modules/sensors/dynamic_sensor/ConnectionDetector.cpp b/modules/sensors/dynamic_sensor/ConnectionDetector.cpp
new file mode 100644
index 0000000..6099493
--- /dev/null
+++ b/modules/sensors/dynamic_sensor/ConnectionDetector.cpp
@@ -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 &regex)
+            : 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
diff --git a/modules/sensors/dynamic_sensor/ConnectionDetector.h b/modules/sensors/dynamic_sensor/ConnectionDetector.h
new file mode 100644
index 0000000..712d832
--- /dev/null
+++ b/modules/sensors/dynamic_sensor/ConnectionDetector.h
@@ -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 &regex);
+    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
diff --git a/modules/sensors/dynamic_sensor/DummyDynamicAccelDaemon.cpp b/modules/sensors/dynamic_sensor/DummyDynamicAccelDaemon.cpp
new file mode 100644
index 0000000..1977967
--- /dev/null
+++ b/modules/sensors/dynamic_sensor/DummyDynamicAccelDaemon.cpp
@@ -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
+
diff --git a/modules/sensors/dynamic_sensor/DummyDynamicAccelDaemon.h b/modules/sensors/dynamic_sensor/DummyDynamicAccelDaemon.h
new file mode 100644
index 0000000..0bffbee
--- /dev/null
+++ b/modules/sensors/dynamic_sensor/DummyDynamicAccelDaemon.h
@@ -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
+
diff --git a/modules/sensors/dynamic_sensor/DynamicSensorManager.cpp b/modules/sensors/dynamic_sensor/DynamicSensorManager.cpp
index d33650c..eb4903d 100644
--- a/modules/sensors/dynamic_sensor/DynamicSensorManager.cpp
+++ b/modules/sensors/dynamic_sensor/DynamicSensorManager.cpp
@@ -16,6 +16,7 @@
 
 #include "BaseDynamicSensorDaemon.h"
 #include "BaseSensorObject.h"
+#include "DummyDynamicAccelDaemon.h"
 #include "DynamicSensorManager.h"
 
 #include <utils/Log.h>
@@ -29,6 +30,7 @@
 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;
 }
 
diff --git a/modules/sensors/dynamic_sensor/sensors.h b/modules/sensors/dynamic_sensor/sensors.h
index be42b67..2fd8708 100644
--- a/modules/sensors/dynamic_sensor/sensors.h
+++ b/modules/sensors/dynamic_sensor/sensors.h
@@ -75,7 +75,6 @@
 
     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;