1 /* 2 * Copyright (C) 2022 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 #pragma once 18 19 #include <linux/netlink.h> 20 #include <poll.h> 21 #include <sys/eventfd.h> 22 #include <sys/socket.h> 23 24 #include <cerrno> 25 #include <memory> 26 #include <optional> 27 #include <string> 28 29 #include "fd.h" 30 #include "log.h" 31 32 namespace android { 33 34 class UEvent { 35 public: 36 static auto CreateInstance() -> std::unique_ptr<UEvent> { 37 auto fd = MakeUniqueFd( 38 socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT)); 39 40 if (!fd) { 41 ALOGE("Failed to open uevent socket: errno=%i", errno); 42 return {}; 43 } 44 45 struct sockaddr_nl addr {}; 46 addr.nl_family = AF_NETLINK; 47 addr.nl_pid = 0; 48 addr.nl_groups = UINT32_MAX; 49 50 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) 51 const int ret = bind(*fd, (struct sockaddr *)&addr, sizeof(addr)); 52 if (ret != 0) { 53 ALOGE("Failed to bind uevent socket: errno=%i", errno); 54 return {}; 55 } 56 57 auto stop_event_fd = MakeUniqueFd(eventfd(0, EFD_CLOEXEC)); 58 if (!stop_event_fd) { 59 ALOGE("Failed to create eventfd: errno=%i", errno); 60 return {}; 61 } 62 63 return std::unique_ptr<UEvent>(new UEvent(fd, stop_event_fd)); 64 } 65 66 auto ReadNext() -> std::optional<std::string> { 67 constexpr int kUEventBufferSize = 1024; 68 char buffer[kUEventBufferSize]; 69 70 if (!WaitForData()) { 71 return {}; 72 } 73 74 ssize_t ret = 0; 75 ret = read(*fd_, &buffer, sizeof(buffer)); 76 if (ret == 0) 77 return {}; 78 79 if (ret < 0) { 80 ALOGE("Got error reading uevent %zd", ret); 81 return {}; 82 } 83 84 for (int i = 0; i < ret - 1; i++) { 85 if (buffer[i] == '\0') { 86 buffer[i] = '\n'; 87 } 88 } 89 90 return std::string(buffer); 91 } 92 Stop()93 void Stop() { 94 // Increment the eventfd by writing 1. All subsequent calls to ReadNext will 95 // return false. 96 const uint64_t value = 1; 97 const ssize_t ret = write(*stop_event_fd_, &value, sizeof(value)); 98 if (ret == -1) { 99 ALOGE("Error writing to eventfd. errno: %d", errno); 100 } else if (ret != sizeof(value)) { 101 ALOGE("Wrote fewer bytes to eventfd than expected: %zd vs %zd", ret, 102 sizeof(value)); 103 } 104 } 105 106 private: 107 enum { kFdIdx = 0, kStopEventFdIdx, kNumFds }; 108 UEvent(UniqueFd & fd,UniqueFd & stop_event_fd)109 UEvent(UniqueFd &fd, UniqueFd &stop_event_fd) 110 : fd_(std::move(fd)), stop_event_fd_(std::move(stop_event_fd)) {}; 111 112 // Returns true if there is data to be read off of fd_. WaitForData()113 bool WaitForData() { 114 struct pollfd poll_fds[kNumFds]; 115 poll_fds[kFdIdx].fd = *fd_; 116 poll_fds[kFdIdx].events = POLLIN; 117 poll_fds[kStopEventFdIdx].fd = *stop_event_fd_; 118 poll_fds[kStopEventFdIdx].events = POLLIN; 119 120 const int ret = poll(poll_fds, kNumFds, -1); 121 if (ret == 0) { 122 // Timeout shouldn't happen, but return here anyways. 123 ALOGE("Timed out polling uevent."); 124 return false; 125 } 126 if (ret < 1) { 127 ALOGE("Error polling uevent. errno: %d", errno); 128 return false; 129 } 130 131 if ((poll_fds[kStopEventFdIdx].revents & POLLIN) != 0) { 132 // Stop event has been signalled. Return without reading from the fd to 133 // ensure that this fd stays in a readable state. 134 ALOGI("Stop event signalled."); 135 return false; 136 } 137 138 // Return true if there is data to read. 139 return (poll_fds[kFdIdx].revents & POLLIN) != 0; 140 } 141 142 UniqueFd fd_; 143 UniqueFd stop_event_fd_; 144 }; 145 146 } // namespace android 147