1 /**
2  * Copyright (c) 2021, 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 #define LOG_TAG "libsysfsmonitor"
18 #define DEBUG false
19 
20 #include "SysfsMonitor.h"
21 
22 #include <android-base/stringprintf.h>
23 #include <log/log.h>
24 
25 #include <sys/epoll.h>
26 
27 namespace {
28 
29 using ::android::base::Error;
30 using ::android::base::Result;
31 using ::android::base::StringPrintf;
32 
33 // The maximum number of sysfs files to monitor.
34 constexpr int32_t EPOLL_MAX_EVENTS = 10;
35 
36 }  // namespace
37 
38 namespace android {
39 namespace automotive {
40 
init(CallbackFunc callback)41 Result<void> SysfsMonitor::init(CallbackFunc callback) {
42     if (mEpollFd >= 0) {
43         return Error() << "Epoll instance was already created";
44     }
45     if (mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC)); mEpollFd < 0) {
46         return Error() << "Cannot create epoll instance: errno = " << errno;
47     }
48     mCallback = callback;
49 
50     pipe(mPipefd);
51     struct epoll_event eventItem = {};
52     eventItem.events = EPOLLIN;
53     eventItem.data.fd = mPipefd[0];
54     epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mPipefd[0], &eventItem);
55 
56     return {};
57 }
58 
release()59 Result<void> SysfsMonitor::release() {
60     if (mEpollFd < 0) {
61         return Error() << "Epoll instance wasn't created";
62     }
63     // kill the observe loop
64     if (mMonitoringThread.joinable()) {
65         int c = 'q';
66         write(mPipefd[1], &c, 1);
67         mMonitoringThread.join();
68     }
69     mMonitoringFds.clear();
70     mEpollFd.reset();
71     mCallback = nullptr;
72     close(mPipefd[0]);
73     close(mPipefd[1]);
74     return {};
75 }
76 
registerFd(int32_t fd)77 Result<void> SysfsMonitor::registerFd(int32_t fd) {
78     if (fd < 0) {
79         return Error() << StringPrintf("fd(%d) is invalid", fd);
80     }
81     if (mMonitoringFds.count(fd) > 0) {
82         return Error() << StringPrintf("fd(%d) is already being monitored", fd);
83     }
84     if (mMonitoringFds.size() == EPOLL_MAX_EVENTS) {
85         return Error() << "Cannot monitor more than " << EPOLL_MAX_EVENTS << " sysfs files";
86     }
87     struct epoll_event eventItem = {};
88     eventItem.events = EPOLLIN | EPOLLPRI | EPOLLET;
89     eventItem.data.fd = fd;
90     if (int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem); result != 0) {
91         return Error() << StringPrintf("Failed to add fd(%d) to epoll instance: errno = %d", fd,
92                                        errno);
93     }
94     mMonitoringFds.insert(fd);
95     return {};
96 }
97 
unregisterFd(int32_t fd)98 Result<void> SysfsMonitor::unregisterFd(int32_t fd) {
99     if (fd < 0) {
100         return Error() << StringPrintf("fd(%d) is invalid", fd);
101     }
102     if (mMonitoringFds.count(fd) == 0) {
103         return Error() << StringPrintf("fd(%d) is not being monitored", fd);
104     }
105     // Even when epoll_ctl() fails, we proceed to handle the request.
106     if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, /*event=*/nullptr)) {
107         ALOGW("Failed to deregister fd(%d) from epoll instance: errno = %d", fd, errno);
108     }
109     mMonitoringFds.erase(fd);
110     return {};
111 }
112 
observe()113 Result<void> SysfsMonitor::observe() {
114     if (mEpollFd < 0) {
115         return Error() << "Epoll instance is not initialized";
116     }
117 
118     mMonitoringThread = std::thread([this]() {
119         struct epoll_event events[EPOLL_MAX_EVENTS + 1];  // +1 for the pipe fd to quit this loop
120         while (true) {
121             int pollResult = epoll_wait(mEpollFd, events, EPOLL_MAX_EVENTS + 1, /*timeout=*/-1);
122             if (pollResult < 0) {
123                 ALOGW("Polling sysfs failed, but continue polling: errno = %d", errno);
124                 continue;
125             }
126             std::vector<int32_t> fds;
127             for (int i = 0; i < pollResult; i++) {
128                 int fd = events[i].data.fd;
129                 if (fd == mPipefd[0]) {
130                     return;
131                 }
132                 if (events[i].events & EPOLLIN) {
133                     fds.push_back(fd);
134                 } else if (events[i].events & EPOLLERR) {
135                     ALOGW("An error occurred when polling fd(%d)", fd);
136                 }
137             }
138             if (mCallback && fds.size() > 0) {
139                 mCallback(fds);
140             }
141         }
142     });
143     return {};
144 }
145 
146 }  // namespace automotive
147 }  // namespace android
148