blob: 418cdeb22332ba615ecd919cb4cb23dd24568e8b [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"
Mark Salyzyn6c6ec722015-10-24 16:20:18 -070039#include "service.h"
Tom Cherry81f5d3e2017-06-22 12:53:17 -070040
41namespace android {
42namespace init {
Colin Crossa8666952010-04-13 19:20:44 -070043
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070044namespace {
Colin Crossa8666952010-04-13 19:20:44 -070045
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070046int keychords_count;
Mark Salyzyn6c6ec722015-10-24 16:20:18 -070047Epoll* epoll;
Colin Crossa8666952010-04-13 19:20:44 -070048
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070049struct KeychordEntry {
50 const std::vector<int> keycodes;
51 bool notified;
52 int id;
53
54 KeychordEntry(const std::vector<int>& keycodes, int id)
55 : keycodes(keycodes), notified(false), id(id) {}
56};
57
58std::vector<KeychordEntry> keychord_entries;
59
60// Bit management
61class KeychordMask {
62 private:
63 typedef unsigned int mask_t;
64 std::vector<mask_t> bits;
65 static constexpr size_t bits_per_byte = 8;
66
67 public:
68 explicit KeychordMask(size_t bit = 0) : bits((bit + sizeof(mask_t) - 1) / sizeof(mask_t), 0) {}
69
70 void SetBit(size_t bit, bool value = true) {
71 auto idx = bit / (bits_per_byte * sizeof(mask_t));
72 if (idx >= bits.size()) return;
73 if (value) {
74 bits[idx] |= mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t)));
75 } else {
76 bits[idx] &= ~(mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t))));
Colin Crossa8666952010-04-13 19:20:44 -070077 }
Colin Crossf7ca6042011-01-04 18:18:45 -080078 }
79
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070080 bool GetBit(size_t bit) const {
81 auto idx = bit / (bits_per_byte * sizeof(mask_t));
82 return bits[idx] & (mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t))));
83 }
84
85 size_t bytesize() const { return bits.size() * sizeof(mask_t); }
86 void* data() { return bits.data(); }
87 size_t size() const { return bits.size() * sizeof(mask_t) * bits_per_byte; }
88 void resize(size_t bit) {
89 auto idx = bit / (bits_per_byte * sizeof(mask_t));
90 if (idx >= bits.size()) {
91 bits.resize(idx + 1, 0);
92 }
93 }
94
95 operator bool() const {
96 for (size_t i = 0; i < bits.size(); ++i) {
97 if (bits[i]) return true;
98 }
99 return false;
100 }
101
102 KeychordMask operator&(const KeychordMask& rval) const {
103 auto len = std::min(bits.size(), rval.bits.size());
104 KeychordMask ret;
105 ret.bits.resize(len);
106 for (size_t i = 0; i < len; ++i) {
107 ret.bits[i] = bits[i] & rval.bits[i];
108 }
109 return ret;
110 }
111
112 void operator|=(const KeychordMask& rval) {
113 size_t len = rval.bits.size();
114 bits.resize(len);
115 for (size_t i = 0; i < len; ++i) {
116 bits[i] |= rval.bits[i];
117 }
118 }
119};
120
121KeychordMask keychord_current;
122
123constexpr char kDevicePath[] = "/dev/input";
124
Mark Salyzyn44692de2018-05-02 11:22:15 -0700125std::map<std::string, int> keychord_registration;
126
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700127void HandleKeychord(int id) {
Yabin Cui74edcea2015-07-24 10:11:05 -0700128 // Only handle keychords if adb is enabled.
Tom Cherryccf23532017-03-28 16:40:41 -0700129 std::string adb_enabled = android::base::GetProperty("init.svc.adbd", "");
Yabin Cui74edcea2015-07-24 10:11:05 -0700130 if (adb_enabled == "running") {
Tom Cherry911b9b12017-07-27 16:20:58 -0700131 Service* svc = ServiceList::GetInstance().FindService(id, &Service::keychord_id);
Colin Crossa8666952010-04-13 19:20:44 -0700132 if (svc) {
Tom Cherry702ca9a2017-08-25 10:36:52 -0700133 LOG(INFO) << "Starting service '" << svc->name() << "' from keychord " << id;
134 if (auto result = svc->Start(); !result) {
135 LOG(ERROR) << "Could not start service '" << svc->name() << "' from keychord " << id
136 << ": " << result.error();
137 }
Colin Crossa8666952010-04-13 19:20:44 -0700138 } else {
Felipe Leme704fe2d2016-07-29 08:34:39 -0700139 LOG(ERROR) << "Service for keychord " << id << " not found";
Colin Crossa8666952010-04-13 19:20:44 -0700140 }
Felipe Lemec64c9822016-07-28 13:26:07 -0700141 } else {
Felipe Leme704fe2d2016-07-29 08:34:39 -0700142 LOG(WARNING) << "Not starting service for keychord " << id << " because ADB is disabled";
Colin Crossa8666952010-04-13 19:20:44 -0700143 }
144}
145
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700146void KeychordLambdaCheck() {
147 for (auto& e : keychord_entries) {
148 bool found = true;
149 for (auto& code : e.keycodes) {
150 if (!keychord_current.GetBit(code)) {
151 e.notified = false;
152 found = false;
153 break;
154 }
155 }
156 if (!found) continue;
157 if (e.notified) continue;
158 e.notified = true;
159 HandleKeychord(e.id);
160 }
161}
162
163void KeychordLambdaHandler(int fd) {
164 input_event event;
165 auto res = TEMP_FAILURE_RETRY(::read(fd, &event, sizeof(event)));
166 if ((res != sizeof(event)) || (event.type != EV_KEY)) return;
167 keychord_current.SetBit(event.code, event.value);
168 KeychordLambdaCheck();
169}
170
171bool KeychordGeteventEnable(int fd) {
172 static bool EviocsmaskSupported = true;
173
174 // Make sure it is an event channel, should pass this ioctl call
175 int version;
176 if (::ioctl(fd, EVIOCGVERSION, &version)) return false;
177
178 if (EviocsmaskSupported) {
179 KeychordMask mask(EV_KEY);
180 mask.SetBit(EV_KEY);
181 input_mask msg = {};
182 msg.type = EV_SYN;
183 msg.codes_size = mask.bytesize();
184 msg.codes_ptr = reinterpret_cast<uintptr_t>(mask.data());
185 if (::ioctl(fd, EVIOCSMASK, &msg) == -1) {
186 PLOG(WARNING) << "EVIOCSMASK not supported";
187 EviocsmaskSupported = false;
188 }
189 }
190
191 KeychordMask mask;
192 for (auto& e : keychord_entries) {
193 for (auto& code : e.keycodes) {
194 mask.resize(code);
195 mask.SetBit(code);
196 }
197 }
198
199 keychord_current.resize(mask.size());
200 KeychordMask available(mask.size());
201 auto res = ::ioctl(fd, EVIOCGBIT(EV_KEY, available.bytesize()), available.data());
202 if (res == -1) return false;
203 if (!(available & mask)) return false;
204
205 if (EviocsmaskSupported) {
206 input_mask msg = {};
207 msg.type = EV_KEY;
208 msg.codes_size = mask.bytesize();
209 msg.codes_ptr = reinterpret_cast<uintptr_t>(mask.data());
210 ::ioctl(fd, EVIOCSMASK, &msg);
211 }
212
213 KeychordMask set(mask.size());
214 res = ::ioctl(fd, EVIOCGKEY(res), set.data());
215 if (res > 0) {
216 keychord_current |= mask & available & set;
217 KeychordLambdaCheck();
218 }
Mark Salyzyn6c6ec722015-10-24 16:20:18 -0700219 epoll->RegisterHandler(fd, [fd]() { KeychordLambdaHandler(fd); });
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700220 return true;
221}
222
223void GeteventOpenDevice(const std::string& device) {
Mark Salyzyn44692de2018-05-02 11:22:15 -0700224 if (keychord_registration.count(device)) return;
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700225 auto fd = TEMP_FAILURE_RETRY(::open(device.c_str(), O_RDWR | O_CLOEXEC));
226 if (fd == -1) {
227 PLOG(ERROR) << "Can not open " << device;
228 return;
229 }
230 if (!KeychordGeteventEnable(fd)) {
231 ::close(fd);
Mark Salyzyn44692de2018-05-02 11:22:15 -0700232 } else {
233 keychord_registration.emplace(device, fd);
234 }
235}
236
237void GeteventCloseDevice(const std::string& device) {
238 auto it = keychord_registration.find(device);
239 if (it == keychord_registration.end()) return;
240 auto fd = (*it).second;
Mark Salyzyn6c6ec722015-10-24 16:20:18 -0700241 epoll->UnregisterHandler(fd);
Mark Salyzyn44692de2018-05-02 11:22:15 -0700242 keychord_registration.erase(it);
243 ::close(fd);
244}
245
246int inotify_fd = -1;
247
248void InotifyHandler() {
249 unsigned char buf[512];
250
251 auto res = TEMP_FAILURE_RETRY(::read(inotify_fd, buf, sizeof(buf)));
252 if (res < 0) {
253 PLOG(WARNING) << "could not get event";
254 return;
255 }
256
257 auto event_buf = buf;
258 while (static_cast<size_t>(res) >= sizeof(inotify_event)) {
259 auto event = reinterpret_cast<inotify_event*>(event_buf);
260 auto event_size = sizeof(inotify_event) + event->len;
261 if (static_cast<size_t>(res) < event_size) break;
262 if (event->len) {
263 std::string devname(kDevicePath);
264 devname += '/';
265 devname += event->name;
266 if (event->mask & IN_CREATE) {
267 GeteventOpenDevice(devname);
268 } else {
269 GeteventCloseDevice(devname);
270 }
271 }
272 res -= event_size;
273 event_buf += event_size;
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700274 }
275}
276
277void GeteventOpenDevice() {
Mark Salyzyn44692de2018-05-02 11:22:15 -0700278 inotify_fd = ::inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
279 if (inotify_fd < 0) {
280 PLOG(WARNING) << "Could not instantiate inotify for " << kDevicePath;
Mark Salyzynf1877152018-05-11 08:25:28 -0700281 } else if (::inotify_add_watch(inotify_fd, kDevicePath, IN_DELETE | IN_CREATE | IN_ONLYDIR) < 0) {
Mark Salyzyn44692de2018-05-02 11:22:15 -0700282 PLOG(WARNING) << "Could not add watch for " << kDevicePath;
283 ::close(inotify_fd);
284 inotify_fd = -1;
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700285 }
Mark Salyzyn44692de2018-05-02 11:22:15 -0700286
287 std::unique_ptr<DIR, decltype(&closedir)> device(opendir(kDevicePath), closedir);
288 if (device) {
289 dirent* entry;
290 while ((entry = readdir(device.get()))) {
291 if (entry->d_name[0] == '.') continue;
292 std::string devname(kDevicePath);
293 devname += '/';
294 devname += entry->d_name;
295 GeteventOpenDevice(devname);
296 }
297 }
298
Mark Salyzyn6c6ec722015-10-24 16:20:18 -0700299 if (inotify_fd >= 0) epoll->RegisterHandler(inotify_fd, InotifyHandler);
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700300}
301
302void AddServiceKeycodes(Service* svc) {
303 if (svc->keycodes().empty()) return;
304 for (auto& code : svc->keycodes()) {
305 if ((code < 0) || (code >= KEY_MAX)) return;
306 }
307 ++keychords_count;
308 keychord_entries.emplace_back(KeychordEntry(svc->keycodes(), keychords_count));
309 svc->set_keychord_id(keychords_count);
310}
311
312} // namespace
313
Mark Salyzyn6c6ec722015-10-24 16:20:18 -0700314void KeychordInit(Epoll* init_epoll) {
315 epoll = init_epoll;
Tom Cherry911b9b12017-07-27 16:20:58 -0700316 for (const auto& service : ServiceList::GetInstance()) {
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700317 AddServiceKeycodes(service.get());
Tom Cherry911b9b12017-07-27 16:20:58 -0700318 }
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700319 if (keychords_count) GeteventOpenDevice();
Colin Crossa8666952010-04-13 19:20:44 -0700320}
Tom Cherry81f5d3e2017-06-22 12:53:17 -0700321
322} // namespace init
323} // namespace android