blob: 10c56e31120c69d06b8cb1aba0783af9a92d3d55 [file] [log] [blame]
Colin Crossa8666952010-04-13 19:20:44 -07001/*
2 * Copyright (C) 2010 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
Tom Cherry81f5d3e2017-06-22 12:53:17 -070017#include "keychords.h"
18
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070019#include <dirent.h>
Colin Crossa8666952010-04-13 19:20:44 -070020#include <fcntl.h>
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070021#include <linux/input.h>
22#include <sys/cdefs.h>
Mark Salyzyn44692de2018-05-02 11:22:15 -070023#include <sys/inotify.h>
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070024#include <sys/ioctl.h>
Colin Crossa8666952010-04-13 19:20:44 -070025#include <sys/types.h>
Olivier Baillyb93e5812010-11-17 11:47:23 -080026#include <unistd.h>
Colin Crossa8666952010-04-13 19:20:44 -070027
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070028#include <algorithm>
29#include <functional>
Mark Salyzyn44692de2018-05-02 11:22:15 -070030#include <map>
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070031#include <memory>
32#include <string>
33#include <vector>
34
Tom Cherry3f5eaae52017-04-06 16:30:22 -070035#include <android-base/logging.h>
Tom Cherryccf23532017-03-28 16:40:41 -070036#include <android-base/properties.h>
37
Colin Crossa8666952010-04-13 19:20:44 -070038#include "init.h"
Tom Cherry81f5d3e2017-06-22 12:53:17 -070039
40namespace android {
41namespace init {
Colin Crossa8666952010-04-13 19:20:44 -070042
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070043namespace {
Colin Crossa8666952010-04-13 19:20:44 -070044
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070045int keychords_count;
Colin Crossa8666952010-04-13 19:20:44 -070046
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070047struct KeychordEntry {
48 const std::vector<int> keycodes;
49 bool notified;
50 int id;
51
52 KeychordEntry(const std::vector<int>& keycodes, int id)
53 : keycodes(keycodes), notified(false), id(id) {}
54};
55
56std::vector<KeychordEntry> keychord_entries;
57
58// Bit management
59class KeychordMask {
60 private:
61 typedef unsigned int mask_t;
62 std::vector<mask_t> bits;
63 static constexpr size_t bits_per_byte = 8;
64
65 public:
66 explicit KeychordMask(size_t bit = 0) : bits((bit + sizeof(mask_t) - 1) / sizeof(mask_t), 0) {}
67
68 void SetBit(size_t bit, bool value = true) {
69 auto idx = bit / (bits_per_byte * sizeof(mask_t));
70 if (idx >= bits.size()) return;
71 if (value) {
72 bits[idx] |= mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t)));
73 } else {
74 bits[idx] &= ~(mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t))));
Colin Crossa8666952010-04-13 19:20:44 -070075 }
Colin Crossf7ca6042011-01-04 18:18:45 -080076 }
77
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070078 bool GetBit(size_t bit) const {
79 auto idx = bit / (bits_per_byte * sizeof(mask_t));
80 return bits[idx] & (mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t))));
81 }
82
83 size_t bytesize() const { return bits.size() * sizeof(mask_t); }
84 void* data() { return bits.data(); }
85 size_t size() const { return bits.size() * sizeof(mask_t) * bits_per_byte; }
86 void resize(size_t bit) {
87 auto idx = bit / (bits_per_byte * sizeof(mask_t));
88 if (idx >= bits.size()) {
89 bits.resize(idx + 1, 0);
90 }
91 }
92
93 operator bool() const {
94 for (size_t i = 0; i < bits.size(); ++i) {
95 if (bits[i]) return true;
96 }
97 return false;
98 }
99
100 KeychordMask operator&(const KeychordMask& rval) const {
101 auto len = std::min(bits.size(), rval.bits.size());
102 KeychordMask ret;
103 ret.bits.resize(len);
104 for (size_t i = 0; i < len; ++i) {
105 ret.bits[i] = bits[i] & rval.bits[i];
106 }
107 return ret;
108 }
109
110 void operator|=(const KeychordMask& rval) {
111 size_t len = rval.bits.size();
112 bits.resize(len);
113 for (size_t i = 0; i < len; ++i) {
114 bits[i] |= rval.bits[i];
115 }
116 }
117};
118
119KeychordMask keychord_current;
120
121constexpr char kDevicePath[] = "/dev/input";
122
Mark Salyzyn44692de2018-05-02 11:22:15 -0700123std::map<std::string, int> keychord_registration;
124
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700125void HandleKeychord(int id) {
Yabin Cui74edcea2015-07-24 10:11:05 -0700126 // Only handle keychords if adb is enabled.
Tom Cherryccf23532017-03-28 16:40:41 -0700127 std::string adb_enabled = android::base::GetProperty("init.svc.adbd", "");
Yabin Cui74edcea2015-07-24 10:11:05 -0700128 if (adb_enabled == "running") {
Tom Cherry911b9b12017-07-27 16:20:58 -0700129 Service* svc = ServiceList::GetInstance().FindService(id, &Service::keychord_id);
Colin Crossa8666952010-04-13 19:20:44 -0700130 if (svc) {
Tom Cherry702ca9a2017-08-25 10:36:52 -0700131 LOG(INFO) << "Starting service '" << svc->name() << "' from keychord " << id;
132 if (auto result = svc->Start(); !result) {
133 LOG(ERROR) << "Could not start service '" << svc->name() << "' from keychord " << id
134 << ": " << result.error();
135 }
Colin Crossa8666952010-04-13 19:20:44 -0700136 } else {
Felipe Leme704fe2d2016-07-29 08:34:39 -0700137 LOG(ERROR) << "Service for keychord " << id << " not found";
Colin Crossa8666952010-04-13 19:20:44 -0700138 }
Felipe Lemec64c9822016-07-28 13:26:07 -0700139 } else {
Felipe Leme704fe2d2016-07-29 08:34:39 -0700140 LOG(WARNING) << "Not starting service for keychord " << id << " because ADB is disabled";
Colin Crossa8666952010-04-13 19:20:44 -0700141 }
142}
143
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700144void KeychordLambdaCheck() {
145 for (auto& e : keychord_entries) {
146 bool found = true;
147 for (auto& code : e.keycodes) {
148 if (!keychord_current.GetBit(code)) {
149 e.notified = false;
150 found = false;
151 break;
152 }
153 }
154 if (!found) continue;
155 if (e.notified) continue;
156 e.notified = true;
157 HandleKeychord(e.id);
158 }
159}
160
161void KeychordLambdaHandler(int fd) {
162 input_event event;
163 auto res = TEMP_FAILURE_RETRY(::read(fd, &event, sizeof(event)));
164 if ((res != sizeof(event)) || (event.type != EV_KEY)) return;
165 keychord_current.SetBit(event.code, event.value);
166 KeychordLambdaCheck();
167}
168
169bool KeychordGeteventEnable(int fd) {
170 static bool EviocsmaskSupported = true;
171
172 // Make sure it is an event channel, should pass this ioctl call
173 int version;
174 if (::ioctl(fd, EVIOCGVERSION, &version)) return false;
175
176 if (EviocsmaskSupported) {
177 KeychordMask mask(EV_KEY);
178 mask.SetBit(EV_KEY);
179 input_mask msg = {};
180 msg.type = EV_SYN;
181 msg.codes_size = mask.bytesize();
182 msg.codes_ptr = reinterpret_cast<uintptr_t>(mask.data());
183 if (::ioctl(fd, EVIOCSMASK, &msg) == -1) {
184 PLOG(WARNING) << "EVIOCSMASK not supported";
185 EviocsmaskSupported = false;
186 }
187 }
188
189 KeychordMask mask;
190 for (auto& e : keychord_entries) {
191 for (auto& code : e.keycodes) {
192 mask.resize(code);
193 mask.SetBit(code);
194 }
195 }
196
197 keychord_current.resize(mask.size());
198 KeychordMask available(mask.size());
199 auto res = ::ioctl(fd, EVIOCGBIT(EV_KEY, available.bytesize()), available.data());
200 if (res == -1) return false;
201 if (!(available & mask)) return false;
202
203 if (EviocsmaskSupported) {
204 input_mask msg = {};
205 msg.type = EV_KEY;
206 msg.codes_size = mask.bytesize();
207 msg.codes_ptr = reinterpret_cast<uintptr_t>(mask.data());
208 ::ioctl(fd, EVIOCSMASK, &msg);
209 }
210
211 KeychordMask set(mask.size());
212 res = ::ioctl(fd, EVIOCGKEY(res), set.data());
213 if (res > 0) {
214 keychord_current |= mask & available & set;
215 KeychordLambdaCheck();
216 }
217 register_epoll_handler(fd, [fd]() { KeychordLambdaHandler(fd); });
218 return true;
219}
220
221void GeteventOpenDevice(const std::string& device) {
Mark Salyzyn44692de2018-05-02 11:22:15 -0700222 if (keychord_registration.count(device)) return;
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700223 auto fd = TEMP_FAILURE_RETRY(::open(device.c_str(), O_RDWR | O_CLOEXEC));
224 if (fd == -1) {
225 PLOG(ERROR) << "Can not open " << device;
226 return;
227 }
228 if (!KeychordGeteventEnable(fd)) {
229 ::close(fd);
Mark Salyzyn44692de2018-05-02 11:22:15 -0700230 } else {
231 keychord_registration.emplace(device, fd);
232 }
233}
234
235void GeteventCloseDevice(const std::string& device) {
236 auto it = keychord_registration.find(device);
237 if (it == keychord_registration.end()) return;
238 auto fd = (*it).second;
239 unregister_epoll_handler(fd);
240 keychord_registration.erase(it);
241 ::close(fd);
242}
243
244int inotify_fd = -1;
245
246void InotifyHandler() {
247 unsigned char buf[512];
248
249 auto res = TEMP_FAILURE_RETRY(::read(inotify_fd, buf, sizeof(buf)));
250 if (res < 0) {
251 PLOG(WARNING) << "could not get event";
252 return;
253 }
254
255 auto event_buf = buf;
256 while (static_cast<size_t>(res) >= sizeof(inotify_event)) {
257 auto event = reinterpret_cast<inotify_event*>(event_buf);
258 auto event_size = sizeof(inotify_event) + event->len;
259 if (static_cast<size_t>(res) < event_size) break;
260 if (event->len) {
261 std::string devname(kDevicePath);
262 devname += '/';
263 devname += event->name;
264 if (event->mask & IN_CREATE) {
265 GeteventOpenDevice(devname);
266 } else {
267 GeteventCloseDevice(devname);
268 }
269 }
270 res -= event_size;
271 event_buf += event_size;
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700272 }
273}
274
275void GeteventOpenDevice() {
Mark Salyzyn44692de2018-05-02 11:22:15 -0700276 inotify_fd = ::inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
277 if (inotify_fd < 0) {
278 PLOG(WARNING) << "Could not instantiate inotify for " << kDevicePath;
279 } else if (::inotify_add_watch(inotify_fd, kDevicePath, IN_DELETE | IN_CREATE) < 0) {
280 PLOG(WARNING) << "Could not add watch for " << kDevicePath;
281 ::close(inotify_fd);
282 inotify_fd = -1;
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700283 }
Mark Salyzyn44692de2018-05-02 11:22:15 -0700284
285 std::unique_ptr<DIR, decltype(&closedir)> device(opendir(kDevicePath), closedir);
286 if (device) {
287 dirent* entry;
288 while ((entry = readdir(device.get()))) {
289 if (entry->d_name[0] == '.') continue;
290 std::string devname(kDevicePath);
291 devname += '/';
292 devname += entry->d_name;
293 GeteventOpenDevice(devname);
294 }
295 }
296
297 if (inotify_fd >= 0) register_epoll_handler(inotify_fd, InotifyHandler);
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700298}
299
300void AddServiceKeycodes(Service* svc) {
301 if (svc->keycodes().empty()) return;
302 for (auto& code : svc->keycodes()) {
303 if ((code < 0) || (code >= KEY_MAX)) return;
304 }
305 ++keychords_count;
306 keychord_entries.emplace_back(KeychordEntry(svc->keycodes(), keychords_count));
307 svc->set_keychord_id(keychords_count);
308}
309
310} // namespace
311
312void KeychordInit() {
Tom Cherry911b9b12017-07-27 16:20:58 -0700313 for (const auto& service : ServiceList::GetInstance()) {
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700314 AddServiceKeycodes(service.get());
Tom Cherry911b9b12017-07-27 16:20:58 -0700315 }
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700316 if (keychords_count) GeteventOpenDevice();
Colin Crossa8666952010-04-13 19:20:44 -0700317}
Tom Cherry81f5d3e2017-06-22 12:53:17 -0700318
319} // namespace init
320} // namespace android