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