1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <log/log.h>
18 #include <sys/epoll.h>
19 #include "multihal_sensors.h"
20 
21 namespace goldfish {
22 
23 namespace {
epollCtlAdd(int epollFd,int fd)24 int epollCtlAdd(int epollFd, int fd) {
25     struct epoll_event ev;
26     ev.events  = EPOLLIN;
27     ev.data.fd = fd;
28     return TEMP_FAILURE_RETRY(epoll_ctl(epollFd, EPOLL_CTL_ADD, fd, &ev));
29 }
30 
qemuSensortThreadRcvCommand(const int fd)31 int qemuSensortThreadRcvCommand(const int fd) {
32     char buf;
33     if (TEMP_FAILURE_RETRY(read(fd, &buf, 1)) == 1) {
34         return buf;
35     } else {
36         return -1;
37     }
38 }
39 }  // namespace
40 
qemuSensorListenerThreadImpl(const int transportFd)41 bool MultihalSensors::qemuSensorListenerThreadImpl(const int transportFd) {
42     const unique_fd epollFd(epoll_create1(0));
43     LOG_ALWAYS_FATAL_IF(!epollFd.ok(), "%s:%d: epoll_create1 failed",
44                         __func__, __LINE__);
45 
46     epollCtlAdd(epollFd.get(), transportFd);
47     epollCtlAdd(epollFd.get(), m_sensorThreadFd.get());
48 
49     while (true) {
50         struct epoll_event events[2];
51         const int kTimeoutMs = 60000;
52         const int n = TEMP_FAILURE_RETRY(epoll_wait(epollFd.get(),
53                                                     events, 2,
54                                                     kTimeoutMs));
55         if (n < 0) {
56             ALOGW("%s:%d: epoll_wait failed with '%s'",
57                   __func__, __LINE__, strerror(errno));
58             return true;
59         }
60 
61         for (int i = 0; i < n; ++i) {
62             const struct epoll_event* ev = &events[i];
63             const int fd = ev->data.fd;
64             const int ev_events = ev->events;
65 
66             if (fd == transportFd) {
67                 if (ev_events & (EPOLLERR | EPOLLHUP)) {
68                     ALOGW("%s:%d: epoll_wait: transportFd has an error, "
69                           "ev_events=%x", __func__, __LINE__, ev_events);
70                     return true;
71                 } else if (ev_events & EPOLLIN) {
72                     std::unique_lock<std::mutex> lock(m_mtx);
73                     parseQemuSensorEventLocked(&m_protocolState);
74                 }
75             } else if (fd == m_sensorThreadFd.get()) {
76                 if (ev_events & (EPOLLERR | EPOLLHUP)) {
77                     LOG_ALWAYS_FATAL("%s:%d: epoll_wait: threadFd has an error, "
78                                      "ev_events=%x", __func__, __LINE__, ev_events);
79                 } else if (ev_events & EPOLLIN) {
80                     const int cmd = qemuSensortThreadRcvCommand(fd);
81                     switch (cmd) {
82                     case kCMD_QUIT: return false;
83                     case kCMD_RESTART: return true;
84                     default:
85                         ALOGW("%s:%d: qemuSensortThreadRcvCommand "
86                               "returned unexpected command, cmd=%d",
87                               __func__, __LINE__, cmd);
88                         return true;
89                     }
90                 }
91             } else {
92                 ALOGW("%s:%d: epoll_wait() returned unexpected fd",
93                       __func__, __LINE__);
94                 return true;
95             }
96         }
97     }
98 }
99 
100 }  // namespace goldfish
101