1*0a9764feSAndroid Build Coastguard Worker /* 2*0a9764feSAndroid Build Coastguard Worker * Copyright (C) 2022 The Android Open Source Project 3*0a9764feSAndroid Build Coastguard Worker * 4*0a9764feSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*0a9764feSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*0a9764feSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*0a9764feSAndroid Build Coastguard Worker * 8*0a9764feSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*0a9764feSAndroid Build Coastguard Worker * 10*0a9764feSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*0a9764feSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*0a9764feSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*0a9764feSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*0a9764feSAndroid Build Coastguard Worker * limitations under the License. 15*0a9764feSAndroid Build Coastguard Worker */ 16*0a9764feSAndroid Build Coastguard Worker 17*0a9764feSAndroid Build Coastguard Worker #pragma once 18*0a9764feSAndroid Build Coastguard Worker 19*0a9764feSAndroid Build Coastguard Worker #include <linux/netlink.h> 20*0a9764feSAndroid Build Coastguard Worker #include <poll.h> 21*0a9764feSAndroid Build Coastguard Worker #include <sys/eventfd.h> 22*0a9764feSAndroid Build Coastguard Worker #include <sys/socket.h> 23*0a9764feSAndroid Build Coastguard Worker 24*0a9764feSAndroid Build Coastguard Worker #include <cerrno> 25*0a9764feSAndroid Build Coastguard Worker #include <memory> 26*0a9764feSAndroid Build Coastguard Worker #include <optional> 27*0a9764feSAndroid Build Coastguard Worker #include <string> 28*0a9764feSAndroid Build Coastguard Worker 29*0a9764feSAndroid Build Coastguard Worker #include "fd.h" 30*0a9764feSAndroid Build Coastguard Worker #include "log.h" 31*0a9764feSAndroid Build Coastguard Worker 32*0a9764feSAndroid Build Coastguard Worker namespace android { 33*0a9764feSAndroid Build Coastguard Worker 34*0a9764feSAndroid Build Coastguard Worker class UEvent { 35*0a9764feSAndroid Build Coastguard Worker public: 36*0a9764feSAndroid Build Coastguard Worker static auto CreateInstance() -> std::unique_ptr<UEvent> { 37*0a9764feSAndroid Build Coastguard Worker auto fd = MakeUniqueFd( 38*0a9764feSAndroid Build Coastguard Worker socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT)); 39*0a9764feSAndroid Build Coastguard Worker 40*0a9764feSAndroid Build Coastguard Worker if (!fd) { 41*0a9764feSAndroid Build Coastguard Worker ALOGE("Failed to open uevent socket: errno=%i", errno); 42*0a9764feSAndroid Build Coastguard Worker return {}; 43*0a9764feSAndroid Build Coastguard Worker } 44*0a9764feSAndroid Build Coastguard Worker 45*0a9764feSAndroid Build Coastguard Worker struct sockaddr_nl addr {}; 46*0a9764feSAndroid Build Coastguard Worker addr.nl_family = AF_NETLINK; 47*0a9764feSAndroid Build Coastguard Worker addr.nl_pid = 0; 48*0a9764feSAndroid Build Coastguard Worker addr.nl_groups = UINT32_MAX; 49*0a9764feSAndroid Build Coastguard Worker 50*0a9764feSAndroid Build Coastguard Worker // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) 51*0a9764feSAndroid Build Coastguard Worker const int ret = bind(*fd, (struct sockaddr *)&addr, sizeof(addr)); 52*0a9764feSAndroid Build Coastguard Worker if (ret != 0) { 53*0a9764feSAndroid Build Coastguard Worker ALOGE("Failed to bind uevent socket: errno=%i", errno); 54*0a9764feSAndroid Build Coastguard Worker return {}; 55*0a9764feSAndroid Build Coastguard Worker } 56*0a9764feSAndroid Build Coastguard Worker 57*0a9764feSAndroid Build Coastguard Worker auto stop_event_fd = MakeUniqueFd(eventfd(0, EFD_CLOEXEC)); 58*0a9764feSAndroid Build Coastguard Worker if (!stop_event_fd) { 59*0a9764feSAndroid Build Coastguard Worker ALOGE("Failed to create eventfd: errno=%i", errno); 60*0a9764feSAndroid Build Coastguard Worker return {}; 61*0a9764feSAndroid Build Coastguard Worker } 62*0a9764feSAndroid Build Coastguard Worker 63*0a9764feSAndroid Build Coastguard Worker return std::unique_ptr<UEvent>(new UEvent(fd, stop_event_fd)); 64*0a9764feSAndroid Build Coastguard Worker } 65*0a9764feSAndroid Build Coastguard Worker 66*0a9764feSAndroid Build Coastguard Worker auto ReadNext() -> std::optional<std::string> { 67*0a9764feSAndroid Build Coastguard Worker constexpr int kUEventBufferSize = 1024; 68*0a9764feSAndroid Build Coastguard Worker char buffer[kUEventBufferSize]; 69*0a9764feSAndroid Build Coastguard Worker 70*0a9764feSAndroid Build Coastguard Worker if (!WaitForData()) { 71*0a9764feSAndroid Build Coastguard Worker return {}; 72*0a9764feSAndroid Build Coastguard Worker } 73*0a9764feSAndroid Build Coastguard Worker 74*0a9764feSAndroid Build Coastguard Worker ssize_t ret = 0; 75*0a9764feSAndroid Build Coastguard Worker ret = read(*fd_, &buffer, sizeof(buffer)); 76*0a9764feSAndroid Build Coastguard Worker if (ret == 0) 77*0a9764feSAndroid Build Coastguard Worker return {}; 78*0a9764feSAndroid Build Coastguard Worker 79*0a9764feSAndroid Build Coastguard Worker if (ret < 0) { 80*0a9764feSAndroid Build Coastguard Worker ALOGE("Got error reading uevent %zd", ret); 81*0a9764feSAndroid Build Coastguard Worker return {}; 82*0a9764feSAndroid Build Coastguard Worker } 83*0a9764feSAndroid Build Coastguard Worker 84*0a9764feSAndroid Build Coastguard Worker for (int i = 0; i < ret - 1; i++) { 85*0a9764feSAndroid Build Coastguard Worker if (buffer[i] == '\0') { 86*0a9764feSAndroid Build Coastguard Worker buffer[i] = '\n'; 87*0a9764feSAndroid Build Coastguard Worker } 88*0a9764feSAndroid Build Coastguard Worker } 89*0a9764feSAndroid Build Coastguard Worker 90*0a9764feSAndroid Build Coastguard Worker return std::string(buffer); 91*0a9764feSAndroid Build Coastguard Worker } 92*0a9764feSAndroid Build Coastguard Worker Stop()93*0a9764feSAndroid Build Coastguard Worker void Stop() { 94*0a9764feSAndroid Build Coastguard Worker // Increment the eventfd by writing 1. All subsequent calls to ReadNext will 95*0a9764feSAndroid Build Coastguard Worker // return false. 96*0a9764feSAndroid Build Coastguard Worker const uint64_t value = 1; 97*0a9764feSAndroid Build Coastguard Worker const ssize_t ret = write(*stop_event_fd_, &value, sizeof(value)); 98*0a9764feSAndroid Build Coastguard Worker if (ret == -1) { 99*0a9764feSAndroid Build Coastguard Worker ALOGE("Error writing to eventfd. errno: %d", errno); 100*0a9764feSAndroid Build Coastguard Worker } else if (ret != sizeof(value)) { 101*0a9764feSAndroid Build Coastguard Worker ALOGE("Wrote fewer bytes to eventfd than expected: %zd vs %zd", ret, 102*0a9764feSAndroid Build Coastguard Worker sizeof(value)); 103*0a9764feSAndroid Build Coastguard Worker } 104*0a9764feSAndroid Build Coastguard Worker } 105*0a9764feSAndroid Build Coastguard Worker 106*0a9764feSAndroid Build Coastguard Worker private: 107*0a9764feSAndroid Build Coastguard Worker enum { kFdIdx = 0, kStopEventFdIdx, kNumFds }; 108*0a9764feSAndroid Build Coastguard Worker UEvent(UniqueFd & fd,UniqueFd & stop_event_fd)109*0a9764feSAndroid Build Coastguard Worker UEvent(UniqueFd &fd, UniqueFd &stop_event_fd) 110*0a9764feSAndroid Build Coastguard Worker : fd_(std::move(fd)), stop_event_fd_(std::move(stop_event_fd)) {}; 111*0a9764feSAndroid Build Coastguard Worker 112*0a9764feSAndroid Build Coastguard Worker // Returns true if there is data to be read off of fd_. WaitForData()113*0a9764feSAndroid Build Coastguard Worker bool WaitForData() { 114*0a9764feSAndroid Build Coastguard Worker struct pollfd poll_fds[kNumFds]; 115*0a9764feSAndroid Build Coastguard Worker poll_fds[kFdIdx].fd = *fd_; 116*0a9764feSAndroid Build Coastguard Worker poll_fds[kFdIdx].events = POLLIN; 117*0a9764feSAndroid Build Coastguard Worker poll_fds[kStopEventFdIdx].fd = *stop_event_fd_; 118*0a9764feSAndroid Build Coastguard Worker poll_fds[kStopEventFdIdx].events = POLLIN; 119*0a9764feSAndroid Build Coastguard Worker 120*0a9764feSAndroid Build Coastguard Worker const int ret = poll(poll_fds, kNumFds, -1); 121*0a9764feSAndroid Build Coastguard Worker if (ret == 0) { 122*0a9764feSAndroid Build Coastguard Worker // Timeout shouldn't happen, but return here anyways. 123*0a9764feSAndroid Build Coastguard Worker ALOGE("Timed out polling uevent."); 124*0a9764feSAndroid Build Coastguard Worker return false; 125*0a9764feSAndroid Build Coastguard Worker } 126*0a9764feSAndroid Build Coastguard Worker if (ret < 1) { 127*0a9764feSAndroid Build Coastguard Worker ALOGE("Error polling uevent. errno: %d", errno); 128*0a9764feSAndroid Build Coastguard Worker return false; 129*0a9764feSAndroid Build Coastguard Worker } 130*0a9764feSAndroid Build Coastguard Worker 131*0a9764feSAndroid Build Coastguard Worker if ((poll_fds[kStopEventFdIdx].revents & POLLIN) != 0) { 132*0a9764feSAndroid Build Coastguard Worker // Stop event has been signalled. Return without reading from the fd to 133*0a9764feSAndroid Build Coastguard Worker // ensure that this fd stays in a readable state. 134*0a9764feSAndroid Build Coastguard Worker ALOGI("Stop event signalled."); 135*0a9764feSAndroid Build Coastguard Worker return false; 136*0a9764feSAndroid Build Coastguard Worker } 137*0a9764feSAndroid Build Coastguard Worker 138*0a9764feSAndroid Build Coastguard Worker // Return true if there is data to read. 139*0a9764feSAndroid Build Coastguard Worker return (poll_fds[kFdIdx].revents & POLLIN) != 0; 140*0a9764feSAndroid Build Coastguard Worker } 141*0a9764feSAndroid Build Coastguard Worker 142*0a9764feSAndroid Build Coastguard Worker UniqueFd fd_; 143*0a9764feSAndroid Build Coastguard Worker UniqueFd stop_event_fd_; 144*0a9764feSAndroid Build Coastguard Worker }; 145*0a9764feSAndroid Build Coastguard Worker 146*0a9764feSAndroid Build Coastguard Worker } // namespace android 147