xref: /aosp_15_r20/system/teeui/libteeui/src/evdev.cpp (revision 20bfefbe1966c142a35ae1ab84a8af250b3fd403)
1*20bfefbeSAndroid Build Coastguard Worker /*
2*20bfefbeSAndroid Build Coastguard Worker  *
3*20bfefbeSAndroid Build Coastguard Worker  * Copyright 2018, The Android Open Source Project
4*20bfefbeSAndroid Build Coastguard Worker  *
5*20bfefbeSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
6*20bfefbeSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
7*20bfefbeSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
8*20bfefbeSAndroid Build Coastguard Worker  *
9*20bfefbeSAndroid Build Coastguard Worker  *     http://www.apache.org/licenses/LICENSE-2.0
10*20bfefbeSAndroid Build Coastguard Worker  *
11*20bfefbeSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
12*20bfefbeSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
13*20bfefbeSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*20bfefbeSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
15*20bfefbeSAndroid Build Coastguard Worker  * limitations under the License.
16*20bfefbeSAndroid Build Coastguard Worker  */
17*20bfefbeSAndroid Build Coastguard Worker 
18*20bfefbeSAndroid Build Coastguard Worker #include <secure_input/evdev.h>
19*20bfefbeSAndroid Build Coastguard Worker 
20*20bfefbeSAndroid Build Coastguard Worker #include <android-base/logging.h>
21*20bfefbeSAndroid Build Coastguard Worker #include <dirent.h>
22*20bfefbeSAndroid Build Coastguard Worker #include <fcntl.h>
23*20bfefbeSAndroid Build Coastguard Worker #include <linux/input.h>
24*20bfefbeSAndroid Build Coastguard Worker #include <poll.h>
25*20bfefbeSAndroid Build Coastguard Worker #include <signal.h>
26*20bfefbeSAndroid Build Coastguard Worker #include <sys/eventfd.h>
27*20bfefbeSAndroid Build Coastguard Worker #include <sys/ioctl.h>
28*20bfefbeSAndroid Build Coastguard Worker #include <sys/stat.h>
29*20bfefbeSAndroid Build Coastguard Worker #include <sys/types.h>
30*20bfefbeSAndroid Build Coastguard Worker #include <teeui/msg_formatting.h>
31*20bfefbeSAndroid Build Coastguard Worker #include <time.h>
32*20bfefbeSAndroid Build Coastguard Worker 
33*20bfefbeSAndroid Build Coastguard Worker #include <algorithm>
34*20bfefbeSAndroid Build Coastguard Worker #include <atomic>
35*20bfefbeSAndroid Build Coastguard Worker #include <chrono>
36*20bfefbeSAndroid Build Coastguard Worker #include <condition_variable>
37*20bfefbeSAndroid Build Coastguard Worker #include <list>
38*20bfefbeSAndroid Build Coastguard Worker #include <mutex>
39*20bfefbeSAndroid Build Coastguard Worker #include <string>
40*20bfefbeSAndroid Build Coastguard Worker #include <thread>
41*20bfefbeSAndroid Build Coastguard Worker #include <tuple>
42*20bfefbeSAndroid Build Coastguard Worker 
43*20bfefbeSAndroid Build Coastguard Worker namespace secure_input {
44*20bfefbeSAndroid Build Coastguard Worker 
timerOrder(const Timer & a,const Timer & b)45*20bfefbeSAndroid Build Coastguard Worker bool EventLoop::timerOrder(const Timer& a, const Timer& b) {
46*20bfefbeSAndroid Build Coastguard Worker     return a.next > b.next;
47*20bfefbeSAndroid Build Coastguard Worker }
48*20bfefbeSAndroid Build Coastguard Worker 
processNewTimers()49*20bfefbeSAndroid Build Coastguard Worker void EventLoop::processNewTimers() {
50*20bfefbeSAndroid Build Coastguard Worker     for (auto& timer : newTimers_) {
51*20bfefbeSAndroid Build Coastguard Worker         timers_.push_back(std::move(timer));
52*20bfefbeSAndroid Build Coastguard Worker         std::push_heap(timers_.begin(), timers_.end(), timerOrder);
53*20bfefbeSAndroid Build Coastguard Worker     }
54*20bfefbeSAndroid Build Coastguard Worker     newTimers_.clear();
55*20bfefbeSAndroid Build Coastguard Worker }
56*20bfefbeSAndroid Build Coastguard Worker 
runTimers()57*20bfefbeSAndroid Build Coastguard Worker int EventLoop::runTimers() {
58*20bfefbeSAndroid Build Coastguard Worker     using namespace std::chrono_literals;
59*20bfefbeSAndroid Build Coastguard Worker     auto now = std::chrono::steady_clock::now();
60*20bfefbeSAndroid Build Coastguard Worker     while (!timers_.empty() && timers_[0].next <= now) {
61*20bfefbeSAndroid Build Coastguard Worker         std::pop_heap(timers_.begin(), timers_.end(), timerOrder);
62*20bfefbeSAndroid Build Coastguard Worker         auto& current = *timers_.rbegin();
63*20bfefbeSAndroid Build Coastguard Worker         current.handleTimer();
64*20bfefbeSAndroid Build Coastguard Worker         if (!current.oneShot) {
65*20bfefbeSAndroid Build Coastguard Worker             auto diff = now - current.next;
66*20bfefbeSAndroid Build Coastguard Worker             current.next += ((diff / current.duration) + 1) * current.duration;
67*20bfefbeSAndroid Build Coastguard Worker             std::push_heap(timers_.begin(), timers_.end(), timerOrder);
68*20bfefbeSAndroid Build Coastguard Worker         } else {
69*20bfefbeSAndroid Build Coastguard Worker             timers_.pop_back();
70*20bfefbeSAndroid Build Coastguard Worker         }
71*20bfefbeSAndroid Build Coastguard Worker     }
72*20bfefbeSAndroid Build Coastguard Worker     if (timers_.empty()) return -1;
73*20bfefbeSAndroid Build Coastguard Worker     auto& next = *timers_.begin();
74*20bfefbeSAndroid Build Coastguard Worker     auto diff = next.next - now;
75*20bfefbeSAndroid Build Coastguard Worker     if (diff > 60s) {
76*20bfefbeSAndroid Build Coastguard Worker         return 60000;
77*20bfefbeSAndroid Build Coastguard Worker     } else {
78*20bfefbeSAndroid Build Coastguard Worker         return std::chrono::duration_cast<std::chrono::milliseconds>(diff).count();
79*20bfefbeSAndroid Build Coastguard Worker     }
80*20bfefbeSAndroid Build Coastguard Worker }
81*20bfefbeSAndroid Build Coastguard Worker 
processNewReceivers()82*20bfefbeSAndroid Build Coastguard Worker void EventLoop::processNewReceivers() {
83*20bfefbeSAndroid Build Coastguard Worker     for (auto& receiver : newReceivers_) {
84*20bfefbeSAndroid Build Coastguard Worker         receivers_.push_back(std::move(receiver));
85*20bfefbeSAndroid Build Coastguard Worker     }
86*20bfefbeSAndroid Build Coastguard Worker     newReceivers_.clear();
87*20bfefbeSAndroid Build Coastguard Worker }
88*20bfefbeSAndroid Build Coastguard Worker 
addEventReceiver(NonCopyableFunction<void (short)> handler,int eventFd,short flags)89*20bfefbeSAndroid Build Coastguard Worker void EventLoop::addEventReceiver(NonCopyableFunction<void(short)> handler, int eventFd,
90*20bfefbeSAndroid Build Coastguard Worker                                  short flags) {
91*20bfefbeSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock(mutex_);
92*20bfefbeSAndroid Build Coastguard Worker     newReceivers_.emplace_back(eventFd, flags, std::move(handler));
93*20bfefbeSAndroid Build Coastguard Worker     if (eventFd_ != -1) {
94*20bfefbeSAndroid Build Coastguard Worker         eventfd_write(eventFd_, 1);
95*20bfefbeSAndroid Build Coastguard Worker     }
96*20bfefbeSAndroid Build Coastguard Worker }
97*20bfefbeSAndroid Build Coastguard Worker 
addTimer(NonCopyableFunction<void ()> handler,std::chrono::steady_clock::duration duration,bool oneShot)98*20bfefbeSAndroid Build Coastguard Worker void EventLoop::addTimer(NonCopyableFunction<void()> handler,
99*20bfefbeSAndroid Build Coastguard Worker                          std::chrono::steady_clock::duration duration, bool oneShot) {
100*20bfefbeSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock(mutex_);
101*20bfefbeSAndroid Build Coastguard Worker     std::chrono::steady_clock::time_point next = std::chrono::steady_clock::now() + duration;
102*20bfefbeSAndroid Build Coastguard Worker     newTimers_.emplace_back(next, duration, std::move(handler), oneShot);
103*20bfefbeSAndroid Build Coastguard Worker     if (eventFd_ != -1) {
104*20bfefbeSAndroid Build Coastguard Worker         eventfd_write(eventFd_, 1);
105*20bfefbeSAndroid Build Coastguard Worker     }
106*20bfefbeSAndroid Build Coastguard Worker }
107*20bfefbeSAndroid Build Coastguard Worker 
start()108*20bfefbeSAndroid Build Coastguard Worker bool EventLoop::start() {
109*20bfefbeSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock(mutex_);
110*20bfefbeSAndroid Build Coastguard Worker     if (state_ != ThreadState::JOINED) return false;
111*20bfefbeSAndroid Build Coastguard Worker     eventFd_ = eventfd(0, EFD_CLOEXEC);
112*20bfefbeSAndroid Build Coastguard Worker     if (eventFd_ == -1) return false;
113*20bfefbeSAndroid Build Coastguard Worker     state_ = ThreadState::STARTING;
114*20bfefbeSAndroid Build Coastguard Worker 
115*20bfefbeSAndroid Build Coastguard Worker     thread_ = std::thread([this]() {
116*20bfefbeSAndroid Build Coastguard Worker         std::unique_lock<std::mutex> lock(mutex_);
117*20bfefbeSAndroid Build Coastguard Worker         state_ = ThreadState::RUNNING;
118*20bfefbeSAndroid Build Coastguard Worker         lock.unlock();
119*20bfefbeSAndroid Build Coastguard Worker         condVar_.notify_all();
120*20bfefbeSAndroid Build Coastguard Worker         lock.lock();
121*20bfefbeSAndroid Build Coastguard Worker         while (state_ == ThreadState::RUNNING) {
122*20bfefbeSAndroid Build Coastguard Worker             processNewTimers();
123*20bfefbeSAndroid Build Coastguard Worker             processNewReceivers();  // must be called while locked
124*20bfefbeSAndroid Build Coastguard Worker             lock.unlock();
125*20bfefbeSAndroid Build Coastguard Worker             std::vector<pollfd> fds(receivers_.size() + 1);
126*20bfefbeSAndroid Build Coastguard Worker             fds[0] = {eventFd_, POLLIN, 0};
127*20bfefbeSAndroid Build Coastguard Worker             unsigned i = 1;
128*20bfefbeSAndroid Build Coastguard Worker             for (auto& receiver : receivers_) {
129*20bfefbeSAndroid Build Coastguard Worker                 fds[i] = {receiver.eventFd, receiver.eventFlags, 0};
130*20bfefbeSAndroid Build Coastguard Worker                 ++i;
131*20bfefbeSAndroid Build Coastguard Worker             }
132*20bfefbeSAndroid Build Coastguard Worker             auto rc = poll(fds.data(), fds.size(), runTimers());
133*20bfefbeSAndroid Build Coastguard Worker             if (state_ != ThreadState::RUNNING) {
134*20bfefbeSAndroid Build Coastguard Worker                 lock.lock();
135*20bfefbeSAndroid Build Coastguard Worker                 break;
136*20bfefbeSAndroid Build Coastguard Worker             }
137*20bfefbeSAndroid Build Coastguard Worker             if (rc > 0) {
138*20bfefbeSAndroid Build Coastguard Worker                 // don't handle eventFd_ explicitly
139*20bfefbeSAndroid Build Coastguard Worker                 i = 1;
140*20bfefbeSAndroid Build Coastguard Worker                 for (auto& receiver : receivers_) {
141*20bfefbeSAndroid Build Coastguard Worker                     if (fds[i].revents & receiver.eventFlags) {
142*20bfefbeSAndroid Build Coastguard Worker                         receiver.handleEvent(fds[i].revents);
143*20bfefbeSAndroid Build Coastguard Worker                     }
144*20bfefbeSAndroid Build Coastguard Worker                     ++i;
145*20bfefbeSAndroid Build Coastguard Worker                 }
146*20bfefbeSAndroid Build Coastguard Worker             } else if (rc < 0) {
147*20bfefbeSAndroid Build Coastguard Worker                 LOG(ERROR) << __func__ << " poll failed with errno: " << strerror(errno);
148*20bfefbeSAndroid Build Coastguard Worker             }
149*20bfefbeSAndroid Build Coastguard Worker             lock.lock();
150*20bfefbeSAndroid Build Coastguard Worker         }
151*20bfefbeSAndroid Build Coastguard Worker         state_ = ThreadState::TERMINATING;
152*20bfefbeSAndroid Build Coastguard Worker         lock.unlock();
153*20bfefbeSAndroid Build Coastguard Worker         condVar_.notify_all();
154*20bfefbeSAndroid Build Coastguard Worker     });
155*20bfefbeSAndroid Build Coastguard Worker     condVar_.wait(lock, [this]() -> bool { return state_ != ThreadState::STARTING; });
156*20bfefbeSAndroid Build Coastguard Worker     return state_ == ThreadState::RUNNING;
157*20bfefbeSAndroid Build Coastguard Worker }
158*20bfefbeSAndroid Build Coastguard Worker 
stop()159*20bfefbeSAndroid Build Coastguard Worker void EventLoop::stop() {
160*20bfefbeSAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lock(mutex_);
161*20bfefbeSAndroid Build Coastguard Worker     if (state_ == ThreadState::JOINED) return;
162*20bfefbeSAndroid Build Coastguard Worker     if (state_ == ThreadState::RUNNING) {
163*20bfefbeSAndroid Build Coastguard Worker         state_ = ThreadState::STOP_REQUESTED;
164*20bfefbeSAndroid Build Coastguard Worker         eventfd_write(eventFd_, 1);
165*20bfefbeSAndroid Build Coastguard Worker     }
166*20bfefbeSAndroid Build Coastguard Worker     condVar_.wait(lock, [this]() -> bool { return state_ == ThreadState::TERMINATING; });
167*20bfefbeSAndroid Build Coastguard Worker     thread_.join();
168*20bfefbeSAndroid Build Coastguard Worker     close(eventFd_);
169*20bfefbeSAndroid Build Coastguard Worker     state_ = ThreadState::JOINED;
170*20bfefbeSAndroid Build Coastguard Worker     LOG(DEBUG) << "Done ending event polling";
171*20bfefbeSAndroid Build Coastguard Worker }
172*20bfefbeSAndroid Build Coastguard Worker 
~EventLoop()173*20bfefbeSAndroid Build Coastguard Worker EventLoop::~EventLoop() {
174*20bfefbeSAndroid Build Coastguard Worker     stop();
175*20bfefbeSAndroid Build Coastguard Worker }
176*20bfefbeSAndroid Build Coastguard Worker 
EventDev()177*20bfefbeSAndroid Build Coastguard Worker EventDev::EventDev() : fd_(-1), path_("") {}
EventDev(const std::string & path)178*20bfefbeSAndroid Build Coastguard Worker EventDev::EventDev(const std::string& path) : fd_(-1), path_(path) {}
EventDev(EventDev && other)179*20bfefbeSAndroid Build Coastguard Worker EventDev::EventDev(EventDev&& other) : fd_(other.fd_), path_(std::move(other.path_)) {
180*20bfefbeSAndroid Build Coastguard Worker     other.fd_ = -1;
181*20bfefbeSAndroid Build Coastguard Worker }
operator =(EventDev && other)182*20bfefbeSAndroid Build Coastguard Worker EventDev& EventDev::operator=(EventDev&& other) {
183*20bfefbeSAndroid Build Coastguard Worker     if (&other == this) return *this;
184*20bfefbeSAndroid Build Coastguard Worker     fd_ = other.fd_;
185*20bfefbeSAndroid Build Coastguard Worker     path_ = std::move(other.path_);
186*20bfefbeSAndroid Build Coastguard Worker     other.fd_ = -1;
187*20bfefbeSAndroid Build Coastguard Worker     return *this;
188*20bfefbeSAndroid Build Coastguard Worker }
grab()189*20bfefbeSAndroid Build Coastguard Worker bool EventDev::grab() {
190*20bfefbeSAndroid Build Coastguard Worker     if (fd_ >= 0) {
191*20bfefbeSAndroid Build Coastguard Worker         return true;
192*20bfefbeSAndroid Build Coastguard Worker     }
193*20bfefbeSAndroid Build Coastguard Worker     fd_ = TEMP_FAILURE_RETRY(open(path_.c_str(), O_RDWR | O_NONBLOCK));
194*20bfefbeSAndroid Build Coastguard Worker     if (fd_ < 0) {
195*20bfefbeSAndroid Build Coastguard Worker         LOG(ERROR) << "failed to open event device \"" << path_ << "\"";
196*20bfefbeSAndroid Build Coastguard Worker         return false;
197*20bfefbeSAndroid Build Coastguard Worker     }
198*20bfefbeSAndroid Build Coastguard Worker     int error = ioctl(fd_, EVIOCGRAB, 1);
199*20bfefbeSAndroid Build Coastguard Worker     if (error) {
200*20bfefbeSAndroid Build Coastguard Worker         LOG(ERROR) << "failed to grab event device " << path_ << " exclusively EVIOCGRAB returned "
201*20bfefbeSAndroid Build Coastguard Worker                    << error << " " << strerror(errno);
202*20bfefbeSAndroid Build Coastguard Worker         close(fd_);
203*20bfefbeSAndroid Build Coastguard Worker         fd_ = -1;
204*20bfefbeSAndroid Build Coastguard Worker         return false;
205*20bfefbeSAndroid Build Coastguard Worker     }
206*20bfefbeSAndroid Build Coastguard Worker     return true;
207*20bfefbeSAndroid Build Coastguard Worker }
208*20bfefbeSAndroid Build Coastguard Worker 
ungrab()209*20bfefbeSAndroid Build Coastguard Worker void EventDev::ungrab() {
210*20bfefbeSAndroid Build Coastguard Worker     if (fd_ < 0) {
211*20bfefbeSAndroid Build Coastguard Worker         return;
212*20bfefbeSAndroid Build Coastguard Worker     }
213*20bfefbeSAndroid Build Coastguard Worker     int error = ioctl(fd_, EVIOCGRAB, 0);
214*20bfefbeSAndroid Build Coastguard Worker     if (error) {
215*20bfefbeSAndroid Build Coastguard Worker         LOG(ERROR) << "failed to ungrab \"" << path_ << "\" EVIOCGRAB returned " << error;
216*20bfefbeSAndroid Build Coastguard Worker     }
217*20bfefbeSAndroid Build Coastguard Worker     close(fd_);
218*20bfefbeSAndroid Build Coastguard Worker     fd_ = -1;
219*20bfefbeSAndroid Build Coastguard Worker }
220*20bfefbeSAndroid Build Coastguard Worker 
readEvent() const221*20bfefbeSAndroid Build Coastguard Worker std::tuple<bool, input_event> EventDev::readEvent() const {
222*20bfefbeSAndroid Build Coastguard Worker     std::tuple<bool, input_event> result{false, {}};
223*20bfefbeSAndroid Build Coastguard Worker     ssize_t rc;
224*20bfefbeSAndroid Build Coastguard Worker     rc = TEMP_FAILURE_RETRY(read(fd_, &std::get<1>(result), sizeof std::get<1>(result)));
225*20bfefbeSAndroid Build Coastguard Worker     std::get<0>(result) = rc == sizeof std::get<1>(result);
226*20bfefbeSAndroid Build Coastguard Worker     return result;
227*20bfefbeSAndroid Build Coastguard Worker }
228*20bfefbeSAndroid Build Coastguard Worker 
fd() const229*20bfefbeSAndroid Build Coastguard Worker int EventDev::fd() const {
230*20bfefbeSAndroid Build Coastguard Worker     return fd_;
231*20bfefbeSAndroid Build Coastguard Worker }
232*20bfefbeSAndroid Build Coastguard Worker 
grabAllEvDevsAndRegisterCallbacks(EventLoop * eventloop,std::function<void (short,const EventDev &)> handler)233*20bfefbeSAndroid Build Coastguard Worker bool grabAllEvDevsAndRegisterCallbacks(EventLoop* eventloop,
234*20bfefbeSAndroid Build Coastguard Worker                                        std::function<void(short, const EventDev&)> handler) {
235*20bfefbeSAndroid Build Coastguard Worker     if (!eventloop) return false;
236*20bfefbeSAndroid Build Coastguard Worker     dirent** dirs = nullptr;
237*20bfefbeSAndroid Build Coastguard Worker     int n = scandir(
238*20bfefbeSAndroid Build Coastguard Worker         "/dev/input", &dirs,
239*20bfefbeSAndroid Build Coastguard Worker         [](const dirent* dir) -> int {
240*20bfefbeSAndroid Build Coastguard Worker             return (dir->d_type & DT_CHR) && !strncmp("event", dir->d_name, 5);
241*20bfefbeSAndroid Build Coastguard Worker         },
242*20bfefbeSAndroid Build Coastguard Worker         alphasort);
243*20bfefbeSAndroid Build Coastguard Worker     if (n < 0) {
244*20bfefbeSAndroid Build Coastguard Worker         LOG(WARNING) << "Unable to enumerate input devices " << strerror(errno);
245*20bfefbeSAndroid Build Coastguard Worker         return true;
246*20bfefbeSAndroid Build Coastguard Worker     }
247*20bfefbeSAndroid Build Coastguard Worker 
248*20bfefbeSAndroid Build Coastguard Worker     bool result = true;
249*20bfefbeSAndroid Build Coastguard Worker     for (int i = 0; i < n; ++i) {
250*20bfefbeSAndroid Build Coastguard Worker         EventDev evDev(std::string("/dev/input/") + dirs[i]->d_name);
251*20bfefbeSAndroid Build Coastguard Worker         result = result && evDev.grab();
252*20bfefbeSAndroid Build Coastguard Worker         int fd = evDev.fd();
253*20bfefbeSAndroid Build Coastguard Worker         eventloop->addEventReceiver(
254*20bfefbeSAndroid Build Coastguard Worker             [&, handler, evDev = std::move(evDev)](short flags) { handler(flags, evDev); }, fd,
255*20bfefbeSAndroid Build Coastguard Worker             POLLIN);
256*20bfefbeSAndroid Build Coastguard Worker         free(dirs[i]);
257*20bfefbeSAndroid Build Coastguard Worker     }
258*20bfefbeSAndroid Build Coastguard Worker     free(dirs);
259*20bfefbeSAndroid Build Coastguard Worker     // true if all devices where grabbed successfully
260*20bfefbeSAndroid Build Coastguard Worker     return result;
261*20bfefbeSAndroid Build Coastguard Worker }
262*20bfefbeSAndroid Build Coastguard Worker 
263*20bfefbeSAndroid Build Coastguard Worker }  // namespace secure_input
264