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