auto import from //branches/cupcake/...@125939
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 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 @@
 
         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 @@
     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 @@
     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 @@
     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 @@
     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 @@
 #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 @@
             }
         }
 #endif
-        nr = poll(ufds, 3, timeout);
+        nr = poll(ufds, fd_count, timeout);
         if (nr <= 0)
             continue;
 
@@ -878,6 +981,8 @@
 
         if (ufds[1].revents == POLLIN)
             handle_property_set_fd(property_set_fd);
+        if (ufds[3].revents == POLLIN)
+            handle_keychord(keychord_fd);
     }
 
     return 0;