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 #include "service.h" 30 31 static struct input_keychord *keychords = 0; 32 static int keychords_count = 0; 33 static int keychords_length = 0; 34 static int keychord_fd = -1; 35 36 void add_service_keycodes(Service* svc) 37 { 38 struct input_keychord *keychord; 39 size_t i, size; 40 41 if (!svc->keycodes().empty()) { 42 /* add a new keychord to the list */ 43 size = sizeof(*keychord) + svc->keycodes().size() * sizeof(keychord->keycodes[0]); 44 keychords = (input_keychord*) realloc(keychords, keychords_length + size); 45 if (!keychords) { 46 ERROR("could not allocate keychords\n"); 47 keychords_length = 0; 48 keychords_count = 0; 49 return; 50 } 51 52 keychord = (struct input_keychord *)((char *)keychords + keychords_length); 53 keychord->version = KEYCHORD_VERSION; 54 keychord->id = keychords_count + 1; 55 keychord->count = svc->keycodes().size(); 56 svc->set_keychord_id(keychord->id); 57 58 for (i = 0; i < svc->keycodes().size(); i++) { 59 keychord->keycodes[i] = svc->keycodes()[i]; 60 } 61 keychords_count++; 62 keychords_length += size; 63 } 64 } 65 66 static void handle_keychord() { 67 int ret; 68 __u16 id; 69 70 ret = read(keychord_fd, &id, sizeof(id)); 71 if (ret != sizeof(id)) { 72 ERROR("could not read keychord id\n"); 73 return; 74 } 75 76 // Only handle keychords if adb is enabled. 77 std::string adb_enabled = property_get("init.svc.adbd"); 78 if (adb_enabled == "running") { 79 Service* svc = ServiceManager::GetInstance().FindServiceByKeychord(id); 80 if (svc) { 81 NOTICE("Starting service '%s' from keychord %d\n", svc->name().c_str(), id); 82 svc->Start(); 83 } else { 84 ERROR("Service for keychord %d not found\n", id); 85 } 86 } else { 87 WARNING("Not starting service for keychord %d because ADB is disabled\n", id); 88 } 89 } 90 91 void keychord_init() { 92 ServiceManager::GetInstance().ForEachService(add_service_keycodes); 93 94 // Nothing to do if no services require keychords. 95 if (!keychords) { 96 return; 97 } 98 99 keychord_fd = TEMP_FAILURE_RETRY(open("/dev/keychord", O_RDWR | O_CLOEXEC)); 100 if (keychord_fd == -1) { 101 ERROR("could not open /dev/keychord: %s\n", strerror(errno)); 102 return; 103 } 104 105 int ret = write(keychord_fd, keychords, keychords_length); 106 if (ret != keychords_length) { 107 ERROR("could not configure /dev/keychord %d: %s\n", ret, strerror(errno)); 108 close(keychord_fd); 109 } 110 111 free(keychords); 112 keychords = nullptr; 113 114 register_epoll_handler(keychord_fd, handle_keychord); 115 } 116