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
add_service_keycodes(struct service * svc)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
keychord_init()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
handle_keychord()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 ret = read(keychord_fd, &id, sizeof(id));
107 if (ret != sizeof(id)) {
108 ERROR("could not read keychord id\n");
109 return;
110 }
111
112 if ((debuggable && !strcmp(debuggable, "1")) ||
113 (adb_enabled && !strcmp(adb_enabled, "running"))) {
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
get_keychord_fd()124 int get_keychord_fd()
125 {
126 return keychord_fd;
127 }
128