summaryrefslogtreecommitdiffstats
path: root/init/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'init/init.c')
-rw-r--r--init/init.c157
1 files changed, 131 insertions, 26 deletions
diff --git a/init/init.c b/init/init.c
index 3616840..b8b4f40 100644
--- a/init/init.c
+++ b/init/init.c
@@ -37,6 +37,7 @@
#include <cutils/sockets.h>
#include <termios.h>
#include <linux/kd.h>
+#include <linux/keychord.h>
#include <sys/system_properties.h>
@@ -60,6 +61,9 @@ static char bootloader[32];
static char hardware[32];
static unsigned revision = 0;
static char qemu[32];
+static struct input_keychord *keychords = 0;
+static int keychords_count = 0;
+static int keychords_length = 0;
static void drain_action_queue(void);
@@ -233,7 +237,7 @@ void service_start(struct service *svc)
setpgid(0, getpid());
- /* as requested, set our gid, supplemental gids, and uid */
+ /* as requested, set our gid, supplemental gids, and uid */
if (svc->gid) {
setgid(svc->gid);
}
@@ -658,17 +662,101 @@ void open_devnull_stdio(void)
exit(1);
}
+void add_service_keycodes(struct service *svc)
+{
+ struct input_keychord *keychord;
+ int i, size;
+
+ if (svc->keycodes) {
+ /* add a new keychord to the list */
+ size = sizeof(*keychord) + svc->nkeycodes * sizeof(keychord->keycodes[0]);
+ keychords = realloc(keychords, keychords_length + size);
+ if (!keychords) {
+ ERROR("could not allocate keychords\n");
+ keychords_length = 0;
+ keychords_count = 0;
+ return;
+ }
+
+ keychord = (struct input_keychord *)((char *)keychords + keychords_length);
+ keychord->version = KEYCHORD_VERSION;
+ keychord->id = keychords_count + 1;
+ keychord->count = svc->nkeycodes;
+ svc->keychord_id = keychord->id;
+
+ for (i = 0; i < svc->nkeycodes; i++) {
+ keychord->keycodes[i] = svc->keycodes[i];
+ }
+ keychords_count++;
+ keychords_length += size;
+ }
+}
+
+int open_keychord()
+{
+ int fd, ret;
+
+ service_for_each(add_service_keycodes);
+
+ /* nothing to do if no services require keychords */
+ if (!keychords)
+ return -1;
+
+ fd = open("/dev/keychord", O_RDWR);
+ if (fd < 0) {
+ ERROR("could not open /dev/keychord\n");
+ return fd;
+ }
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+ ret = write(fd, keychords, keychords_length);
+ if (ret != keychords_length) {
+ ERROR("could not configure /dev/keychord %d (%d)\n", ret, errno);
+ close(fd);
+ fd = -1;
+ }
+
+ free(keychords);
+ keychords = 0;
+
+ return fd;
+}
+
+void handle_keychord(int fd)
+{
+ struct service *svc;
+ int ret;
+ __u16 id;
+
+ ret = read(fd, &id, sizeof(id));
+ if (ret != sizeof(id)) {
+ ERROR("could not read keychord id\n");
+ return;
+ }
+
+ svc = service_find_by_keychord(id);
+ if (svc) {
+ INFO("starting service %s from keychord\n", svc->name);
+ service_start(svc);
+ } else {
+ ERROR("service for keychord %d not found\n", id);
+ }
+}
+
int main(int argc, char **argv)
{
int device_fd = -1;
int property_set_fd = -1;
int signal_recv_fd = -1;
+ int keychord_fd = -1;
+ int fd_count;
int s[2];
int fd;
struct sigaction act;
char tmp[PROP_VALUE_MAX];
struct pollfd ufds[4];
char *tmpdev;
+ char* debuggable;
act.sa_handler = sigchld_handler;
act.sa_flags = SA_NOCLDSTOP;
@@ -721,6 +809,12 @@ int main(int argc, char **argv)
device_fd = device_init();
property_init();
+
+ // only listen for keychords if ro.debuggable is true
+ debuggable = property_get("ro.debuggable");
+ if (debuggable && !strcmp(debuggable, "1")) {
+ keychord_fd = open_keychord();
+ }
if (console[0]) {
snprintf(tmp, sizeof(tmp), "/dev/%s", console);
@@ -733,27 +827,27 @@ int main(int argc, char **argv)
close(fd);
if( load_565rle_image(INIT_IMAGE_FILE) ) {
- fd = open("/dev/tty0", O_WRONLY);
- if (fd >= 0) {
- const char *msg;
+ fd = open("/dev/tty0", O_WRONLY);
+ if (fd >= 0) {
+ const char *msg;
msg = "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n" // console is 40 cols x 30 lines
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- " A N D R O I D ";
- write(fd, msg, strlen(msg));
- close(fd);
- }
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n" // console is 40 cols x 30 lines
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ " A N D R O I D ";
+ write(fd, msg, strlen(msg));
+ close(fd);
+ }
}
if (qemu[0])
@@ -823,6 +917,16 @@ int main(int argc, char **argv)
ufds[1].events = POLLIN;
ufds[2].fd = signal_recv_fd;
ufds[2].events = POLLIN;
+ fd_count = 3;
+
+ if (keychord_fd > 0) {
+ ufds[3].fd = keychord_fd;
+ ufds[3].events = POLLIN;
+ fd_count++;
+ } else {
+ ufds[3].events = 0;
+ ufds[3].revents = 0;
+ }
#if BOOTCHART
bootchart_count = bootchart_init();
@@ -836,11 +940,10 @@ int main(int argc, char **argv)
#endif
for(;;) {
- int nr, timeout = -1;
+ int nr, i, timeout = -1;
- ufds[0].revents = 0;
- ufds[1].revents = 0;
- ufds[2].revents = 0;
+ for (i = 0; i < fd_count; i++)
+ ufds[i].revents = 0;
drain_action_queue();
restart_processes();
@@ -861,7 +964,7 @@ int main(int argc, char **argv)
}
}
#endif
- nr = poll(ufds, 3, timeout);
+ nr = poll(ufds, fd_count, timeout);
if (nr <= 0)
continue;
@@ -878,6 +981,8 @@ int main(int argc, char **argv)
if (ufds[1].revents == POLLIN)
handle_property_set_fd(property_set_fd);
+ if (ufds[3].revents == POLLIN)
+ handle_keychord(keychord_fd);
}
return 0;