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