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