keychords.c revision ed8a7d84428ec945c48b6b53dc5a3a18fabaf683
1a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross/*
2a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross * Copyright (C) 2010 The Android Open Source Project
3a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross *
4a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross * Licensed under the Apache License, Version 2.0 (the "License");
5a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross * you may not use this file except in compliance with the License.
6a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross * You may obtain a copy of the License at
7a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross *
8a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross *      http://www.apache.org/licenses/LICENSE-2.0
9a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross *
10a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross * Unless required by applicable law or agreed to in writing, software
11a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross * distributed under the License is distributed on an "AS IS" BASIS,
12a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross * See the License for the specific language governing permissions and
14a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross * limitations under the License.
15a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross */
16a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
17a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross#include <errno.h>
18a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross#include <fcntl.h>
19a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross#include <stdlib.h>
20a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross#include <sys/stat.h>
21a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross#include <sys/types.h>
22a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross#include <linux/keychord.h>
23a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
24a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross#include "init.h"
25ed8a7d84428ec945c48b6b53dc5a3a18fabaf683Colin Cross#include "log.h"
26a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross#include "property_service.h"
27a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
28a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Crossstatic struct input_keychord *keychords = 0;
29a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Crossstatic int keychords_count = 0;
30a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Crossstatic int keychords_length = 0;
31a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Crossstatic int keychord_fd = -1;
32a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
33a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Crossvoid add_service_keycodes(struct service *svc)
34a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross{
35a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    struct input_keychord *keychord;
36a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    int i, size;
37a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
38a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    if (svc->keycodes) {
39a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        /* add a new keychord to the list */
40a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        size = sizeof(*keychord) + svc->nkeycodes * sizeof(keychord->keycodes[0]);
41a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        keychords = realloc(keychords, keychords_length + size);
42a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        if (!keychords) {
43a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross            ERROR("could not allocate keychords\n");
44a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross            keychords_length = 0;
45a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross            keychords_count = 0;
46a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross            return;
47a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        }
48a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
49a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        keychord = (struct input_keychord *)((char *)keychords + keychords_length);
50a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        keychord->version = KEYCHORD_VERSION;
51a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        keychord->id = keychords_count + 1;
52a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        keychord->count = svc->nkeycodes;
53a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        svc->keychord_id = keychord->id;
54a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
55a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        for (i = 0; i < svc->nkeycodes; i++) {
56a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross            keychord->keycodes[i] = svc->keycodes[i];
57a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        }
58a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        keychords_count++;
59a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        keychords_length += size;
60a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    }
61a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross}
62a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
63a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Crossvoid keychord_init()
64a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross{
65a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    int fd, ret;
66a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
67a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    service_for_each(add_service_keycodes);
68a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
69a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    /* nothing to do if no services require keychords */
70a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    if (!keychords)
71a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        return;
72a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
73a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    fd = open("/dev/keychord", O_RDWR);
74a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    if (fd < 0) {
75a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        ERROR("could not open /dev/keychord\n");
76a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        return;
77a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    }
78a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    fcntl(fd, F_SETFD, FD_CLOEXEC);
79a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
80a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    ret = write(fd, keychords, keychords_length);
81a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    if (ret != keychords_length) {
82a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        ERROR("could not configure /dev/keychord %d (%d)\n", ret, errno);
83a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        close(fd);
84a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        fd = -1;
85a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    }
86a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
87a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    free(keychords);
88a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    keychords = 0;
89a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
90a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    keychord_fd = fd;
91a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross}
92a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
93a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Crossvoid handle_keychord()
94a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross{
95a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    struct service *svc;
96a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    const char* debuggable;
97a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    const char* adb_enabled;
98a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    int ret;
99a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    __u16 id;
100a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
101a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    // only handle keychords if ro.debuggable is set or adb is enabled.
102a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    // the logic here is that bugreports should be enabled in userdebug or eng builds
103a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    // and on user builds for users that are developers.
104a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    debuggable = property_get("ro.debuggable");
105a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    adb_enabled = property_get("init.svc.adbd");
106a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    if ((debuggable && !strcmp(debuggable, "1")) ||
107a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        (adb_enabled && !strcmp(adb_enabled, "running"))) {
108a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        ret = read(keychord_fd, &id, sizeof(id));
109a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        if (ret != sizeof(id)) {
110a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross            ERROR("could not read keychord id\n");
111a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross            return;
112a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        }
113a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
114a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        svc = service_find_by_keychord(id);
115a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        if (svc) {
116a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross            INFO("starting service %s from keychord\n", svc->name);
117a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross            service_start(svc, NULL);
118a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        } else {
119a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross            ERROR("service for keychord %d not found\n", id);
120a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross        }
121a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    }
122a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross}
123a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross
124a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Crossint get_keychord_fd()
125a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross{
126a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross    return keychord_fd;
127a866695ebe3a396a0ec411c0f99e0921c74c0fd2Colin Cross}
128