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