/** * Copyright (c) 2021, 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. */ #define LOG_TAG "libsysfsmonitor" #define DEBUG false #include "SysfsMonitor.h" #include #include #include namespace { using ::android::base::Error; using ::android::base::Result; using ::android::base::StringPrintf; // The maximum number of sysfs files to monitor. constexpr int32_t EPOLL_MAX_EVENTS = 10; } // namespace namespace android { namespace automotive { Result SysfsMonitor::init(CallbackFunc callback) { if (mEpollFd >= 0) { return Error() << "Epoll instance was already created"; } if (mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC)); mEpollFd < 0) { return Error() << "Cannot create epoll instance: errno = " << errno; } mCallback = callback; return {}; } Result SysfsMonitor::release() { if (mEpollFd < 0) { return Error() << "Epoll instance wasn't created"; } for (const int32_t fd : mMonitoringFds) { if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, /*event=*/nullptr)) { ALOGW("Failed to deregister fd(%d) from epoll instance: errno = %d", fd, errno); } } mMonitoringFds.clear(); mEpollFd.reset(); mCallback = nullptr; return {}; } Result SysfsMonitor::registerFd(int32_t fd) { if (fd < 0) { return Error() << StringPrintf("fd(%d) is invalid", fd); } if (mMonitoringFds.count(fd) > 0) { return Error() << StringPrintf("fd(%d) is already being monitored", fd); } if (mMonitoringFds.size() == EPOLL_MAX_EVENTS) { return Error() << "Cannot monitor more than " << EPOLL_MAX_EVENTS << " sysfs files"; } struct epoll_event eventItem = {}; eventItem.events = EPOLLIN | EPOLLPRI | EPOLLET; eventItem.data.fd = fd; if (int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem); result != 0) { return Error() << StringPrintf("Failed to add fd(%d) to epoll instance: errno = %d", fd, errno); } mMonitoringFds.insert(fd); return {}; } Result SysfsMonitor::unregisterFd(int32_t fd) { if (fd < 0) { return Error() << StringPrintf("fd(%d) is invalid", fd); } if (mMonitoringFds.count(fd) == 0) { return Error() << StringPrintf("fd(%d) is not being monitored", fd); } // Even when epoll_ctl() fails, we proceed to handle the request. if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, /*event=*/nullptr)) { ALOGW("Failed to deregister fd(%d) from epoll instance: errno = %d", fd, errno); } mMonitoringFds.erase(fd); return {}; } Result SysfsMonitor::observe() { if (mEpollFd < 0) { return Error() << "Epoll instance is not initialized"; } struct epoll_event events[EPOLL_MAX_EVENTS]; while (true) { int pollResult = epoll_wait(mEpollFd, events, EPOLL_MAX_EVENTS, /*timeout=*/-1); if (pollResult < 0) { ALOGW("Polling sysfs failed, but continue polling: errno = %d", errno); continue; } std::vector fds; for (int i = 0; i < pollResult; i++) { int fd = events[i].data.fd; if (mMonitoringFds.count(fd) == 0) { continue; } if (events[i].events & EPOLLIN) { fds.push_back(fd); } else if (events[i].events & EPOLLERR) { ALOGW("An error occurred when polling fd(%d)", fd); } } if (mCallback && fds.size() > 0) { mCallback(fds); } } return {}; } } // namespace automotive } // namespace android