am bc39871b: Merge changes I46a91849,I3a24afa2,I1df96964,Ic7a19073,I31db51eb,I11ed0f3e,I8fba9f5f,I04e8f0ae into kraken
diff --git a/init/Android.mk b/init/Android.mk
index d3766d4..3233883 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -10,7 +10,9 @@
 	property_service.c \
 	util.c \
 	parser.c \
-	logo.c
+	logo.c \
+	keychords.c \
+	signal_handler.c
 
 ifeq ($(strip $(INIT_BOOTCHART)),true)
 LOCAL_SRC_FILES += bootchart.c
diff --git a/init/builtins.c b/init/builtins.c
index b4af700..7696954 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -35,6 +35,8 @@
 #include "keywords.h"
 #include "property_service.h"
 #include "devices.h"
+#include "parser.h"
+#include "util.h"
 
 #include <private/android_filesystem_config.h>
 
diff --git a/init/devices.c b/init/devices.c
index bde906b..a9ed141 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -40,6 +40,8 @@
 #define FIRMWARE_DIR    "/etc/firmware"
 #define MAX_QEMU_PERM 6
 
+static int device_fd = -1;
+
 struct uevent {
     const char *action;
     const char *path;
@@ -569,12 +571,12 @@
 }
 
 #define UEVENT_MSG_LEN  1024
-void handle_device_fd(int fd)
+void handle_device_fd()
 {
     char msg[UEVENT_MSG_LEN+2];
     int n;
 
-    while((n = recv(fd, msg, UEVENT_MSG_LEN, 0)) > 0) {
+    while((n = recv(device_fd, msg, UEVENT_MSG_LEN, 0)) > 0) {
         struct uevent uevent;
 
         if(n == UEVENT_MSG_LEN)   /* overflow -- discard */
@@ -599,7 +601,7 @@
 ** socket's buffer.  
 */
 
-static void do_coldboot(int event_fd, DIR *d)
+static void do_coldboot(DIR *d)
 {
     struct dirent *de;
     int dfd, fd;
@@ -610,7 +612,7 @@
     if(fd >= 0) {
         write(fd, "add\n", 4);
         close(fd);
-        handle_device_fd(event_fd);
+        handle_device_fd();
     }
 
     while((de = readdir(d))) {
@@ -627,40 +629,42 @@
         if(d2 == 0)
             close(fd);
         else {
-            do_coldboot(event_fd, d2);
+            do_coldboot(d2);
             closedir(d2);
         }
     }
 }
 
-static void coldboot(int event_fd, const char *path)
+static void coldboot(const char *path)
 {
     DIR *d = opendir(path);
     if(d) {
-        do_coldboot(event_fd, d);
+        do_coldboot(d);
         closedir(d);
     }
 }
 
-int device_init(void)
+void device_init(void)
 {
     suseconds_t t0, t1;
-    int fd;
 
-    fd = open_uevent_socket();
-    if(fd < 0)
-        return -1;
+    device_fd = open_uevent_socket();
+    if(device_fd < 0)
+        return;
 
-    fcntl(fd, F_SETFD, FD_CLOEXEC);
-    fcntl(fd, F_SETFL, O_NONBLOCK);
+    fcntl(device_fd, F_SETFD, FD_CLOEXEC);
+    fcntl(device_fd, F_SETFL, O_NONBLOCK);
 
     t0 = get_usecs();
-    coldboot(fd, "/sys/class");
-    coldboot(fd, "/sys/block");
-    coldboot(fd, "/sys/devices");
+    coldboot("/sys/class");
+    coldboot("/sys/block");
+    coldboot("/sys/devices");
     t1 = get_usecs();
 
     log_event_print("coldboot %ld uS\n", ((long) (t1 - t0)));
+}
 
-    return fd;
+int get_device_fd()
+{
+    return device_fd;
 }
diff --git a/init/devices.h b/init/devices.h
index b484da4..e14f4c8 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -17,11 +17,11 @@
 #ifndef _INIT_DEVICES_H
 #define _INIT_DEVICES_H
 
-extern void handle_device_fd(int fd);
-extern int device_init(void);
+extern void handle_device_fd();
+extern void device_init(void);
 extern void qemu_init(void);
 extern void qemu_cmdline(const char* name, const char *value);
 extern int add_devperms_partners(const char *name, mode_t perm, unsigned int uid,
                                  unsigned int gid, unsigned short prefix);
-
+int get_device_fd();
 #endif	/* _INIT_DEVICES_H */
diff --git a/init/init.c b/init/init.c
index 65d3d84..3d619b9 100755
--- a/init/init.c
+++ b/init/init.c
@@ -25,20 +25,16 @@
 #include <sys/mount.h>
 #include <sys/stat.h>
 #include <sys/poll.h>
-#include <time.h>
 #include <errno.h>
 #include <stdarg.h>
 #include <mtd/mtd-user.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/un.h>
-#include <sys/reboot.h>
 
 #include <cutils/sockets.h>
 #include <cutils/iosched_policy.h>
 #include <termios.h>
-#include <linux/kd.h>
-#include <linux/keychord.h>
 
 #include <sys/system_properties.h>
 
@@ -46,6 +42,10 @@
 #include "init.h"
 #include "property_service.h"
 #include "bootchart.h"
+#include "signal_handler.h"
+#include "keychords.h"
+#include "parser.h"
+#include "util.h"
 
 static int property_triggers_enabled = 0;
 
@@ -62,11 +62,8 @@
 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 notify_service_state(const char *name, const char *state)
+void notify_service_state(const char *name, const char *state)
 {
     char pname[PROP_NAME_MAX];
     int len = strlen(name);
@@ -122,24 +119,6 @@
     close(fd);
 }
 
-/*
- * gettime() - returns the time in seconds of the system's monotonic clock or
- * zero on error.
- */
-static time_t gettime(void)
-{
-    struct timespec ts;
-    int ret;
-
-    ret = clock_gettime(CLOCK_MONOTONIC, &ts);
-    if (ret < 0) {
-        ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno));
-        return 0;
-    }
-
-    return ts.tv_sec;
-}
-
 static void publish_socket(const char *name, int fd)
 {
     char key[64] = ANDROID_SOCKET_ENV_PREFIX;
@@ -328,86 +307,6 @@
     }
 }
 
-#define CRITICAL_CRASH_THRESHOLD    4       /* if we crash >4 times ... */
-#define CRITICAL_CRASH_WINDOW       (4*60)  /* ... in 4 minutes, goto recovery*/
-
-static int wait_for_one_process(int block)
-{
-    pid_t pid;
-    int status;
-    struct service *svc;
-    struct socketinfo *si;
-    time_t now;
-    struct listnode *node;
-    struct command *cmd;
-
-    while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR );
-    if (pid <= 0) return -1;
-    INFO("waitpid returned pid %d, status = %08x\n", pid, status);
-
-    svc = service_find_by_pid(pid);
-    if (!svc) {
-        ERROR("untracked pid %d exited\n", pid);
-        return 0;
-    }
-
-    NOTICE("process '%s', pid %d exited\n", svc->name, pid);
-
-    if (!(svc->flags & SVC_ONESHOT)) {
-        kill(-pid, SIGKILL);
-        NOTICE("process '%s' killing any children in process group\n", svc->name);
-    }
-
-    /* remove any sockets we may have created */
-    for (si = svc->sockets; si; si = si->next) {
-        char tmp[128];
-        snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);
-        unlink(tmp);
-    }
-
-    svc->pid = 0;
-    svc->flags &= (~SVC_RUNNING);
-
-        /* oneshot processes go into the disabled state on exit */
-    if (svc->flags & SVC_ONESHOT) {
-        svc->flags |= SVC_DISABLED;
-    }
-
-        /* disabled processes do not get restarted automatically */
-    if (svc->flags & SVC_DISABLED) {
-        notify_service_state(svc->name, "stopped");
-        return 0;
-    }
-
-    now = gettime();
-    if (svc->flags & SVC_CRITICAL) {
-        if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
-            if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
-                ERROR("critical process '%s' exited %d times in %d minutes; "
-                      "rebooting into recovery mode\n", svc->name,
-                      CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
-                sync();
-                __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
-                         LINUX_REBOOT_CMD_RESTART2, "recovery");
-                return 0;
-            }
-        } else {
-            svc->time_crashed = now;
-            svc->nr_crashed = 1;
-        }
-    }
-
-    svc->flags |= SVC_RESTARTING;
-
-    /* Execute all onrestart commands for this service. */
-    list_for_each(node, &svc->onrestart.commands) {
-        cmd = node_to_item(node, struct command, clist);
-        cmd->func(cmd->nargs, cmd->args);
-    }
-    notify_service_state(svc->name, "restarting");
-    return 0;
-}
-
 static void restart_service_if_needed(struct service *svc)
 {
     time_t next_start_time = svc->time_started + 5;
@@ -431,13 +330,6 @@
                            restart_service_if_needed);
 }
 
-static int signal_fd = -1;
-
-static void sigchld_handler(int s)
-{
-    write(signal_fd, &s, 1);
-}
-
 static void msg_start(const char *name)
 {
     struct service *svc;
@@ -486,78 +378,6 @@
     }
 }
 
-#define MAX_MTD_PARTITIONS 16
-
-static struct {
-    char name[16];
-    int number;
-} mtd_part_map[MAX_MTD_PARTITIONS];
-
-static int mtd_part_count = -1;
-
-static void find_mtd_partitions(void)
-{
-    int fd;
-    char buf[1024];
-    char *pmtdbufp;
-    ssize_t pmtdsize;
-    int r;
-
-    fd = open("/proc/mtd", O_RDONLY);
-    if (fd < 0)
-        return;
-
-    buf[sizeof(buf) - 1] = '\0';
-    pmtdsize = read(fd, buf, sizeof(buf) - 1);
-    pmtdbufp = buf;
-    while (pmtdsize > 0) {
-        int mtdnum, mtdsize, mtderasesize;
-        char mtdname[16];
-        mtdname[0] = '\0';
-        mtdnum = -1;
-        r = sscanf(pmtdbufp, "mtd%d: %x %x %15s",
-                   &mtdnum, &mtdsize, &mtderasesize, mtdname);
-        if ((r == 4) && (mtdname[0] == '"')) {
-            char *x = strchr(mtdname + 1, '"');
-            if (x) {
-                *x = 0;
-            }
-            INFO("mtd partition %d, %s\n", mtdnum, mtdname + 1);
-            if (mtd_part_count < MAX_MTD_PARTITIONS) {
-                strcpy(mtd_part_map[mtd_part_count].name, mtdname + 1);
-                mtd_part_map[mtd_part_count].number = mtdnum;
-                mtd_part_count++;
-            } else {
-                ERROR("too many mtd partitions\n");
-            }
-        }
-        while (pmtdsize > 0 && *pmtdbufp != '\n') {
-            pmtdbufp++;
-            pmtdsize--;
-        }
-        if (pmtdsize > 0) {
-            pmtdbufp++;
-            pmtdsize--;
-        }
-    }
-    close(fd);
-}
-
-int mtd_name_to_number(const char *name) 
-{
-    int n;
-    if (mtd_part_count < 0) {
-        mtd_part_count = 0;
-        find_mtd_partitions();
-    }
-    for (n = 0; n < mtd_part_count; n++) {
-        if (!strcmp(name, mtd_part_map[n].name)) {
-            return mtd_part_map[n].number;
-        }
-    }
-    return -1;
-}
-
 static void import_kernel_nv(char *name, int in_qemu)
 {
     char *value = strchr(name, '=');
@@ -712,103 +532,8 @@
     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;
-    char* debuggable;
-    char* adb_enabled;
-    int ret;
-    __u16 id;
-
-    // only handle keychords if ro.debuggable is set or adb is enabled.
-    // the logic here is that bugreports should be enabled in userdebug or eng builds
-    // and on user builds for users that are developers.
-    debuggable = property_get("ro.debuggable");
-    adb_enabled = property_get("init.svc.adbd");
-    if ((debuggable && !strcmp(debuggable, "1")) ||
-        (adb_enabled && !strcmp(adb_enabled, "running"))) {
-        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, NULL);
-        } 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;
@@ -818,12 +543,6 @@
     char *tmpdev;
     char* debuggable;
 
-    act.sa_handler = sigchld_handler;
-    act.sa_flags = SA_NOCLDSTOP;
-    act.sa_mask = 0;
-    act.sa_restorer = NULL;
-    sigaction(SIGCHLD, &act, 0);
-
     /* clear the umask */
     umask(0);
 
@@ -866,12 +585,12 @@
     drain_action_queue();
 
     INFO("device init\n");
-    device_fd = device_init();
+    device_init();
 
     property_init();
     
     // only listen for keychords if ro.debuggable is true
-    keychord_fd = open_keychord();
+    keychord_init();
 
     if (console[0]) {
         snprintf(tmp, sizeof(tmp), "/dev/%s", console);
@@ -939,22 +658,14 @@
          * after the ro.foo properties are set above so
          * that /data/local.prop cannot interfere with them.
          */
-    property_set_fd = start_property_service();
+    start_property_service();
 
-    /* create a signalling mechanism for the sigchld handler */
-    if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {
-        signal_fd = s[0];
-        signal_recv_fd = s[1];
-        fcntl(s[0], F_SETFD, FD_CLOEXEC);
-        fcntl(s[0], F_SETFL, O_NONBLOCK);
-        fcntl(s[1], F_SETFD, FD_CLOEXEC);
-        fcntl(s[1], F_SETFL, O_NONBLOCK);
-    }
+    signal_init();
 
     /* make sure we actually have all the pieces we need */
-    if ((device_fd < 0) ||
-        (property_set_fd < 0) ||
-        (signal_recv_fd < 0)) {
+    if ((get_device_fd() < 0) ||
+        (get_property_set_fd() < 0) ||
+        (get_signal_fd() < 0)) {
         ERROR("init startup failure\n");
         return 1;
     }
@@ -971,16 +682,16 @@
         /* enable property triggers */   
     property_triggers_enabled = 1;     
 
-    ufds[0].fd = device_fd;
+    ufds[0].fd = get_device_fd();
     ufds[0].events = POLLIN;
-    ufds[1].fd = property_set_fd;
+    ufds[1].fd = get_property_set_fd();
     ufds[1].events = POLLIN;
-    ufds[2].fd = signal_recv_fd;
+    ufds[2].fd = get_signal_fd();
     ufds[2].events = POLLIN;
     fd_count = 3;
 
-    if (keychord_fd > 0) {
-        ufds[3].fd = keychord_fd;
+    if (get_keychord_fd() > 0) {
+        ufds[3].fd = get_keychord_fd();
         ufds[3].events = POLLIN;
         fd_count++;
     } else {
@@ -1029,20 +740,17 @@
             continue;
 
         if (ufds[2].revents == POLLIN) {
-            /* we got a SIGCHLD - reap and restart as needed */
-            read(signal_recv_fd, tmp, sizeof(tmp));
-            while (!wait_for_one_process(0))
-                ;
+            handle_signal();
             continue;
         }
 
         if (ufds[0].revents == POLLIN)
-            handle_device_fd(device_fd);
+            handle_device_fd();
 
         if (ufds[1].revents == POLLIN)
-            handle_property_set_fd(property_set_fd);
+            handle_property_set_fd();
         if (ufds[3].revents == POLLIN)
-            handle_keychord(keychord_fd);
+            handle_keychord();
     }
 
     return 0;
diff --git a/init/init.h b/init/init.h
index f92a4d7..1ebdbac 100644
--- a/init/init.h
+++ b/init/init.h
@@ -17,15 +17,8 @@
 #ifndef _INIT_INIT_H
 #define _INIT_INIT_H
 
-int mtd_name_to_number(const char *name);
-
 void handle_control_message(const char *msg, const char *arg);
 
-int create_socket(const char *name, int type, mode_t perm,
-                  uid_t uid, gid_t gid);
-
-void *read_file(const char *fn, unsigned *_sz);
-
 void log_init(void);
 void log_set_level(int level);
 void log_close(void);
@@ -39,8 +32,6 @@
 #define LOG_DEFAULT_LEVEL  3  /* messages <= this level are logged */
 #define LOG_UEVENTS        0  /* log uevent messages if 1. verbose */
 
-unsigned int decode_uid(const char *s);
-
 struct listnode
 {
     struct listnode *next;
@@ -156,6 +147,8 @@
 
 int parse_config_file(const char *fn);
 
+void notify_service_state(const char *name, const char *state);
+
 struct service *service_find_by_name(const char *name);
 struct service *service_find_by_pid(pid_t pid);
 struct service *service_find_by_keychord(int keychord_id);
@@ -168,14 +161,6 @@
 void service_start(struct service *svc, const char *dynamic_args);
 void property_changed(const char *name, const char *value);
 
-void drain_action_queue(void);
-struct action *action_remove_queue_head(void);
-void action_add_queue_tail(struct action *act);
-void action_for_each_trigger(const char *trigger,
-                             void (*func)(struct action *act));
-void queue_property_triggers(const char *name, const char *value);
-void queue_all_property_triggers();
-
 #define INIT_IMAGE_FILE	"/initlogo.rle"
 
 int load_565rle_image( char *file_name );
diff --git a/init/keychords.c b/init/keychords.c
new file mode 100644
index 0000000..bc286dd
--- /dev/null
+++ b/init/keychords.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <linux/keychord.h>
+
+#include "init.h"
+#include "property_service.h"
+
+static struct input_keychord *keychords = 0;
+static int keychords_count = 0;
+static int keychords_length = 0;
+static int keychord_fd = -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;
+    }
+}
+
+void keychord_init()
+{
+    int fd, ret;
+
+    service_for_each(add_service_keycodes);
+
+    /* nothing to do if no services require keychords */
+    if (!keychords)
+        return;
+
+    fd = open("/dev/keychord", O_RDWR);
+    if (fd < 0) {
+        ERROR("could not open /dev/keychord\n");
+        return;
+    }
+    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;
+
+    keychord_fd = fd;
+}
+
+void handle_keychord()
+{
+    struct service *svc;
+    const char* debuggable;
+    const char* adb_enabled;
+    int ret;
+    __u16 id;
+
+    // only handle keychords if ro.debuggable is set or adb is enabled.
+    // the logic here is that bugreports should be enabled in userdebug or eng builds
+    // and on user builds for users that are developers.
+    debuggable = property_get("ro.debuggable");
+    adb_enabled = property_get("init.svc.adbd");
+    if ((debuggable && !strcmp(debuggable, "1")) ||
+        (adb_enabled && !strcmp(adb_enabled, "running"))) {
+        ret = read(keychord_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, NULL);
+        } else {
+            ERROR("service for keychord %d not found\n", id);
+        }
+    }
+}
+
+int get_keychord_fd()
+{
+    return keychord_fd;
+}
diff --git a/init/keychords.h b/init/keychords.h
new file mode 100644
index 0000000..070b858
--- /dev/null
+++ b/init/keychords.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_KEYCHORDS_H_
+#define _INIT_KEYCHORDS_H_
+
+struct service;
+
+void add_service_keycodes(struct service *svc);
+void keychord_init(void);
+void handle_keychord(void);
+int get_keychord_fd(void);
+
+#endif
diff --git a/init/parser.c b/init/parser.c
index 7da0d19..9424e7e 100644
--- a/init/parser.c
+++ b/init/parser.c
@@ -9,6 +9,8 @@
 
 #include "init.h"
 #include "property_service.h"
+#include "parser.h"
+#include "util.h"
 
 #include <cutils/iosched_policy.h>
 
diff --git a/init/parser.h b/init/parser.h
new file mode 100644
index 0000000..cec848d
--- /dev/null
+++ b/init/parser.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PARSER_H_
+#define PARSER_H_
+
+struct action;
+
+void drain_action_queue(void);
+struct action *action_remove_queue_head(void);
+void action_add_queue_tail(struct action *act);
+void action_for_each_trigger(const char *trigger,
+                             void (*func)(struct action *act));
+int action_queue_empty(void);
+void queue_property_triggers(const char *name, const char *value);
+void queue_all_property_triggers();
+
+#endif /* PARSER_H_ */
diff --git a/init/property_service.c b/init/property_service.c
index d2505dd..b1c6552 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -43,11 +43,14 @@
 
 #include "property_service.h"
 #include "init.h"
+#include "util.h"
 
 #define PERSISTENT_PROPERTY_DIR  "/data/property"
 
 static int persistent_properties_loaded = 0;
 
+static int property_set_fd = -1;
+
 /* White list of permissions for setting property services. */
 struct {
     const char *prefix;
@@ -187,7 +190,7 @@
  *
  * Returns 1 if uid allowed, 0 otherwise.
  */
-static int check_control_perms(const char *name, int uid, int gid) {
+static int check_control_perms(const char *name, unsigned int uid, unsigned int gid) {
     int i;
     if (uid == AID_SYSTEM || uid == AID_ROOT)
         return 1;
@@ -208,7 +211,7 @@
  * Checks permissions for setting system properties.
  * Returns 1 if uid allowed, 0 otherwise.
  */
-static int check_perms(const char *name, unsigned int uid, int gid)
+static int check_perms(const char *name, unsigned int uid, unsigned int gid)
 {
     int i;
     if (uid == 0)
@@ -344,7 +347,7 @@
     return 0;
 }
 
-void handle_property_set_fd(int fd)
+void handle_property_set_fd()
 {
     prop_msg msg;
     int s;
@@ -355,7 +358,7 @@
     socklen_t addr_size = sizeof(addr);
     socklen_t cr_size = sizeof(cr);
 
-    if ((s = accept(fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
+    if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
         return;
     }
 
@@ -493,7 +496,7 @@
     load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);
 }
 
-int start_property_service(void)
+void start_property_service(void)
 {
     int fd;
 
@@ -504,10 +507,15 @@
     load_persistent_properties();
 
     fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0);
-    if(fd < 0) return -1;
+    if(fd < 0) return;
     fcntl(fd, F_SETFD, FD_CLOEXEC);
     fcntl(fd, F_SETFL, O_NONBLOCK);
 
     listen(fd, 8);
-    return fd;
+    property_set_fd = fd;
+}
+
+int get_property_set_fd()
+{
+    return property_set_fd;
 }
diff --git a/init/property_service.h b/init/property_service.h
index d12f1f3..5bfa46c 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -17,12 +17,12 @@
 #ifndef _INIT_PROPERTY_H
 #define _INIT_PROPERTY_H
 
-extern void handle_property_fd(int fd);
-extern void handle_property_set_fd(int fd);
+extern void handle_property_set_fd(void);
 extern void property_init(void);
-extern int start_property_service(void);
+extern void start_property_service(void);
 void get_property_workspace(int *fd, int *sz);
 extern const char* property_get(const char *name);
 extern int property_set(const char *name, const char *value);
+int get_property_set_fd(void);
 
 #endif	/* _INIT_PROPERTY_H */
diff --git a/init/signal_handler.c b/init/signal_handler.c
new file mode 100644
index 0000000..b16eef1
--- /dev/null
+++ b/init/signal_handler.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <cutils/sockets.h>
+#include <sys/reboot.h>
+
+#include "init.h"
+#include "util.h"
+
+static int signal_fd = -1;
+static int signal_recv_fd = -1;
+
+static void sigchld_handler(int s)
+{
+    write(signal_fd, &s, 1);
+}
+
+void signal_init(void)
+{
+    int s[2];
+
+    struct sigaction act;
+
+    act.sa_handler = sigchld_handler;
+    act.sa_flags = SA_NOCLDSTOP;
+    act.sa_mask = 0;
+    act.sa_restorer = NULL;
+    sigaction(SIGCHLD, &act, 0);
+
+    /* create a signalling mechanism for the sigchld handler */
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {
+        signal_fd = s[0];
+        signal_recv_fd = s[1];
+        fcntl(s[0], F_SETFD, FD_CLOEXEC);
+        fcntl(s[0], F_SETFL, O_NONBLOCK);
+        fcntl(s[1], F_SETFD, FD_CLOEXEC);
+        fcntl(s[1], F_SETFL, O_NONBLOCK);
+    }
+}
+
+#define CRITICAL_CRASH_THRESHOLD    4       /* if we crash >4 times ... */
+#define CRITICAL_CRASH_WINDOW       (4*60)  /* ... in 4 minutes, goto recovery*/
+
+static int wait_for_one_process(int block)
+{
+    pid_t pid;
+    int status;
+    struct service *svc;
+    struct socketinfo *si;
+    time_t now;
+    struct listnode *node;
+    struct command *cmd;
+
+    while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR );
+    if (pid <= 0) return -1;
+    INFO("waitpid returned pid %d, status = %08x\n", pid, status);
+
+    svc = service_find_by_pid(pid);
+    if (!svc) {
+        ERROR("untracked pid %d exited\n", pid);
+        return 0;
+    }
+
+    NOTICE("process '%s', pid %d exited\n", svc->name, pid);
+
+    if (!(svc->flags & SVC_ONESHOT)) {
+        kill(-pid, SIGKILL);
+        NOTICE("process '%s' killing any children in process group\n", svc->name);
+    }
+
+    /* remove any sockets we may have created */
+    for (si = svc->sockets; si; si = si->next) {
+        char tmp[128];
+        snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);
+        unlink(tmp);
+    }
+
+    svc->pid = 0;
+    svc->flags &= (~SVC_RUNNING);
+
+        /* oneshot processes go into the disabled state on exit */
+    if (svc->flags & SVC_ONESHOT) {
+        svc->flags |= SVC_DISABLED;
+    }
+
+        /* disabled processes do not get restarted automatically */
+    if (svc->flags & SVC_DISABLED) {
+        notify_service_state(svc->name, "stopped");
+        return 0;
+    }
+
+    now = gettime();
+    if (svc->flags & SVC_CRITICAL) {
+        if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
+            if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
+                ERROR("critical process '%s' exited %d times in %d minutes; "
+                      "rebooting into recovery mode\n", svc->name,
+                      CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
+                sync();
+                __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
+                         LINUX_REBOOT_CMD_RESTART2, "recovery");
+                return 0;
+            }
+        } else {
+            svc->time_crashed = now;
+            svc->nr_crashed = 1;
+        }
+    }
+
+    svc->flags |= SVC_RESTARTING;
+
+    /* Execute all onrestart commands for this service. */
+    list_for_each(node, &svc->onrestart.commands) {
+        cmd = node_to_item(node, struct command, clist);
+        cmd->func(cmd->nargs, cmd->args);
+    }
+    notify_service_state(svc->name, "restarting");
+    return 0;
+}
+
+void handle_signal(void)
+{
+    char tmp[32];
+
+    /* we got a SIGCHLD - reap and restart as needed */
+    read(signal_recv_fd, tmp, sizeof(tmp));
+    while (!wait_for_one_process(0))
+        ;
+}
+
+int get_signal_fd()
+{
+    return signal_recv_fd;
+}
diff --git a/init/signal_handler.h b/init/signal_handler.h
new file mode 100644
index 0000000..b092ccb
--- /dev/null
+++ b/init/signal_handler.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_SIGNAL_HANDLER_H_
+#define _INIT_SIGNAL_HANDLER_H_
+
+void signal_init(void);
+void handle_signal(void);
+int get_signal_fd(void);
+
+#endif
diff --git a/init/util.c b/init/util.c
index 0b7667d..6f9a12e 100644
--- a/init/util.c
+++ b/init/util.c
@@ -21,6 +21,7 @@
 #include <fcntl.h>
 #include <ctype.h>
 #include <errno.h>
+#include <time.h>
 
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -209,3 +210,92 @@
     item->prev->next = item->next;
 }
 
+#define MAX_MTD_PARTITIONS 16
+
+static struct {
+    char name[16];
+    int number;
+} mtd_part_map[MAX_MTD_PARTITIONS];
+
+static int mtd_part_count = -1;
+
+static void find_mtd_partitions(void)
+{
+    int fd;
+    char buf[1024];
+    char *pmtdbufp;
+    ssize_t pmtdsize;
+    int r;
+
+    fd = open("/proc/mtd", O_RDONLY);
+    if (fd < 0)
+        return;
+
+    buf[sizeof(buf) - 1] = '\0';
+    pmtdsize = read(fd, buf, sizeof(buf) - 1);
+    pmtdbufp = buf;
+    while (pmtdsize > 0) {
+        int mtdnum, mtdsize, mtderasesize;
+        char mtdname[16];
+        mtdname[0] = '\0';
+        mtdnum = -1;
+        r = sscanf(pmtdbufp, "mtd%d: %x %x %15s",
+                   &mtdnum, &mtdsize, &mtderasesize, mtdname);
+        if ((r == 4) && (mtdname[0] == '"')) {
+            char *x = strchr(mtdname + 1, '"');
+            if (x) {
+                *x = 0;
+            }
+            INFO("mtd partition %d, %s\n", mtdnum, mtdname + 1);
+            if (mtd_part_count < MAX_MTD_PARTITIONS) {
+                strcpy(mtd_part_map[mtd_part_count].name, mtdname + 1);
+                mtd_part_map[mtd_part_count].number = mtdnum;
+                mtd_part_count++;
+            } else {
+                ERROR("too many mtd partitions\n");
+            }
+        }
+        while (pmtdsize > 0 && *pmtdbufp != '\n') {
+            pmtdbufp++;
+            pmtdsize--;
+        }
+        if (pmtdsize > 0) {
+            pmtdbufp++;
+            pmtdsize--;
+        }
+    }
+    close(fd);
+}
+
+int mtd_name_to_number(const char *name)
+{
+    int n;
+    if (mtd_part_count < 0) {
+        mtd_part_count = 0;
+        find_mtd_partitions();
+    }
+    for (n = 0; n < mtd_part_count; n++) {
+        if (!strcmp(name, mtd_part_map[n].name)) {
+            return mtd_part_map[n].number;
+        }
+    }
+    return -1;
+}
+
+/*
+ * gettime() - returns the time in seconds of the system's monotonic clock or
+ * zero on error.
+ */
+time_t gettime(void)
+{
+    struct timespec ts;
+    int ret;
+
+    ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+    if (ret < 0) {
+        ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno));
+        return 0;
+    }
+
+    return ts.tv_sec;
+}
diff --git a/init/util.h b/init/util.h
new file mode 100644
index 0000000..4f473ec
--- /dev/null
+++ b/init/util.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_UTIL_H_
+#define _INIT_UTIL_H_
+
+int mtd_name_to_number(const char *name);
+int create_socket(const char *name, int type, mode_t perm,
+                  uid_t uid, gid_t gid);
+void *read_file(const char *fn, unsigned *_sz);
+time_t gettime(void);
+unsigned int decode_uid(const char *s);
+
+#endif