summaryrefslogtreecommitdiff
path: root/modules/sensors/dynamic_sensor/ConnectionDetector.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/sensors/dynamic_sensor/ConnectionDetector.cpp')
-rw-r--r--modules/sensors/dynamic_sensor/ConnectionDetector.cpp215
1 files changed, 215 insertions, 0 deletions
diff --git a/modules/sensors/dynamic_sensor/ConnectionDetector.cpp b/modules/sensors/dynamic_sensor/ConnectionDetector.cpp
new file mode 100644
index 00000000..60994930
--- /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