1a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross/*
2a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross * Copyright (C) 2010 The Android Open Source Project
3a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross *
4a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross * Licensed under the Apache License, Version 2.0 (the "License");
5a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross * you may not use this file except in compliance with the License.
6a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross * You may obtain a copy of the License at
7a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross *
8a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross *      http://www.apache.org/licenses/LICENSE-2.0
9a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross *
10a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross * Unless required by applicable law or agreed to in writing, software
11a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross * distributed under the License is distributed on an "AS IS" BASIS,
12a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross * See the License for the specific language governing permissions and
14a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross * limitations under the License.
15a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross */
16a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
1781f5d3ebef2c3789737bf718fc2a2cdd7b9e8b33Tom Cherry#include "keychords.h"
1881f5d3ebef2c3789737bf718fc2a2cdd7b9e8b33Tom Cherry
19a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross#include <fcntl.h>
20a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross#include <stdlib.h>
21a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross#include <sys/stat.h>
22a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross#include <sys/types.h>
23a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross#include <linux/keychord.h>
24b93e5812faffd3b6c5fb349072413aace31918d8Olivier Bailly#include <unistd.h>
25a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
263f5eaae526413a29de899270714469c76dc91ec8Tom Cherry#include <android-base/logging.h>
27ccf23537eeacfa47e5f18dd3b75089886d177c1bTom Cherry#include <android-base/properties.h>
28ccf23537eeacfa47e5f18dd3b75089886d177c1bTom Cherry
29a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross#include "init.h"
3081f5d3ebef2c3789737bf718fc2a2cdd7b9e8b33Tom Cherry
3181f5d3ebef2c3789737bf718fc2a2cdd7b9e8b33Tom Cherrynamespace android {
3281f5d3ebef2c3789737bf718fc2a2cdd7b9e8b33Tom Cherrynamespace init {
33a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
34a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Crossstatic struct input_keychord *keychords = 0;
35a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Crossstatic int keychords_count = 0;
36a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Crossstatic int keychords_length = 0;
37a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Crossstatic int keychord_fd = -1;
38a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
39bac3299720623f4226bca103b26260052732ad30Tom Cherryvoid add_service_keycodes(Service* svc)
40a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross{
41a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    struct input_keychord *keychord;
42bac3299720623f4226bca103b26260052732ad30Tom Cherry    size_t i, size;
43a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
44bac3299720623f4226bca103b26260052732ad30Tom Cherry    if (!svc->keycodes().empty()) {
45a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        /* add a new keychord to the list */
46bac3299720623f4226bca103b26260052732ad30Tom Cherry        size = sizeof(*keychord) + svc->keycodes().size() * sizeof(keychord->keycodes[0]);
47f3cf438714aa1284d8a58e2f3b108ba93f6d3abbElliott Hughes        keychords = (input_keychord*) realloc(keychords, keychords_length + size);
48a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        if (!keychords) {
49f86b5a6b90619e02d1d034ef7b0adc3b439f4abbElliott Hughes            PLOG(ERROR) << "could not allocate keychords";
50a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross            keychords_length = 0;
51a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross            keychords_count = 0;
52a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross            return;
53a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        }
54a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
55a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        keychord = (struct input_keychord *)((char *)keychords + keychords_length);
56a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        keychord->version = KEYCHORD_VERSION;
57a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        keychord->id = keychords_count + 1;
58bac3299720623f4226bca103b26260052732ad30Tom Cherry        keychord->count = svc->keycodes().size();
59bac3299720623f4226bca103b26260052732ad30Tom Cherry        svc->set_keychord_id(keychord->id);
60a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
61bac3299720623f4226bca103b26260052732ad30Tom Cherry        for (i = 0; i < svc->keycodes().size(); i++) {
62bac3299720623f4226bca103b26260052732ad30Tom Cherry            keychord->keycodes[i] = svc->keycodes()[i];
63a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        }
64a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        keychords_count++;
65a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        keychords_length += size;
66a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    }
67a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross}
68a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
69929f4070767d1e4806c058849178afa13d9ded1eElliott Hughesstatic void handle_keychord() {
70a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    int ret;
71a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    __u16 id;
72a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
73f7ca6040616f672a6f0039d55e39c610b7c1cf91Colin Cross    ret = read(keychord_fd, &id, sizeof(id));
74f7ca6040616f672a6f0039d55e39c610b7c1cf91Colin Cross    if (ret != sizeof(id)) {
75f86b5a6b90619e02d1d034ef7b0adc3b439f4abbElliott Hughes        PLOG(ERROR) << "could not read keychord id";
76f7ca6040616f672a6f0039d55e39c610b7c1cf91Colin Cross        return;
77f7ca6040616f672a6f0039d55e39c610b7c1cf91Colin Cross    }
78f7ca6040616f672a6f0039d55e39c610b7c1cf91Colin Cross
7974edcea90e31a3795e58aa1b2bbe96032f0bcd61Yabin Cui    // Only handle keychords if adb is enabled.
80ccf23537eeacfa47e5f18dd3b75089886d177c1bTom Cherry    std::string adb_enabled = android::base::GetProperty("init.svc.adbd", "");
8174edcea90e31a3795e58aa1b2bbe96032f0bcd61Yabin Cui    if (adb_enabled == "running") {
82bac3299720623f4226bca103b26260052732ad30Tom Cherry        Service* svc = ServiceManager::GetInstance().FindServiceByKeychord(id);
83a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        if (svc) {
84704fe2d62895ed591317f4830dc8df2ade640a3eFelipe Leme            LOG(INFO) << "Starting service " << svc->name() << " from keychord " << id;
85bac3299720623f4226bca103b26260052732ad30Tom Cherry            svc->Start();
86a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        } else {
87704fe2d62895ed591317f4830dc8df2ade640a3eFelipe Leme            LOG(ERROR) << "Service for keychord " << id << " not found";
88a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        }
89c64c982e729e4c4ff5c7d1878488ed216738d443Felipe Leme    } else {
90704fe2d62895ed591317f4830dc8df2ade640a3eFelipe Leme        LOG(WARNING) << "Not starting service for keychord " << id << " because ADB is disabled";
91a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    }
92a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross}
93a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
94929f4070767d1e4806c058849178afa13d9ded1eElliott Hughesvoid keychord_init() {
95bac3299720623f4226bca103b26260052732ad30Tom Cherry    ServiceManager::GetInstance().ForEachService(add_service_keycodes);
96929f4070767d1e4806c058849178afa13d9ded1eElliott Hughes
97929f4070767d1e4806c058849178afa13d9ded1eElliott Hughes    // Nothing to do if no services require keychords.
98929f4070767d1e4806c058849178afa13d9ded1eElliott Hughes    if (!keychords) {
99929f4070767d1e4806c058849178afa13d9ded1eElliott Hughes        return;
100929f4070767d1e4806c058849178afa13d9ded1eElliott Hughes    }
101929f4070767d1e4806c058849178afa13d9ded1eElliott Hughes
102929f4070767d1e4806c058849178afa13d9ded1eElliott Hughes    keychord_fd = TEMP_FAILURE_RETRY(open("/dev/keychord", O_RDWR | O_CLOEXEC));
103929f4070767d1e4806c058849178afa13d9ded1eElliott Hughes    if (keychord_fd == -1) {
104f86b5a6b90619e02d1d034ef7b0adc3b439f4abbElliott Hughes        PLOG(ERROR) << "could not open /dev/keychord";
105929f4070767d1e4806c058849178afa13d9ded1eElliott Hughes        return;
106929f4070767d1e4806c058849178afa13d9ded1eElliott Hughes    }
107929f4070767d1e4806c058849178afa13d9ded1eElliott Hughes
108929f4070767d1e4806c058849178afa13d9ded1eElliott Hughes    int ret = write(keychord_fd, keychords, keychords_length);
109929f4070767d1e4806c058849178afa13d9ded1eElliott Hughes    if (ret != keychords_length) {
110f86b5a6b90619e02d1d034ef7b0adc3b439f4abbElliott Hughes        PLOG(ERROR) << "could not configure /dev/keychord " << ret;
111929f4070767d1e4806c058849178afa13d9ded1eElliott Hughes        close(keychord_fd);
112929f4070767d1e4806c058849178afa13d9ded1eElliott Hughes    }
113929f4070767d1e4806c058849178afa13d9ded1eElliott Hughes
114929f4070767d1e4806c058849178afa13d9ded1eElliott Hughes    free(keychords);
115929f4070767d1e4806c058849178afa13d9ded1eElliott Hughes    keychords = nullptr;
116929f4070767d1e4806c058849178afa13d9ded1eElliott Hughes
117929f4070767d1e4806c058849178afa13d9ded1eElliott Hughes    register_epoll_handler(keychord_fd, handle_keychord);
118a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross}
11981f5d3ebef2c3789737bf718fc2a2cdd7b9e8b33Tom Cherry
12081f5d3ebef2c3789737bf718fc2a2cdd7b9e8b33Tom Cherry}  // namespace init
12181f5d3ebef2c3789737bf718fc2a2cdd7b9e8b33Tom Cherry}  // namespace android
122