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