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 return {};
50 }
51
release()52 Result<void> SysfsMonitor::release() {
53 if (mEpollFd < 0) {
54 return Error() << "Epoll instance wasn't created";
55 }
56 for (const int32_t fd : mMonitoringFds) {
57 if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, /*event=*/nullptr)) {
58 ALOGW("Failed to deregister fd(%d) from epoll instance: errno = %d", fd, errno);
59 }
60 }
61 mMonitoringFds.clear();
62 mEpollFd.reset();
63 mCallback = nullptr;
64 return {};
65 }
66
registerFd(int32_t fd)67 Result<void> SysfsMonitor::registerFd(int32_t fd) {
68 if (fd < 0) {
69 return Error() << StringPrintf("fd(%d) is invalid", fd);
70 }
71 if (mMonitoringFds.count(fd) > 0) {
72 return Error() << StringPrintf("fd(%d) is already being monitored", fd);
73 }
74 if (mMonitoringFds.size() == EPOLL_MAX_EVENTS) {
75 return Error() << "Cannot monitor more than " << EPOLL_MAX_EVENTS << " sysfs files";
76 }
77 struct epoll_event eventItem = {};
78 eventItem.events = EPOLLIN | EPOLLPRI | EPOLLET;
79 eventItem.data.fd = fd;
80 if (int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem); result != 0) {
81 return Error() << StringPrintf("Failed to add fd(%d) to epoll instance: errno = %d", fd,
82 errno);
83 }
84 mMonitoringFds.insert(fd);
85 return {};
86 }
87
unregisterFd(int32_t fd)88 Result<void> SysfsMonitor::unregisterFd(int32_t fd) {
89 if (fd < 0) {
90 return Error() << StringPrintf("fd(%d) is invalid", fd);
91 }
92 if (mMonitoringFds.count(fd) == 0) {
93 return Error() << StringPrintf("fd(%d) is not being monitored", fd);
94 }
95 // Even when epoll_ctl() fails, we proceed to handle the request.
96 if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, /*event=*/nullptr)) {
97 ALOGW("Failed to deregister fd(%d) from epoll instance: errno = %d", fd, errno);
98 }
99 mMonitoringFds.erase(fd);
100 return {};
101 }
102
observe()103 Result<void> SysfsMonitor::observe() {
104 if (mEpollFd < 0) {
105 return Error() << "Epoll instance is not initialized";
106 }
107
108 struct epoll_event events[EPOLL_MAX_EVENTS];
109 while (true) {
110 int pollResult = epoll_wait(mEpollFd, events, EPOLL_MAX_EVENTS, /*timeout=*/-1);
111 if (pollResult < 0) {
112 ALOGW("Polling sysfs failed, but continue polling: errno = %d", errno);
113 continue;
114 }
115 std::vector<int32_t> fds;
116 for (int i = 0; i < pollResult; i++) {
117 int fd = events[i].data.fd;
118 if (mMonitoringFds.count(fd) == 0) {
119 continue;
120 }
121 if (events[i].events & EPOLLIN) {
122 fds.push_back(fd);
123 } else if (events[i].events & EPOLLERR) {
124 ALOGW("An error occurred when polling fd(%d)", fd);
125 }
126 }
127 if (mCallback && fds.size() > 0) {
128 mCallback(fds);
129 }
130 }
131 return {};
132 }
133
134 } // namespace automotive
135 } // namespace android
136