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 17a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross#include <errno.h> 18a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross#include <fcntl.h> 19a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross#include <stdlib.h> 20b93e5812faffd3b6c5fb349072413aace31918d8Olivier Bailly#include <string.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 26a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross#include "init.h" 27ed8a7d84428ec945c48b6b53dc5a3a18fabaf683Colin Cross#include "log.h" 28a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross#include "property_service.h" 29a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross 30a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Crossstatic struct input_keychord *keychords = 0; 31a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Crossstatic int keychords_count = 0; 32a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Crossstatic int keychords_length = 0; 33a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Crossstatic int keychord_fd = -1; 34a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross 35a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Crossvoid add_service_keycodes(struct service *svc) 36a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross{ 37a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross struct input_keychord *keychord; 38a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross int i, size; 39a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross 40a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross if (svc->keycodes) { 41a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross /* add a new keychord to the list */ 42a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross size = sizeof(*keychord) + svc->nkeycodes * sizeof(keychord->keycodes[0]); 43a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross keychords = realloc(keychords, keychords_length + size); 44a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross if (!keychords) { 45a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross ERROR("could not allocate keychords\n"); 46a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross keychords_length = 0; 47a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross keychords_count = 0; 48a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross return; 49a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross } 50a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross 51a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross keychord = (struct input_keychord *)((char *)keychords + keychords_length); 52a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross keychord->version = KEYCHORD_VERSION; 53a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross keychord->id = keychords_count + 1; 54a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross keychord->count = svc->nkeycodes; 55a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross svc->keychord_id = keychord->id; 56a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross 57a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross for (i = 0; i < svc->nkeycodes; i++) { 58a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross keychord->keycodes[i] = svc->keycodes[i]; 59a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross } 60a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross keychords_count++; 61a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross keychords_length += size; 62a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross } 63a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross} 64a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross 65a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Crossvoid keychord_init() 66a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross{ 67a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross int fd, ret; 68a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross 69a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross service_for_each(add_service_keycodes); 70a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross 71a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross /* nothing to do if no services require keychords */ 72a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross if (!keychords) 73a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross return; 74a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross 75a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross fd = open("/dev/keychord", O_RDWR); 76a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross if (fd < 0) { 77a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross ERROR("could not open /dev/keychord\n"); 78a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross return; 79a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross } 80a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross fcntl(fd, F_SETFD, FD_CLOEXEC); 81a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross 82a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross ret = write(fd, keychords, keychords_length); 83a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross if (ret != keychords_length) { 84a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross ERROR("could not configure /dev/keychord %d (%d)\n", ret, errno); 85a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross close(fd); 86a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross fd = -1; 87a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross } 88a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross 89a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross free(keychords); 90a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross keychords = 0; 91a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross 92a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross keychord_fd = fd; 93a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross} 94a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross 95a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Crossvoid handle_keychord() 96a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross{ 97a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross struct service *svc; 98a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross const char* debuggable; 99a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross const char* adb_enabled; 100a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross int ret; 101a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross __u16 id; 102a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross 103a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross // only handle keychords if ro.debuggable is set or adb is enabled. 104a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross // the logic here is that bugreports should be enabled in userdebug or eng builds 105a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross // and on user builds for users that are developers. 106a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross debuggable = property_get("ro.debuggable"); 107a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross adb_enabled = property_get("init.svc.adbd"); 108f7ca6040616f672a6f0039d55e39c610b7c1cf91Colin Cross ret = read(keychord_fd, &id, sizeof(id)); 109f7ca6040616f672a6f0039d55e39c610b7c1cf91Colin Cross if (ret != sizeof(id)) { 110f7ca6040616f672a6f0039d55e39c610b7c1cf91Colin Cross ERROR("could not read keychord id\n"); 111f7ca6040616f672a6f0039d55e39c610b7c1cf91Colin Cross return; 112f7ca6040616f672a6f0039d55e39c610b7c1cf91Colin Cross } 113f7ca6040616f672a6f0039d55e39c610b7c1cf91Colin Cross 114a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross if ((debuggable && !strcmp(debuggable, "1")) || 115a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross (adb_enabled && !strcmp(adb_enabled, "running"))) { 116a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross svc = service_find_by_keychord(id); 117a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross if (svc) { 118a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross INFO("starting service %s from keychord\n", svc->name); 119a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross service_start(svc, NULL); 120a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross } else { 121a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross ERROR("service for keychord %d not found\n", id); 122a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross } 123a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross } 124a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross} 125a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross 126a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Crossint get_keychord_fd() 127a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross{ 128a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross return keychord_fd; 129a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross} 130