blob: f55d2c43c3fa2901ec006d2951ba8eb80182aa6c [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>
23#include <sys/ioctl.h>
Colin Crossa8666952010-04-13 19:20:44 -070024#include <sys/types.h>
Olivier Baillyb93e5812010-11-17 11:47:23 -080025#include <unistd.h>
Colin Crossa8666952010-04-13 19:20:44 -070026
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070027#include <algorithm>
28#include <functional>
29#include <memory>
30#include <string>
31#include <vector>
32
Tom Cherry3f5eaae52017-04-06 16:30:22 -070033#include <android-base/logging.h>
Tom Cherryccf23532017-03-28 16:40:41 -070034#include <android-base/properties.h>
35
Colin Crossa8666952010-04-13 19:20:44 -070036#include "init.h"
Tom Cherry81f5d3e2017-06-22 12:53:17 -070037
38namespace android {
39namespace init {
Colin Crossa8666952010-04-13 19:20:44 -070040
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070041namespace {
Colin Crossa8666952010-04-13 19:20:44 -070042
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070043int keychords_count;
Colin Crossa8666952010-04-13 19:20:44 -070044
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070045struct KeychordEntry {
46 const std::vector<int> keycodes;
47 bool notified;
48 int id;
49
50 KeychordEntry(const std::vector<int>& keycodes, int id)
51 : keycodes(keycodes), notified(false), id(id) {}
52};
53
54std::vector<KeychordEntry> keychord_entries;
55
56// Bit management
57class KeychordMask {
58 private:
59 typedef unsigned int mask_t;
60 std::vector<mask_t> bits;
61 static constexpr size_t bits_per_byte = 8;
62
63 public:
64 explicit KeychordMask(size_t bit = 0) : bits((bit + sizeof(mask_t) - 1) / sizeof(mask_t), 0) {}
65
66 void SetBit(size_t bit, bool value = true) {
67 auto idx = bit / (bits_per_byte * sizeof(mask_t));
68 if (idx >= bits.size()) return;
69 if (value) {
70 bits[idx] |= mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t)));
71 } else {
72 bits[idx] &= ~(mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t))));
Colin Crossa8666952010-04-13 19:20:44 -070073 }
Colin Crossf7ca6042011-01-04 18:18:45 -080074 }
75
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070076 bool GetBit(size_t bit) const {
77 auto idx = bit / (bits_per_byte * sizeof(mask_t));
78 return bits[idx] & (mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t))));
79 }
80
81 size_t bytesize() const { return bits.size() * sizeof(mask_t); }
82 void* data() { return bits.data(); }
83 size_t size() const { return bits.size() * sizeof(mask_t) * bits_per_byte; }
84 void resize(size_t bit) {
85 auto idx = bit / (bits_per_byte * sizeof(mask_t));
86 if (idx >= bits.size()) {
87 bits.resize(idx + 1, 0);
88 }
89 }
90
91 operator bool() const {
92 for (size_t i = 0; i < bits.size(); ++i) {
93 if (bits[i]) return true;
94 }
95 return false;
96 }
97
98 KeychordMask operator&(const KeychordMask& rval) const {
99 auto len = std::min(bits.size(), rval.bits.size());
100 KeychordMask ret;
101 ret.bits.resize(len);
102 for (size_t i = 0; i < len; ++i) {
103 ret.bits[i] = bits[i] & rval.bits[i];
104 }
105 return ret;
106 }
107
108 void operator|=(const KeychordMask& rval) {
109 size_t len = rval.bits.size();
110 bits.resize(len);
111 for (size_t i = 0; i < len; ++i) {
112 bits[i] |= rval.bits[i];
113 }
114 }
115};
116
117KeychordMask keychord_current;
118
119constexpr char kDevicePath[] = "/dev/input";
120
121void HandleKeychord(int id) {
Yabin Cui74edcea2015-07-24 10:11:05 -0700122 // Only handle keychords if adb is enabled.
Tom Cherryccf23532017-03-28 16:40:41 -0700123 std::string adb_enabled = android::base::GetProperty("init.svc.adbd", "");
Yabin Cui74edcea2015-07-24 10:11:05 -0700124 if (adb_enabled == "running") {
Tom Cherry911b9b12017-07-27 16:20:58 -0700125 Service* svc = ServiceList::GetInstance().FindService(id, &Service::keychord_id);
Colin Crossa8666952010-04-13 19:20:44 -0700126 if (svc) {
Tom Cherry702ca9a2017-08-25 10:36:52 -0700127 LOG(INFO) << "Starting service '" << svc->name() << "' from keychord " << id;
128 if (auto result = svc->Start(); !result) {
129 LOG(ERROR) << "Could not start service '" << svc->name() << "' from keychord " << id
130 << ": " << result.error();
131 }
Colin Crossa8666952010-04-13 19:20:44 -0700132 } else {
Felipe Leme704fe2d2016-07-29 08:34:39 -0700133 LOG(ERROR) << "Service for keychord " << id << " not found";
Colin Crossa8666952010-04-13 19:20:44 -0700134 }
Felipe Lemec64c9822016-07-28 13:26:07 -0700135 } else {
Felipe Leme704fe2d2016-07-29 08:34:39 -0700136 LOG(WARNING) << "Not starting service for keychord " << id << " because ADB is disabled";
Colin Crossa8666952010-04-13 19:20:44 -0700137 }
138}
139
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700140void KeychordLambdaCheck() {
141 for (auto& e : keychord_entries) {
142 bool found = true;
143 for (auto& code : e.keycodes) {
144 if (!keychord_current.GetBit(code)) {
145 e.notified = false;
146 found = false;
147 break;
148 }
149 }
150 if (!found) continue;
151 if (e.notified) continue;
152 e.notified = true;
153 HandleKeychord(e.id);
154 }
155}
156
157void KeychordLambdaHandler(int fd) {
158 input_event event;
159 auto res = TEMP_FAILURE_RETRY(::read(fd, &event, sizeof(event)));
160 if ((res != sizeof(event)) || (event.type != EV_KEY)) return;
161 keychord_current.SetBit(event.code, event.value);
162 KeychordLambdaCheck();
163}
164
165bool KeychordGeteventEnable(int fd) {
166 static bool EviocsmaskSupported = true;
167
168 // Make sure it is an event channel, should pass this ioctl call
169 int version;
170 if (::ioctl(fd, EVIOCGVERSION, &version)) return false;
171
172 if (EviocsmaskSupported) {
173 KeychordMask mask(EV_KEY);
174 mask.SetBit(EV_KEY);
175 input_mask msg = {};
176 msg.type = EV_SYN;
177 msg.codes_size = mask.bytesize();
178 msg.codes_ptr = reinterpret_cast<uintptr_t>(mask.data());
179 if (::ioctl(fd, EVIOCSMASK, &msg) == -1) {
180 PLOG(WARNING) << "EVIOCSMASK not supported";
181 EviocsmaskSupported = false;
182 }
183 }
184
185 KeychordMask mask;
186 for (auto& e : keychord_entries) {
187 for (auto& code : e.keycodes) {
188 mask.resize(code);
189 mask.SetBit(code);
190 }
191 }
192
193 keychord_current.resize(mask.size());
194 KeychordMask available(mask.size());
195 auto res = ::ioctl(fd, EVIOCGBIT(EV_KEY, available.bytesize()), available.data());
196 if (res == -1) return false;
197 if (!(available & mask)) return false;
198
199 if (EviocsmaskSupported) {
200 input_mask msg = {};
201 msg.type = EV_KEY;
202 msg.codes_size = mask.bytesize();
203 msg.codes_ptr = reinterpret_cast<uintptr_t>(mask.data());
204 ::ioctl(fd, EVIOCSMASK, &msg);
205 }
206
207 KeychordMask set(mask.size());
208 res = ::ioctl(fd, EVIOCGKEY(res), set.data());
209 if (res > 0) {
210 keychord_current |= mask & available & set;
211 KeychordLambdaCheck();
212 }
213 register_epoll_handler(fd, [fd]() { KeychordLambdaHandler(fd); });
214 return true;
215}
216
217void GeteventOpenDevice(const std::string& device) {
218 auto fd = TEMP_FAILURE_RETRY(::open(device.c_str(), O_RDWR | O_CLOEXEC));
219 if (fd == -1) {
220 PLOG(ERROR) << "Can not open " << device;
221 return;
222 }
223 if (!KeychordGeteventEnable(fd)) {
224 ::close(fd);
225 }
226}
227
228void GeteventOpenDevice() {
229 std::unique_ptr<DIR, decltype(&closedir)> device(opendir(kDevicePath), closedir);
230 if (!device) return;
231
232 dirent* entry;
233 while ((entry = readdir(device.get()))) {
234 if (entry->d_name[0] == '.') continue;
235 std::string devname(kDevicePath);
236 devname += '/';
237 devname += entry->d_name;
238 GeteventOpenDevice(devname);
239 }
240}
241
242void AddServiceKeycodes(Service* svc) {
243 if (svc->keycodes().empty()) return;
244 for (auto& code : svc->keycodes()) {
245 if ((code < 0) || (code >= KEY_MAX)) return;
246 }
247 ++keychords_count;
248 keychord_entries.emplace_back(KeychordEntry(svc->keycodes(), keychords_count));
249 svc->set_keychord_id(keychords_count);
250}
251
252} // namespace
253
254void KeychordInit() {
Tom Cherry911b9b12017-07-27 16:20:58 -0700255 for (const auto& service : ServiceList::GetInstance()) {
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700256 AddServiceKeycodes(service.get());
Tom Cherry911b9b12017-07-27 16:20:58 -0700257 }
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700258 if (keychords_count) GeteventOpenDevice();
Colin Crossa8666952010-04-13 19:20:44 -0700259}
Tom Cherry81f5d3e2017-06-22 12:53:17 -0700260
261} // namespace init
262} // namespace android