blob: febb62fab2c139ddd5c622502d35c9087139e54c [file] [log] [blame]
Colin Crossa8666952010-04-13 19:20:44 -07001/*
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"
Colin Crossed8a7d82010-04-19 17:05:34 -070025#include "log.h"
Colin Crossa8666952010-04-13 19:20:44 -070026#include "property_service.h"
27
28static struct input_keychord *keychords = 0;
29static int keychords_count = 0;
30static int keychords_length = 0;
31static int keychord_fd = -1;
32
33void 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
63void 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
93void 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");
Colin Crossf7ca6042011-01-04 18:18:45 -0800106 ret = read(keychord_fd, &id, sizeof(id));
107 if (ret != sizeof(id)) {
108 ERROR("could not read keychord id\n");
109 return;
110 }
111
Colin Crossa8666952010-04-13 19:20:44 -0700112 if ((debuggable && !strcmp(debuggable, "1")) ||
113 (adb_enabled && !strcmp(adb_enabled, "running"))) {
Colin Crossa8666952010-04-13 19:20:44 -0700114 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
124int get_keychord_fd()
125{
126 return keychord_fd;
127}