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