am de35f274: am 03752be0: am 0c297f5e: Merge "Revert "Fold uevent message origin checking from init into libcutils.""

* commit 'de35f2741c4e32e331a92be99f7c04b92b94beb2':
  Revert "Fold uevent message origin checking from init into libcutils."
diff --git a/adb/adb.c b/adb/adb.c
index f5e6e0c..b0a70dc 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -36,6 +36,9 @@
 #include "usb_vendors.h"
 #endif
 
+#if ADB_TRACE
+ADB_MUTEX_DEFINE( D_lock );
+#endif
 
 int HOST = 0;
 
@@ -90,6 +93,7 @@
         { "sysdeps", TRACE_SYSDEPS },
         { "transport", TRACE_TRANSPORT },
         { "jdwp", TRACE_JDWP },
+        { "services", TRACE_SERVICES },
         { NULL, 0 }
     };
 
@@ -591,14 +595,6 @@
     return 0;
 }
 
-#ifdef HAVE_FORKEXEC
-static void sigchld_handler(int n)
-{
-    int status;
-    while(waitpid(-1, &status, WNOHANG) > 0) ;
-}
-#endif
-
 #ifdef HAVE_WIN32_PROC
 static BOOL WINAPI ctrlc_handler(DWORD type)
 {
@@ -641,6 +637,7 @@
 
     fd = unix_open("/dev/null", O_RDONLY);
     dup2(fd, 0);
+    adb_close(fd);
 
     fd = unix_open("/tmp/adb.log", O_WRONLY | O_CREAT | O_APPEND, 0640);
     if(fd < 0) {
@@ -648,6 +645,7 @@
     }
     dup2(fd, 1);
     dup2(fd, 2);
+    adb_close(fd);
     fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
 #endif
 }
@@ -807,9 +805,10 @@
         // wait for the "OK\n" message
         adb_close(fd[1]);
         int ret = adb_read(fd[0], temp, 3);
+        int saved_errno = errno;
         adb_close(fd[0]);
         if (ret < 0) {
-            fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", errno);
+            fprintf(stderr, "could not read ok from ADB Server, errno = %d\n", saved_errno);
             return -1;
         }
         if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
@@ -848,7 +847,7 @@
 #ifdef HAVE_WIN32_PROC
     SetConsoleCtrlHandler( ctrlc_handler, TRUE );
 #elif defined(HAVE_FORKEXEC)
-    signal(SIGCHLD, sigchld_handler);
+    // No SIGCHLD. Let the service subproc handle its children.
     signal(SIGPIPE, SIG_IGN);
 #endif
 
@@ -957,7 +956,9 @@
         // listen on default port
         local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
     }
+    D("adb_main(): pre init_jdwp()\n");
     init_jdwp();
+    D("adb_main(): post init_jdwp()\n");
 #endif
 
     if (is_daemon)
@@ -971,6 +972,7 @@
 #endif
         start_logging();
     }
+    D("Event loop starting\n");
 
     fdevent_loop();
 
@@ -1269,8 +1271,9 @@
 int main(int argc, char **argv)
 {
 #if ADB_HOST
-    adb_trace_init();
     adb_sysdeps_init();
+    adb_trace_init();
+    D("Handling commandline()\n");
     return adb_commandline(argc - 1, argv + 1);
 #else
     if((argc > 1) && (!strcmp(argv[1],"recovery"))) {
@@ -1279,6 +1282,7 @@
     }
 
     start_device_log();
+    D("Handling main()\n");
     return adb_main(0, DEFAULT_ADB_PORT);
 #endif
 }
diff --git a/adb/adb.h b/adb/adb.h
index 0aa98d3..2908f1e 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -19,6 +19,8 @@
 
 #include <limits.h>
 
+#include "transport.h"  /* readx(), writex() */
+
 #define MAX_PAYLOAD 4096
 
 #define A_SYNC 0x434e5953
@@ -315,13 +317,6 @@
 int check_header(apacket *p);
 int check_data(apacket *p);
 
-/* convenience wrappers around read/write that will retry on
-** EINTR and/or short read/write.  Returns 0 on success, -1
-** on error or EOF.
-*/
-int readx(int fd, void *ptr, size_t len);
-int writex(int fd, const void *ptr, size_t len);
-
 /* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */
 
 #define  ADB_TRACE    1
@@ -331,33 +326,56 @@
  * the adb_trace_init() function implemented in adb.c
  */
 typedef enum {
-    TRACE_ADB = 0,
+    TRACE_ADB = 0,   /* 0x001 */
     TRACE_SOCKETS,
     TRACE_PACKETS,
     TRACE_TRANSPORT,
-    TRACE_RWX,
+    TRACE_RWX,       /* 0x010 */
     TRACE_USB,
     TRACE_SYNC,
     TRACE_SYSDEPS,
-    TRACE_JDWP,
+    TRACE_JDWP,      /* 0x100 */
+    TRACE_SERVICES,
 } AdbTrace;
 
 #if ADB_TRACE
 
-  int     adb_trace_mask;
-
+  extern int     adb_trace_mask;
+  extern unsigned char    adb_trace_output_count;
   void    adb_trace_init(void);
 
 #  define ADB_TRACING  ((adb_trace_mask & (1 << TRACE_TAG)) != 0)
 
   /* you must define TRACE_TAG before using this macro */
-  #define  D(...)                                      \
+#  define  D(...)                                      \
         do {                                           \
-            if (ADB_TRACING)                           \
+            if (ADB_TRACING) {                         \
+                int save_errno = errno;                \
+                adb_mutex_lock(&D_lock);               \
+                fprintf(stderr, "%s::%s():",           \
+                        __FILE__, __FUNCTION__);       \
+                errno = save_errno;                    \
                 fprintf(stderr, __VA_ARGS__ );         \
+                fflush(stderr);                        \
+                adb_mutex_unlock(&D_lock);             \
+                errno = save_errno;                    \
+           }                                           \
+        } while (0)
+#  define  DR(...)                                     \
+        do {                                           \
+            if (ADB_TRACING) {                         \
+                int save_errno = errno;                \
+                adb_mutex_lock(&D_lock);               \
+                errno = save_errno;                    \
+                fprintf(stderr, __VA_ARGS__ );         \
+                fflush(stderr);                        \
+                adb_mutex_unlock(&D_lock);             \
+                errno = save_errno;                    \
+           }                                           \
         } while (0)
 #else
 #  define  D(...)          ((void)0)
+#  define  DR(...)         ((void)0)
 #  define  ADB_TRACING     0
 #endif
 
@@ -413,6 +431,7 @@
 #define CS_NOPERM     5 /* Insufficient permissions to communicate with the device */
 
 extern int HOST;
+extern int SHELL_EXIT_NOTIFY_FD;
 
 #define CHUNK_SIZE (64*1024)
 
diff --git a/adb/adb_client.c b/adb/adb_client.c
index 882810a..9a812f0 100644
--- a/adb/adb_client.c
+++ b/adb/adb_client.c
@@ -202,6 +202,7 @@
         return -1;
     }
 
+    D("_adb_connect: return fd %d\n", fd);
     return fd;
 }
 
@@ -210,6 +211,7 @@
     // first query the adb server's version
     int fd = _adb_connect("host:version");
 
+    D("adb_connect: service %s\n", service);
     if(fd == -2) {
         fprintf(stdout,"* daemon not running. starting it now on port %d *\n",
                 __adb_server_port);
@@ -266,6 +268,7 @@
     if(fd == -2) {
         fprintf(stderr,"** daemon still not running");
     }
+    D("adb_connect: return fd %d\n", fd);
 
     return fd;
 error:
diff --git a/adb/commandline.c b/adb/commandline.c
index b0c2b80..0f9fc31 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -37,12 +37,6 @@
 #include "adb_client.h"
 #include "file_sync_service.h"
 
-enum {
-    IGNORE_DATA,
-    WIPE_DATA,
-    FLASH_DATA
-};
-
 static int do_cmd(transport_type ttype, char* serial, char *cmd, ...);
 
 void get_my_path(char *s, size_t maxLen);
@@ -138,11 +132,6 @@
         "  adb help                     - show this help message\n"
         "  adb version                  - show version num\n"
         "\n"
-        "DATAOPTS:\n"
-        " (no option)                   - don't touch the data partition\n"
-        "  -w                           - wipe the data partition\n"
-        "  -d                           - flash the data partition\n"
-        "\n"
         "scripting:\n"
         "  adb wait-for-device          - block until device is online\n"
         "  adb start-server             - ensure that there is a server running\n"
@@ -218,7 +207,9 @@
     int len;
 
     while(fd >= 0) {
+        D("read_and_dump(): pre adb_read(fd=%d)\n", fd);
         len = adb_read(fd, buf, 4096);
+        D("read_and_dump(): post adb_read(fd=%d): len=%d\n", fd, len);
         if(len == 0) {
             break;
         }
@@ -246,7 +237,9 @@
 
     for(;;) {
         /* fdi is really the client's stdin, so use read, not adb_read here */
+        D("stdin_read_thread(): pre unix_read(fdi=%d,...)\n", fdi);
         r = unix_read(fdi, buf, 1024);
+        D("stdin_read_thread(): post unix_read(fdi=%d,...)\n", fdi);
         if(r == 0) break;
         if(r < 0) {
             if(errno == EINTR) continue;
@@ -853,6 +846,7 @@
         }
 
         if(argc < 2) {
+            D("starting interactive shell\n");
             r = interactive_shell();
             if (h) {
                 printf("\x1b[0m");
@@ -877,9 +871,12 @@
         }
 
         for(;;) {
+            D("interactive shell loop. buff=%s\n", buf);
             fd = adb_connect(buf);
             if(fd >= 0) {
+                D("about to read_and_dump(fd=%d)\n", fd);
                 read_and_dump(fd);
+                D("read_and_dump() done.\n");
                 adb_close(fd);
                 r = 0;
             } else {
@@ -896,6 +893,7 @@
                     printf("\x1b[0m");
                     fflush(stdout);
                 }
+                D("interactive shell loop. return r=%d\n", r);
                 return r;
             }
         }
diff --git a/adb/fdevent.c b/adb/fdevent.c
index c179b20..5c374a7 100644
--- a/adb/fdevent.c
+++ b/adb/fdevent.c
@@ -15,6 +15,8 @@
 ** limitations under the License.
 */
 
+#include <sys/ioctl.h>
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -27,10 +29,20 @@
 #include <stddef.h>
 
 #include "fdevent.h"
+#include "transport.h"
+#include "sysdeps.h"
 
-#define TRACE(x...) fprintf(stderr,x)
 
-#define DEBUG 0
+/* !!! Do not enable DEBUG for the adb that will run as the server:
+** both stdout and stderr are used to communicate between the client
+** and server. Any extra output will cause failures.
+*/
+#define DEBUG 0   /* non-0 will break adb server */
+
+// This socket is used when a subproc shell service exists.
+// It wakes up the fdevent_loop() and cause the correct handling
+// of the shell's pseudo-tty master. I.e. force close it.
+int SHELL_EXIT_NOTIFY_FD = -1;
 
 static void fatal(const char *fn, const char *fmt, ...)
 {
@@ -45,15 +57,28 @@
 #define FATAL(x...) fatal(__FUNCTION__, x)
 
 #if DEBUG
+#define D(...) \
+    do { \
+        adb_mutex_lock(&D_lock);               \
+        int save_errno = errno;                \
+        fprintf(stderr, "%s::%s():", __FILE__, __FUNCTION__);  \
+        errno = save_errno;                    \
+        fprintf(stderr, __VA_ARGS__);          \
+        adb_mutex_unlock(&D_lock);             \
+        errno = save_errno;                    \
+    } while(0)
 static void dump_fde(fdevent *fde, const char *info)
 {
+    adb_mutex_lock(&D_lock);
     fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd,
             fde->state & FDE_READ ? 'R' : ' ',
             fde->state & FDE_WRITE ? 'W' : ' ',
             fde->state & FDE_ERROR ? 'E' : ' ',
             info);
+    adb_mutex_unlock(&D_lock);
 }
 #else
+#define D(...) ((void)0)
 #define dump_fde(fde, info) do { } while(0)
 #endif
 
@@ -67,6 +92,7 @@
 static void fdevent_plist_enqueue(fdevent *node);
 static void fdevent_plist_remove(fdevent *node);
 static fdevent *fdevent_plist_dequeue(void);
+static void fdevent_subproc_event_func(int fd, unsigned events, void *userdata);
 
 static fdevent list_pending = {
     .next = &list_pending,
@@ -270,9 +296,72 @@
         FD_CLR(fde->fd, &error_fds);
     }
 
-    fde->state = (fde->state & FDE_STATEMASK) | events;    
+    fde->state = (fde->state & FDE_STATEMASK) | events;
 }
 
+/* Looks at fd_table[] for bad FDs and sets bit in fds.
+** Returns the number of bad FDs.
+*/
+static int fdevent_fd_check(fd_set *fds)
+{
+    int i, n = 0;
+    fdevent *fde;
+
+    for(i = 0; i < select_n; i++) {
+        fde = fd_table[i];
+        if(fde == 0) continue;
+        if(fcntl(i, F_GETFL, NULL) < 0) {
+            FD_SET(i, fds);
+            n++;
+            // fde->state |= FDE_DONT_CLOSE;
+
+        }
+    }
+    return n;
+}
+
+#if !DEBUG
+static inline void dump_all_fds(const char *extra_msg) {}
+#else
+static void dump_all_fds(const char *extra_msg)
+{
+int i;
+    fdevent *fde;
+    // per fd: 4 digits (but really: log10(FD_SETSIZE)), 1 staus, 1 blank
+    char msg_buff[FD_SETSIZE*6 + 1], *pb=msg_buff;
+    size_t max_chars = FD_SETSIZE * 6 + 1;
+    int printed_out;
+#define SAFE_SPRINTF(...)                                                    \
+    do {                                                                     \
+        printed_out = snprintf(pb, max_chars, __VA_ARGS__);                  \
+        if (printed_out <= 0) {                                              \
+            D("... snprintf failed.\n");                                     \
+            return;                                                          \
+        }                                                                    \
+        if (max_chars < (unsigned int)printed_out) {                         \
+            D("... snprintf out of space.\n");                               \
+            return;                                                          \
+        }                                                                    \
+        pb += printed_out;                                                   \
+        max_chars -= printed_out;                                            \
+    } while(0)
+
+    for(i = 0; i < select_n; i++) {
+        fde = fd_table[i];
+        SAFE_SPRINTF("%d", i);
+        if(fde == 0) {
+            SAFE_SPRINTF("? ");
+            continue;
+        }
+        if(fcntl(i, F_GETFL, NULL) < 0) {
+            SAFE_SPRINTF("b");
+        }
+        SAFE_SPRINTF(" ");
+    }
+    D("%s fd_table[]->fd = {%s}\n", extra_msg, msg_buff);
+}
+#endif
+
 static void fdevent_process()
 {
     int i, n;
@@ -284,28 +373,49 @@
     memcpy(&wfd, &write_fds, sizeof(fd_set));
     memcpy(&efd, &error_fds, sizeof(fd_set));
 
-    n = select(select_n, &rfd, &wfd, &efd, 0);
+    dump_all_fds("pre select()");
+
+    n = select(select_n, &rfd, &wfd, &efd, NULL);
+    int saved_errno = errno;
+    D("select() returned n=%d, errno=%d\n", n, n<0?saved_errno:0);
+
+    dump_all_fds("post select()");
 
     if(n < 0) {
-        if(errno == EINTR) return;
-        perror("select");
-        return;
+        switch(saved_errno) {
+        case EINTR: return;
+        case EBADF:
+            // Can't trust the FD sets after an error.
+            FD_ZERO(&wfd);
+            FD_ZERO(&efd);
+            FD_ZERO(&rfd);
+            break;
+        default:
+            D("Unexpected select() error=%d\n", saved_errno);
+            return;
+        }
+    }
+    if(n <= 0) {
+        // We fake a read, as the rest of the code assumes
+        // that errors will be detected at that point.
+        n = fdevent_fd_check(&rfd);
     }
 
     for(i = 0; (i < select_n) && (n > 0); i++) {
         events = 0;
-        if(FD_ISSET(i, &rfd)) events |= FDE_READ;
-        if(FD_ISSET(i, &wfd)) events |= FDE_WRITE;
-        if(FD_ISSET(i, &efd)) events |= FDE_ERROR;
+        if(FD_ISSET(i, &rfd)) { events |= FDE_READ; n--; }
+        if(FD_ISSET(i, &wfd)) { events |= FDE_WRITE; n--; }
+        if(FD_ISSET(i, &efd)) { events |= FDE_ERROR; n--; }
 
         if(events) {
-            n--;
-
             fde = fd_table[i];
-            if(fde == 0) FATAL("missing fde for fd %d\n", i);
+            if(fde == 0)
+              FATAL("missing fde for fd %d\n", i);
 
             fde->events |= events;
 
+            D("got events fde->fd=%d events=%04x, state=%04x\n",
+                fde->fd, fde->events, fde->state);
             if(fde->state & FDE_PENDING) continue;
             fde->state |= FDE_PENDING;
             fdevent_plist_enqueue(fde);
@@ -350,14 +460,14 @@
     }
 
     if(fd_table[fde->fd] != fde) {
-        FATAL("fd_table out of sync");
+        FATAL("fd_table out of sync [%d]\n", fde->fd);
     }
 
     fd_table[fde->fd] = 0;
 
     if(!(fde->state & FDE_DONT_CLOSE)) {
         dump_fde(fde, "close");
-        close(fde->fd);
+        adb_close(fde->fd);
     }
 }
 
@@ -394,6 +504,74 @@
     return node;
 }
 
+static void fdevent_call_fdfunc(fdevent* fde)
+{
+    unsigned events = fde->events;
+    fde->events = 0;
+    if(!(fde->state & FDE_PENDING)) return;
+    fde->state &= (~FDE_PENDING);
+    dump_fde(fde, "callback");
+    fde->func(fde->fd, events, fde->arg);
+}
+
+static void fdevent_subproc_event_func(int fd, unsigned ev, void *userdata)
+{
+
+    D("subproc handling on fd=%d ev=%04x\n", fd, ev);
+
+    // Hook oneself back into the fde's suitable for select() on read.
+    if((fd < 0) || (fd >= fd_table_max)) {
+        FATAL("fd %d out of range for fd_table \n", fd);
+    }
+    fdevent *fde = fd_table[fd];
+    fdevent_add(fde, FDE_READ);
+
+    if(ev & FDE_READ){
+      int subproc_fd;
+
+      if(readx(fd, &subproc_fd, sizeof(subproc_fd))) {
+          FATAL("Failed to read the subproc's fd from fd=%d\n", fd);
+      }
+      if((subproc_fd < 0) || (subproc_fd >= fd_table_max)) {
+          D("subproc_fd %d out of range 0, fd_table_max=%d\n",
+            subproc_fd, fd_table_max);
+          return;
+      }
+      fdevent *subproc_fde = fd_table[subproc_fd];
+      if(!subproc_fde) {
+          D("subproc_fd %d cleared from fd_table\n", subproc_fd);
+          return;
+      }
+      if(subproc_fde->fd != subproc_fd) {
+          // Already reallocated?
+          D("subproc_fd %d != fd_table[].fd %d\n", subproc_fd, subproc_fde->fd);
+          return;
+      }
+
+      subproc_fde->force_eof = 1;
+
+      int rcount = 0;
+      ioctl(subproc_fd, FIONREAD, &rcount);
+      D("subproc with fd=%d  has rcount=%d err=%d\n",
+        subproc_fd, rcount, errno);
+
+      if(rcount) {
+        // If there is data left, it will show up in the select().
+        // This works because there is no other thread reading that
+        // data when in this fd_func().
+        return;
+      }
+
+      D("subproc_fde.state=%04x\n", subproc_fde->state);
+      subproc_fde->events |= FDE_READ;
+      if(subproc_fde->state & FDE_PENDING) {
+        return;
+      }
+      subproc_fde->state |= FDE_PENDING;
+      fdevent_call_fdfunc(subproc_fde);
+    }
+}
+
 fdevent *fdevent_create(int fd, fd_func func, void *arg)
 {
     fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
@@ -412,11 +590,12 @@
     fdevent_remove(fde);
 }
 
-void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg) 
+void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
 {
     memset(fde, 0, sizeof(fdevent));
     fde->state = FDE_ACTIVE;
     fde->fd = fd;
+    fde->force_eof = 0;
     fde->func = func;
     fde->arg = arg;
 
@@ -437,7 +616,7 @@
 
     if(fde->state & FDE_ACTIVE) {
         fdevent_disconnect(fde);
-        dump_fde(fde, "disconnect");    
+        dump_fde(fde, "disconnect");
         fdevent_unregister(fde);
     }
 
@@ -484,23 +663,33 @@
         fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
 }
 
+void fdevent_subproc_setup()
+{
+    int s[2];
+
+    if(adb_socketpair(s)) {
+        FATAL("cannot create shell-exit socket-pair\n");
+    }
+    SHELL_EXIT_NOTIFY_FD = s[0];
+    fdevent *fde;
+    fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL);
+    if(!fde)
+      FATAL("cannot create fdevent for shell-exit handler\n");
+    fdevent_add(fde, FDE_READ);
+}
+
 void fdevent_loop()
 {
     fdevent *fde;
+    fdevent_subproc_setup();
 
     for(;;) {
-#if DEBUG
-        fprintf(stderr,"--- ---- waiting for events\n");
-#endif
+        D("--- ---- waiting for events\n");
+
         fdevent_process();
 
         while((fde = fdevent_plist_dequeue())) {
-            unsigned events = fde->events;
-            fde->events = 0;
-            fde->state &= (~FDE_PENDING);
-            dump_fde(fde, "callback");
-            fde->func(fde->fd, events, fde->arg);
+            fdevent_call_fdfunc(fde);
         }
     }
 }
-
diff --git a/adb/fdevent.h b/adb/fdevent.h
index 6b7e7ec..a0ebe2a 100644
--- a/adb/fdevent.h
+++ b/adb/fdevent.h
@@ -70,6 +70,8 @@
     fdevent *prev;
 
     int fd;
+    int force_eof;
+
     unsigned short state;
     unsigned short events;
 
diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c
index 5c7a26f..64e393c 100644
--- a/adb/file_sync_client.c
+++ b/adb/file_sync_client.c
@@ -641,8 +641,9 @@
         } else {
             ci = mkcopyinfo(lpath, rpath, name, 0);
             if(lstat(ci->src, &st)) {
-                closedir(d);
                 fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
+                closedir(d);
+
                 return -1;
             }
             if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
diff --git a/adb/file_sync_service.c b/adb/file_sync_service.c
index a231e93..d3e841b 100644
--- a/adb/file_sync_service.c
+++ b/adb/file_sync_service.c
@@ -193,9 +193,11 @@
         if(fd < 0)
             continue;
         if(writex(fd, buffer, len)) {
+            int saved_errno = errno;
             adb_close(fd);
             adb_unlink(path);
             fd = -1;
+            errno = saved_errno;
             if(fail_errno(s)) return -1;
         }
     }
diff --git a/adb/mutex_list.h b/adb/mutex_list.h
index eebe0df..652dd73 100644
--- a/adb/mutex_list.h
+++ b/adb/mutex_list.h
@@ -1,8 +1,11 @@
-/* the list of mutexes used by addb */
+/* the list of mutexes used by adb */
+/* #ifndef __MUTEX_LIST_H
+ * Do not use an include-guard. This file is included once to declare the locks
+ * and once in win32 to actually do the runtime initialization.
+ */
 #ifndef ADB_MUTEX
 #error ADB_MUTEX not defined when including this file
 #endif
-
 ADB_MUTEX(dns_lock)
 ADB_MUTEX(socket_list_lock)
 ADB_MUTEX(transport_lock)
@@ -11,4 +14,13 @@
 #endif
 ADB_MUTEX(usb_lock)
 
+// Sadly logging to /data/adb/adb-... is not thread safe.
+//  After modifying adb.h::D() to count invocations:
+//   DEBUG(jpa):0:Handling main()
+//   DEBUG(jpa):1:[ usb_init - starting thread ]
+// (Oopsies, no :2:, and matching message is also gone.)
+//   DEBUG(jpa):3:[ usb_thread - opening device ]
+//   DEBUG(jpa):4:jdwp control socket started (10)
+ADB_MUTEX(D_lock)
+
 #undef ADB_MUTEX
diff --git a/adb/services.c b/adb/services.c
index 7eab17a..43f9174 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -22,7 +22,7 @@
 
 #include "sysdeps.h"
 
-#define  TRACE_TAG  TRACE_ADB
+#define  TRACE_TAG  TRACE_SERVICES
 #include "adb.h"
 #include "file_sync_service.h"
 
@@ -30,6 +30,7 @@
 #  ifndef HAVE_WINSOCK
 #    include <netinet/in.h>
 #    include <netdb.h>
+#    include <sys/ioctl.h>
 #  endif
 #else
 #  include <cutils/android_reboot.h>
@@ -267,15 +268,16 @@
     return s[0];
 }
 
-static int create_subprocess(const char *cmd, const char *arg0, const char *arg1)
+#if !ADB_HOST
+static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
 {
 #ifdef HAVE_WIN32_PROC
-	fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
-	return -1;
+    D("create_subprocess(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
+    fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
+    return -1;
 #else /* !HAVE_WIN32_PROC */
     char *devname;
     int ptm;
-    pid_t pid;
 
     ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
     if(ptm < 0){
@@ -287,22 +289,27 @@
     if(grantpt(ptm) || unlockpt(ptm) ||
        ((devname = (char*) ptsname(ptm)) == 0)){
         printf("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
+        adb_close(ptm);
         return -1;
     }
 
-    pid = fork();
-    if(pid < 0) {
+    *pid = fork();
+    if(*pid < 0) {
         printf("- fork failed: %s -\n", strerror(errno));
+        adb_close(ptm);
         return -1;
     }
 
-    if(pid == 0){
+    if(*pid == 0){
         int pts;
 
         setsid();
 
         pts = unix_open(devname, O_RDWR);
-        if(pts < 0) exit(-1);
+        if(pts < 0) {
+            fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
+            exit(-1);
+        }
 
         dup2(pts, 0);
         dup2(pts, 1);
@@ -311,15 +318,9 @@
         adb_close(pts);
         adb_close(ptm);
 
-        execl(cmd, cmd, arg0, arg1, NULL);
-        fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
-                cmd, strerror(errno), errno);
-        exit(-1);
-    } else {
-#if !ADB_HOST
-        // set child's OOM adjustment to zero
+        // set OOM adjustment to zero
         char text[64];
-        snprintf(text, sizeof text, "/proc/%d/oom_adj", pid);
+        snprintf(text, sizeof text, "/proc/%d/oom_adj", getpid());
         int fd = adb_open(text, O_WRONLY);
         if (fd >= 0) {
             adb_write(fd, "0", 1);
@@ -327,11 +328,20 @@
         } else {
            D("adb: unable to open %s\n", text);
         }
-#endif
+        execl(cmd, cmd, arg0, arg1, NULL);
+        fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
+                cmd, strerror(errno), errno);
+        exit(-1);
+    } else {
+        // Don't set child's OOM adjustment to zero.
+        // Let the child do it itself, as sometimes the parent starts
+        // running before the child has a /proc/pid/oom_adj.
+        // """adb: unable to open /proc/644/oom_adj""" seen in some logs.
         return ptm;
     }
 #endif /* !HAVE_WIN32_PROC */
 }
+#endif  /* !ABD_HOST */
 
 #if ADB_HOST
 #define SHELL_COMMAND "/bin/sh"
@@ -339,6 +349,70 @@
 #define SHELL_COMMAND "/system/bin/sh"
 #endif
 
+#if !ADB_HOST
+static void subproc_waiter_service(int fd, void *cookie)
+{
+    pid_t pid = (pid_t)cookie;
+
+    D("entered. fd=%d of pid=%d\n", fd, pid);
+    for (;;) {
+        int status;
+        pid_t p = waitpid(pid, &status, 0);
+        if (p == pid) {
+            D("fd=%d, post waitpid(pid=%d) status=%04x\n", fd, p, status);
+            if (WIFSIGNALED(status)) {
+                D("*** Killed by signal %d\n", WTERMSIG(status));
+                break;
+            } else if (!WIFEXITED(status)) {
+                D("*** Didn't exit!!. status %d\n", status);
+                break;
+            } else if (WEXITSTATUS(status) >= 0) {
+                D("*** Exit code %d\n", WEXITSTATUS(status));
+                break;
+            }
+         }
+        usleep(100000);  // poll every 0.1 sec
+    }
+    D("shell exited fd=%d of pid=%d err=%d\n", fd, pid, errno);
+    if (SHELL_EXIT_NOTIFY_FD >=0) {
+      int res;
+      res = writex(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd));
+      D("notified shell exit via fd=%d for pid=%d res=%d errno=%d\n",
+        SHELL_EXIT_NOTIFY_FD, pid, res, errno);
+    }
+}
+
+static int create_subproc_thread(const char *name)
+{
+    stinfo *sti;
+    adb_thread_t t;
+    int ret_fd;
+    pid_t pid;
+    if(name) {
+        ret_fd = create_subprocess(SHELL_COMMAND, "-c", name, &pid);
+    } else {
+        ret_fd = create_subprocess(SHELL_COMMAND, "-", 0, &pid);
+    }
+    D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid);
+
+    sti = malloc(sizeof(stinfo));
+    if(sti == 0) fatal("cannot allocate stinfo");
+    sti->func = subproc_waiter_service;
+    sti->cookie = (void*)pid;
+    sti->fd = ret_fd;
+
+    if(adb_thread_create( &t, service_bootstrap_func, sti)){
+        free(sti);
+        adb_close(ret_fd);
+        printf("cannot create service thread\n");
+        return -1;
+    }
+
+    D("service thread started, fd=%d pid=%d\n",ret_fd, pid);
+    return ret_fd;
+}
+#endif
+
 int service_to_fd(const char *name)
 {
     int ret = -1;
@@ -389,14 +463,12 @@
         ret = create_jdwp_connection_fd(atoi(name+5));
     } else if (!strncmp(name, "log:", 4)) {
         ret = create_service_thread(log_service, get_log_file_path(name + 4));
-#endif
     } else if(!HOST && !strncmp(name, "shell:", 6)) {
         if(name[6]) {
-            ret = create_subprocess(SHELL_COMMAND, "-c", name + 6);
+            ret = create_subproc_thread(name + 6);
         } else {
-            ret = create_subprocess(SHELL_COMMAND, "-", 0);
+            ret = create_subproc_thread(0);
         }
-#if !ADB_HOST
     } else if(!strncmp(name, "sync:", 5)) {
         ret = create_service_thread(file_sync_service, NULL);
     } else if(!strncmp(name, "remount:", 8)) {
diff --git a/adb/sockets.c b/adb/sockets.c
index aa4d5fc..45d935c 100644
--- a/adb/sockets.c
+++ b/adb/sockets.c
@@ -199,6 +199,7 @@
 static void local_socket_destroy(asocket  *s)
 {
     apacket *p, *n;
+    D("LS(%d): destroying fde.fd=%d\n", s->id, s->fde.fd);
 
         /* IMPORTANT: the remove closes the fd
         ** that belongs to this socket
@@ -218,7 +219,10 @@
 
 static void local_socket_close_locked(asocket *s)
 {
+    D("entered. LS(%d) fd=%d\n", s->id, s->fd);
     if(s->peer) {
+        D("LS(%d): closing peer. peer->id=%d peer->fd=%d\n",
+          s->id, s->peer->id, s->peer->fd);
         s->peer->peer = 0;
         // tweak to avoid deadlock
         if (s->peer->close == local_socket_close)
@@ -243,6 +247,7 @@
     s->closing = 1;
     fdevent_del(&s->fde, FDE_READ);
     remove_socket(s);
+    D("LS(%d): put on socket_closing_list fd=%d\n", s->id, s->fd);
     insert_local_socket(s, &local_socket_closing_list);
 }
 
@@ -250,6 +255,8 @@
 {
     asocket *s = _s;
 
+    D("LS(%d): event_func(fd=%d(==%d), ev=%04x)\n", s->id, s->fd, fd, ev);
+
     /* put the FDE_WRITE processing before the FDE_READ
     ** in order to simplify the code.
     */
@@ -308,6 +315,7 @@
 
         while(avail > 0) {
             r = adb_read(fd, x, avail);
+            D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%d\n", s->id, s->fd, r, r<0?errno:0, avail);
             if(r > 0) {
                 avail -= r;
                 x += r;
@@ -322,13 +330,15 @@
             is_eof = 1;
             break;
         }
-
+        D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d\n",
+          s->id, s->fd, r, is_eof, s->fde.force_eof);
         if((avail == MAX_PAYLOAD) || (s->peer == 0)) {
             put_apacket(p);
         } else {
             p->len = MAX_PAYLOAD - avail;
 
             r = s->peer->enqueue(s->peer, p);
+            D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd, r);
 
             if(r < 0) {
                     /* error return means they closed us as a side-effect
@@ -350,8 +360,8 @@
                 fdevent_del(&s->fde, FDE_READ);
             }
         }
-
-        if(is_eof) {
+        /* Don't allow a forced eof if data is still there */
+        if((s->fde.force_eof && !r) || is_eof) {
             s->close(s);
         }
     }
@@ -362,6 +372,8 @@
             ** bytes of readable data.
             */
 //        s->close(s);
+        D("LS(%d): FDE_ERROR (fd=%d)\n", s->id, s->fd);
+
         return;
     }
 }
@@ -370,11 +382,11 @@
 {
     asocket *s = calloc(1, sizeof(asocket));
     if (s == NULL) fatal("cannot allocate socket");
-    install_local_socket(s);
     s->fd = fd;
     s->enqueue = local_socket_enqueue;
     s->ready = local_socket_ready;
     s->close = local_socket_close;
+    install_local_socket(s);
 
     fdevent_install(&s->fde, fd, local_socket_event_func, s);
 /*    fdevent_add(&s->fde, FDE_ERROR); */
@@ -400,7 +412,7 @@
     if(fd < 0) return 0;
 
     s = create_local_socket(fd);
-    D("LS(%d): bound to '%s'\n", s->id, name);
+    D("LS(%d): bound to '%s' via %d\n", s->id, name, fd);
     return s;
 }
 
@@ -430,7 +442,8 @@
 
 static int remote_socket_enqueue(asocket *s, apacket *p)
 {
-    D("Calling remote_socket_enqueue\n");
+    D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d\n",
+      s->id, s->fd, s->peer->fd);
     p->msg.command = A_WRTE;
     p->msg.arg0 = s->peer->id;
     p->msg.arg1 = s->id;
@@ -441,7 +454,8 @@
 
 static void remote_socket_ready(asocket *s)
 {
-    D("Calling remote_socket_ready\n");
+    D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d\n",
+      s->id, s->fd, s->peer->fd);
     apacket *p = get_apacket();
     p->msg.command = A_OKAY;
     p->msg.arg0 = s->peer->id;
@@ -451,12 +465,15 @@
 
 static void remote_socket_close(asocket *s)
 {
-    D("Calling remote_socket_close\n");
+    D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d\n",
+      s->id, s->fd, s->peer?s->peer->fd:-1);
     apacket *p = get_apacket();
     p->msg.command = A_CLSE;
     if(s->peer) {
         p->msg.arg0 = s->peer->id;
         s->peer->peer = 0;
+        D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d\n",
+          s->id, s->peer->id, s->peer->fd);
         s->peer->close(s->peer);
     }
     p->msg.arg1 = s->id;
@@ -501,7 +518,7 @@
 
 void connect_to_remote(asocket *s, const char *destination)
 {
-    D("Connect_to_remote call \n");
+    D("Connect_to_remote call RS(%d) fd=%d\n", s->id, s->fd);
     apacket *p = get_apacket();
     int len = strlen(destination) + 1;
 
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 74f4ed1..b518076 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -44,6 +44,7 @@
 #define  ADB_MUTEX_DEFINE(x)     adb_mutex_t   x
 
 /* declare all mutexes */
+/* For win32, adb_sysdeps_init() will do the mutex runtime initialization. */
 #define  ADB_MUTEX(x)   extern adb_mutex_t  x;
 #include "mutex_list.h"
 
@@ -195,6 +196,8 @@
     fdevent *prev;
 
     int fd;
+    int force_eof;
+
     unsigned short state;
     unsigned short events;
 
@@ -274,13 +277,14 @@
 #define OS_PATH_SEPARATOR_STR "/"
 
 typedef  pthread_mutex_t          adb_mutex_t;
+
 #define  ADB_MUTEX_INITIALIZER    PTHREAD_MUTEX_INITIALIZER
 #define  adb_mutex_init           pthread_mutex_init
 #define  adb_mutex_lock           pthread_mutex_lock
 #define  adb_mutex_unlock         pthread_mutex_unlock
 #define  adb_mutex_destroy        pthread_mutex_destroy
 
-#define  ADB_MUTEX_DEFINE(m)      static adb_mutex_t   m = PTHREAD_MUTEX_INITIALIZER
+#define  ADB_MUTEX_DEFINE(m)      adb_mutex_t   m = PTHREAD_MUTEX_INITIALIZER
 
 #define  adb_cond_t               pthread_cond_t
 #define  adb_cond_init            pthread_cond_init
@@ -289,6 +293,10 @@
 #define  adb_cond_signal          pthread_cond_signal
 #define  adb_cond_destroy         pthread_cond_destroy
 
+/* declare all mutexes */
+#define  ADB_MUTEX(x)   extern adb_mutex_t  x;
+#include "mutex_list.h"
+
 static __inline__ void  close_on_exec(int  fd)
 {
     fcntl( fd, F_SETFD, FD_CLOEXEC );
diff --git a/adb/transport.c b/adb/transport.c
index 2baf340..83a349a 100644
--- a/adb/transport.c
+++ b/adb/transport.c
@@ -35,24 +35,30 @@
 ADB_MUTEX_DEFINE( transport_lock );
 
 #if ADB_TRACE
+#define MAX_DUMP_HEX_LEN 16
 static void  dump_hex( const unsigned char*  ptr, size_t  len )
 {
     int  nn, len2 = len;
+    // Build a string instead of logging each character.
+    // MAX chars in 2 digit hex, one space, MAX chars, one '\0'.
+    char buffer[MAX_DUMP_HEX_LEN *2 + 1 + MAX_DUMP_HEX_LEN + 1 ], *pb = buffer;
 
-    if (len2 > 16) len2 = 16;
+    if (len2 > MAX_DUMP_HEX_LEN) len2 = MAX_DUMP_HEX_LEN;
 
-    for (nn = 0; nn < len2; nn++)
-        D("%02x", ptr[nn]);
-    D("  ");
+    for (nn = 0; nn < len2; nn++) {
+        sprintf(pb, "%02x", ptr[nn]);
+        pb += 2;
+    }
+    sprintf(pb++, " ");
 
     for (nn = 0; nn < len2; nn++) {
         int  c = ptr[nn];
         if (c < 32 || c > 127)
             c = '.';
-        D("%c", c);
+        *pb++ =  c;
     }
-    D("\n");
-    fflush(stdout);
+    *pb++ = '\0';
+    DR("%s\n", buffer);
 }
 #endif
 
@@ -192,6 +198,7 @@
 static void transport_socket_events(int fd, unsigned events, void *_t)
 {
     atransport *t = _t;
+    D("transport_socket_events(fd=%d, events=%04x,...)\n", fd, events);
     if(events & FDE_READ){
         apacket *p = 0;
         if(read_packet(fd, t->serial, &p)){
@@ -221,8 +228,10 @@
     print_packet("send", p);
 
     if (t == NULL) {
-        fatal_errno("Transport is null");
         D("Transport is null \n");
+        // Zap errno because print_packet() and other stuff have errno effect.
+        errno = 0;
+        fatal_errno("Transport is null");
     }
 
     if(write_packet(t->transport_socket, t->serial, &p)){
@@ -1069,4 +1078,3 @@
         return 0;
     }
 }
-
diff --git a/adb/transport.h b/adb/transport.h
new file mode 100644
index 0000000..992e052
--- /dev/null
+++ b/adb/transport.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2011 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 __TRANSPORT_H
+#define __TRANSPORT_H
+
+/* convenience wrappers around read/write that will retry on
+** EINTR and/or short read/write.  Returns 0 on success, -1
+** on error or EOF.
+*/
+int readx(int fd, void *ptr, size_t len);
+int writex(int fd, const void *ptr, size_t len);
+#endif   /* __TRANSPORT_H */
diff --git a/adb/usb_linux.c b/adb/usb_linux.c
index cd61083..b7ee4ec 100644
--- a/adb/usb_linux.c
+++ b/adb/usb_linux.c
@@ -45,7 +45,7 @@
 /* usb scan debugging is waaaay too verbose */
 #define DBGX(x...)
 
-static adb_mutex_t usb_lock = ADB_MUTEX_INITIALIZER;
+ADB_MUTEX_DEFINE( usb_lock );
 
 struct usb_handle
 {
@@ -369,6 +369,7 @@
         h->reaper_thread = pthread_self();
         adb_mutex_unlock(&h->lock);
         res = ioctl(h->desc, USBDEVFS_REAPURB, &out);
+        int saved_errno = errno;
         adb_mutex_lock(&h->lock);
         h->reaper_thread = 0;
         if(h->dead) {
@@ -376,7 +377,7 @@
             break;
         }
         if(res < 0) {
-            if(errno == EINTR) {
+            if(saved_errno == EINTR) {
                 continue;
             }
             D("[ reap urb - error ]\n");
@@ -685,4 +686,3 @@
         fatal_errno("cannot create input thread");
     }
 }
-
diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.c
index 0a21c6f..635fa4b 100644
--- a/adb/usb_linux_client.c
+++ b/adb/usb_linux_client.c
@@ -83,14 +83,14 @@
 {
     int n;
 
-    D("[ write %d ]\n", len);
+    D("about to write (fd=%d, len=%d)\n", h->fd, len);
     n = adb_write(h->fd, data, len);
     if(n != len) {
-        D("ERROR: n = %d, errno = %d (%s)\n",
-            n, errno, strerror(errno));
+        D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
+            h->fd, n, errno, strerror(errno));
         return -1;
     }
-    D("[ done ]\n");
+    D("[ done fd=%d ]\n", h->fd);
     return 0;
 }
 
@@ -98,13 +98,14 @@
 {
     int n;
 
-    D("[ read %d ]\n", len);
+    D("about to read (fd=%d, len=%d)\n", h->fd, len);
     n = adb_read(h->fd, data, len);
     if(n != len) {
-        D("ERROR: n = %d, errno = %d (%s)\n",
-            n, errno, strerror(errno));
+        D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
+            h->fd, n, errno, strerror(errno));
         return -1;
     }
+    D("[ done fd=%d ]\n", h->fd);
     return 0;
 }
 
diff --git a/adb/usb_vendors.h b/adb/usb_vendors.h
index 43790b9..cee23a1 100644
--- a/adb/usb_vendors.h
+++ b/adb/usb_vendors.h
@@ -22,4 +22,4 @@
 
 void usb_vendors_init(void);
 
-#endif
\ No newline at end of file
+#endif
diff --git a/adb/usb_windows.c b/adb/usb_windows.c
index 38c4cf4..b216999 100644
--- a/adb/usb_windows.c
+++ b/adb/usb_windows.c
@@ -246,10 +246,10 @@
   }
 
   // Something went wrong.
-  errno = GetLastError();
+  int saved_errno = GetLastError();
   usb_cleanup_handle(ret);
   free(ret);
-  SetLastError(errno);
+  SetLastError(saved_errno);
 
   return NULL;
 }
@@ -267,7 +267,7 @@
                                (unsigned long)len,
                                &written,
                                time_out);
-    errno = GetLastError();
+    int saved_errno = GetLastError();
 
     if (ret) {
       // Make sure that we've written what we were asked to write
@@ -285,9 +285,10 @@
       }
     } else {
       // assume ERROR_INVALID_HANDLE indicates we are disconnected
-      if (errno == ERROR_INVALID_HANDLE)
+      if (saved_errno == ERROR_INVALID_HANDLE)
         usb_kick(handle);
     }
+    errno = saved_errno;
   } else {
     D("usb_write NULL handle\n");
     SetLastError(ERROR_INVALID_HANDLE);
@@ -313,20 +314,21 @@
                                   (unsigned long)xfer,
                                   &read,
                                   time_out);
-      errno = GetLastError();
-      D("usb_write got: %ld, expected: %d, errno: %d\n", read, xfer, errno);
+      int saved_errno = GetLastError();
+      D("usb_write got: %ld, expected: %d, errno: %d\n", read, xfer, saved_errno);
       if (ret) {
         data += read;
         len -= read;
 
         if (len == 0)
           return 0;
-      } else if (errno != ERROR_SEM_TIMEOUT) {
+      } else if (saved_errno != ERROR_SEM_TIMEOUT) {
         // assume ERROR_INVALID_HANDLE indicates we are disconnected
-        if (errno == ERROR_INVALID_HANDLE)
+        if (saved_errno == ERROR_INVALID_HANDLE)
           usb_kick(handle);
         break;
       }
+      errno = saved_errno;
     }
   } else {
     D("usb_read NULL handle\n");
diff --git a/debuggerd/debuggerd.c b/debuggerd/debuggerd.c
index 7a3e781..685f147 100644
--- a/debuggerd/debuggerd.c
+++ b/debuggerd/debuggerd.c
@@ -37,7 +37,6 @@
 
 #include <private/android_filesystem_config.h>
 
-#include <byteswap.h>
 #include "debuggerd.h"
 #include "utility.h"
 
@@ -196,73 +195,6 @@
     if(sig) dump_fault_addr(tfd, tid, sig);
 }
 
-/* After randomization (ASLR), stack contents that point to randomized
- * code become uninterpretable (e.g. can't be resolved to line numbers).
- * Here, we bundle enough information so that stack analysis on the
- * server side can still be performed. This means we are leaking some
- * information about the device (its randomization base). We have to make
- * sure an attacker has no way of intercepting the tombstone.
- */
-
-typedef struct {
-    int32_t mmap_addr;
-    char tag[4]; /* 'P', 'R', 'E', ' ' */
-} prelink_info_t __attribute__((packed));
-
-static inline void set_prelink(long *prelink_addr,
-                               prelink_info_t *info)
-{
-    // We will assume the binary is little-endian, and test the
-    // host endianness here.
-    unsigned long test_endianness = 0xFF;
-
-    if (sizeof(prelink_info_t) == 8 && prelink_addr) {
-        if (*(unsigned char *)&test_endianness)
-            *prelink_addr = info->mmap_addr;
-        else
-            *prelink_addr = bswap_32(info->mmap_addr);
-    }
-}
-
-static int check_prelinked(const char *fname,
-                           long *prelink_addr)
-{
-    *prelink_addr = 0;
-    if (sizeof(prelink_info_t) != 8) return 0;
-
-    int fd = open(fname, O_RDONLY);
-    if (fd < 0) return 0;
-    off_t end = lseek(fd, 0, SEEK_END);
-    int nr = sizeof(prelink_info_t);
-
-    off_t sz = lseek(fd, -nr, SEEK_CUR);
-    if ((long)(end - sz) != (long)nr) return 0;
-    if (sz == (off_t)-1) return 0;
-
-    prelink_info_t info;
-    int num_read = read(fd, &info, nr);
-    if (num_read < 0) return 0;
-    if (num_read != sizeof(info)) return 0;
-
-    int prelinked = 0;
-    if (!strncmp(info.tag, "PRE ", 4)) {
-        set_prelink(prelink_addr, &info);
-        prelinked = 1;
-    }
-    if (close(fd) < 0) return 0;
-    return prelinked;
-}
-
-void dump_randomization_base(int tfd, bool at_fault) {
-    bool only_in_tombstone = !at_fault;
-    long prelink_addr;
-    check_prelinked("/system/lib/libc.so", &prelink_addr);
-    _LOG(tfd, only_in_tombstone,
-         "\nlibc base address: %08x\n", prelink_addr);
-}
-
-/* End of ASLR-related logic. */
-
 static void parse_elf_info(mapinfo *milist, pid_t pid)
 {
     mapinfo *mi;
@@ -353,7 +285,6 @@
         dump_pc_and_lr(tfd, tid, milist, stack_depth, at_fault);
     }
 
-    dump_randomization_base(tfd, at_fault);
     dump_stack_and_code(tfd, tid, milist, stack_depth, sp_list, at_fault);
 #elif __i386__
     /* If stack unwinder fails, use the default solution to dump the stack
diff --git a/include/arch/darwin-x86/AndroidConfig.h b/include/arch/darwin-x86/AndroidConfig.h
index d99072a..c8ccc7e 100644
--- a/include/arch/darwin-x86/AndroidConfig.h
+++ b/include/arch/darwin-x86/AndroidConfig.h
@@ -305,12 +305,4 @@
  */
 #define HAVE_PRINTF_ZD 1
 
-/*
- * We need to open binary files using O_BINARY on Windows.
- * Most systems lack (and actually don't need) this flag.
- */
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
 #endif /*_ANDROID_CONFIG_H*/
diff --git a/include/arch/freebsd-x86/AndroidConfig.h b/include/arch/freebsd-x86/AndroidConfig.h
index 9703c76..d828bd5 100644
--- a/include/arch/freebsd-x86/AndroidConfig.h
+++ b/include/arch/freebsd-x86/AndroidConfig.h
@@ -363,12 +363,4 @@
  */
 #define HAVE_PRINTF_ZD 1
 
-/*
- * We need to open binary files using O_BINARY on Windows.
- * Most systems lack (and actually don't need) this flag.
- */
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
 #endif /*_ANDROID_CONFIG_H*/
diff --git a/include/arch/linux-arm/AndroidConfig.h b/include/arch/linux-arm/AndroidConfig.h
index 5138d90..83891cd 100644
--- a/include/arch/linux-arm/AndroidConfig.h
+++ b/include/arch/linux-arm/AndroidConfig.h
@@ -361,12 +361,4 @@
  */
 #define HAVE_PRINTF_ZD 1
 
-/*
- * We need to open binary files using O_BINARY on Windows.
- * Most systems lack (and actually don't need) this flag.
- */
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
 #endif /* _ANDROID_CONFIG_H */
diff --git a/include/arch/linux-ppc/AndroidConfig.h b/include/arch/linux-ppc/AndroidConfig.h
index 60bddd6..00706dc 100644
--- a/include/arch/linux-ppc/AndroidConfig.h
+++ b/include/arch/linux-ppc/AndroidConfig.h
@@ -323,12 +323,4 @@
  */
 #define HAVE_PREAD 1
 
-/*
- * We need to open binary files using O_BINARY on Windows.
- * Most systems lack (and actually don't need) this flag.
- */
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
 #endif /*_ANDROID_CONFIG_H*/
diff --git a/include/arch/linux-sh/AndroidConfig.h b/include/arch/linux-sh/AndroidConfig.h
index 9303bb6..5562eae 100644
--- a/include/arch/linux-sh/AndroidConfig.h
+++ b/include/arch/linux-sh/AndroidConfig.h
@@ -366,12 +366,4 @@
  */
 #define HAVE_PRINTF_ZD 1
 
-/*
- * We need to open binary files using O_BINARY on Windows.
- * Most systems lack (and actually don't need) this flag.
- */
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
 #endif /* _ANDROID_CONFIG_H */
diff --git a/include/arch/linux-x86/AndroidConfig.h b/include/arch/linux-x86/AndroidConfig.h
index 6fd26ea..7dcaa98 100644
--- a/include/arch/linux-x86/AndroidConfig.h
+++ b/include/arch/linux-x86/AndroidConfig.h
@@ -333,12 +333,4 @@
  */
 #define HAVE_PRINTF_ZD 1
 
-/*
- * We need to open binary files using O_BINARY on Windows.
- * Most systems lack (and actually don't need) this flag.
- */
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
 #endif /*_ANDROID_CONFIG_H*/
diff --git a/include/arch/target_linux-x86/AndroidConfig.h b/include/arch/target_linux-x86/AndroidConfig.h
index a6f7090..05dd220 100644
--- a/include/arch/target_linux-x86/AndroidConfig.h
+++ b/include/arch/target_linux-x86/AndroidConfig.h
@@ -350,12 +350,4 @@
  */
 #define HAVE_PRINTF_ZD 1
 
-/*
- * We need to open binary files using O_BINARY on Windows.
- * Most systems lack (and actually don't need) this flag.
- */
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
 #endif /* _ANDROID_CONFIG_H */
diff --git a/include/arch/windows/AndroidConfig.h b/include/arch/windows/AndroidConfig.h
index 8a7e062..ad890b4 100644
--- a/include/arch/windows/AndroidConfig.h
+++ b/include/arch/windows/AndroidConfig.h
@@ -338,10 +338,4 @@
  */
 /* #define HAVE_PRINTF_ZD 1 */
 
-/*
- * We need to open binary files using O_BINARY on Windows.
- * We don't define it on Windows since it is part of the io headers.
- */
-/* #define O_BINARY 0 */
-
 #endif /*_ANDROID_CONFIG_H*/
diff --git a/include/cutils/atomic-inline.h b/include/cutils/atomic-inline.h
index 6acb67c..49f3e70 100644
--- a/include/cutils/atomic-inline.h
+++ b/include/cutils/atomic-inline.h
@@ -17,6 +17,10 @@
 #ifndef ANDROID_CUTILS_ATOMIC_INLINE_H
 #define ANDROID_CUTILS_ATOMIC_INLINE_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /*
  * Inline declarations and macros for some special-purpose atomic
  * operations.  These are intended for rare circumstances where a
@@ -61,4 +65,8 @@
 #define ANDROID_MEMBAR_STORE android_memory_store_barrier
 #endif
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* ANDROID_CUTILS_ATOMIC_INLINE_H */
diff --git a/include/cutils/bitops.h b/include/cutils/bitops.h
new file mode 100644
index 0000000..1b3b762
--- /dev/null
+++ b/include/cutils/bitops.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2011 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 __CUTILS_BITOPS_H
+#define __CUTILS_BITOPS_H
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+static inline int popcount(unsigned int x)
+{
+    return __builtin_popcount(x);
+}
+
+static inline int popcountl(unsigned long x)
+{
+    return __builtin_popcountl(x);
+}
+
+static inline int popcountll(unsigned long long x)
+{
+    return __builtin_popcountll(x);
+}
+
+__END_DECLS
+
+#endif /* __CUTILS_BITOPS_H */
diff --git a/include/cutils/log.h b/include/cutils/log.h
index f602017..42d7382 100644
--- a/include/cutils/log.h
+++ b/include/cutils/log.h
@@ -289,13 +289,17 @@
  * It is NOT stripped from release builds.  Note that the condition test
  * is -inverted- from the normal assert() semantics.
  */
+#ifndef LOG_ALWAYS_FATAL_IF
 #define LOG_ALWAYS_FATAL_IF(cond, ...) \
     ( (CONDITION(cond)) \
     ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \
     : (void)0 )
+#endif
 
+#ifndef LOG_ALWAYS_FATAL
 #define LOG_ALWAYS_FATAL(...) \
     ( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) )
+#endif
 
 /*
  * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that
@@ -303,13 +307,21 @@
  */
 #if LOG_NDEBUG
 
+#ifndef LOG_FATAL_IF
 #define LOG_FATAL_IF(cond, ...) ((void)0)
+#endif
+#ifndef LOG_FATAL
 #define LOG_FATAL(...) ((void)0)
+#endif
 
 #else
 
+#ifndef LOG_FATAL_IF
 #define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__)
+#endif
+#ifndef LOG_FATAL
 #define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
+#endif
 
 #endif
 
@@ -317,8 +329,10 @@
  * Assertion that generates a log message when the assertion fails.
  * Stripped out of release builds.  Uses the current LOG_TAG.
  */
+#ifndef LOG_ASSERT
 #define LOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__)
 //#define LOG_ASSERT(cond) LOG_FATAL_IF(!(cond), "Assertion failed: " #cond)
+#endif
 
 // ---------------------------------------------------------------------
 
@@ -377,18 +391,24 @@
 } AndroidEventLogType;
 
 
+#ifndef LOG_EVENT_INT
 #define LOG_EVENT_INT(_tag, _value) {                                       \
         int intBuf = _value;                                                \
         (void) android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf,            \
             sizeof(intBuf));                                                \
     }
+#endif
+#ifndef LOG_EVENT_LONG
 #define LOG_EVENT_LONG(_tag, _value) {                                      \
         long long longBuf = _value;                                         \
         (void) android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf,          \
             sizeof(longBuf));                                               \
     }
+#endif
+#ifndef LOG_EVENT_STRING
 #define LOG_EVENT_STRING(_tag, _value)                                      \
     ((void) 0)  /* not implemented -- must combine len with string */
+#endif
 /* TODO: something for LIST */
 
 /*
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index f23c235..55d9220 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -53,7 +53,7 @@
 #define AID_KEYSTORE      1017  /* keystore subsystem */
 #define AID_USB           1018  /* USB devices */
 #define AID_DRM           1019  /* DRM server */
-#define AID_AVAILABLE     1020  /* available for use */
+#define AID_KEYCHAIN      1020  /* keychain service */
 #define AID_GPS           1021  /* GPS daemon */
 #define AID_UNUSED1       1022  /* deprecated, DO NOT USE */
 #define AID_MEDIA_RW      1023  /* internal media storage write access */
@@ -101,7 +101,7 @@
     { "install",   AID_INSTALL, },
     { "media",     AID_MEDIA, },
     { "drm",       AID_DRM, },
-    { "available", AID_AVAILABLE, },
+    { "keychain",  AID_KEYCHAIN, },
     { "nfc",       AID_NFC, },
     { "shell",     AID_SHELL, },
     { "cache",     AID_CACHE, },
diff --git a/init/devices.c b/init/devices.c
index 036b8f7..bc36ac1 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -97,8 +97,15 @@
     struct listnode plist;
 };
 
+struct platform_node {
+    char *name;
+    int name_len;
+    struct listnode list;
+};
+
 static list_declare(sys_perms);
 static list_declare(dev_perms);
+static list_declare(platform_names);
 
 int add_dev_perms(const char *name, const char *attr,
                   mode_t perm, unsigned int uid, unsigned int gid,
@@ -212,6 +219,68 @@
     setegid(AID_ROOT);
 }
 
+static void add_platform_device(const char *name)
+{
+    int name_len = strlen(name);
+    struct listnode *node;
+    struct platform_node *bus;
+
+    list_for_each_reverse(node, &platform_names) {
+        bus = node_to_item(node, struct platform_node, list);
+        if ((bus->name_len < name_len) &&
+                (name[bus->name_len] == '/') &&
+                !strncmp(name, bus->name, bus->name_len))
+            /* subdevice of an existing platform, ignore it */
+            return;
+    }
+
+    INFO("adding platform device %s\n", name);
+
+    bus = calloc(1, sizeof(struct platform_node));
+    bus->name = strdup(name);
+    bus->name_len = name_len;
+    list_add_tail(&platform_names, &bus->list);
+}
+
+/*
+ * given a name that may start with a platform device, find the length of the
+ * platform device prefix.  If it doesn't start with a platform device, return
+ * 0.
+ */
+static const char *find_platform_device(const char *name)
+{
+    int name_len = strlen(name);
+    struct listnode *node;
+    struct platform_node *bus;
+
+    list_for_each_reverse(node, &platform_names) {
+        bus = node_to_item(node, struct platform_node, list);
+        if ((bus->name_len < name_len) &&
+                (name[bus->name_len] == '/') &&
+                !strncmp(name, bus->name, bus->name_len))
+            return bus->name;
+    }
+
+    return NULL;
+}
+
+static void remove_platform_device(const char *name)
+{
+    struct listnode *node;
+    struct platform_node *bus;
+
+    list_for_each_reverse(node, &platform_names) {
+        bus = node_to_item(node, struct platform_node, list);
+        if (!strcmp(name, bus->name)) {
+            INFO("removing platform device %s\n", name);
+            free(bus->name);
+            list_remove(node);
+            free(bus);
+            return;
+        }
+    }
+}
+
 #if LOG_UEVENTS
 
 static inline suseconds_t get_usecs(void)
@@ -332,7 +401,7 @@
 
 static char **parse_platform_block_device(struct uevent *uevent)
 {
-    const char *driver;
+    const char *device;
     const char *path;
     char *slash;
     int width;
@@ -352,16 +421,14 @@
 
     /* Drop "/devices/platform/" */
     path = uevent->path;
-    driver = path + 18;
-    slash = strchr(driver, '/');
-    if (!slash)
-        goto err;
-    width = slash - driver;
-    if (width <= 0)
+    device = path + 18;
+    device = find_platform_device(device);
+    if (!device)
         goto err;
 
-    snprintf(link_path, sizeof(link_path), "/dev/block/platform/%.*s",
-             width, driver);
+    INFO("found platform device %s\n", device);
+
+    snprintf(link_path, sizeof(link_path), "/dev/block/platform/%s", device);
 
     if (uevent->partition_name) {
         p = strdup(uevent->partition_name);
@@ -393,104 +460,20 @@
     return NULL;
 }
 
-static void handle_device_event(struct uevent *uevent)
+static void handle_device(const char *action, const char *devpath,
+        const char *path, int block, int major, int minor, char **links)
 {
-    char devpath[96];
-    int devpath_ready = 0;
-    char *base, *name;
-    char **links = NULL;
-    int block;
     int i;
 
-    if (!strcmp(uevent->action,"add"))
-        fixup_sys_perms(uevent->path);
-
-        /* if it's not a /dev device, nothing else to do */
-    if((uevent->major < 0) || (uevent->minor < 0))
-        return;
-
-        /* do we have a name? */
-    name = strrchr(uevent->path, '/');
-    if(!name)
-        return;
-    name++;
-
-        /* too-long names would overrun our buffer */
-    if(strlen(name) > 64)
-        return;
-
-        /* are we block or char? where should we live? */
-    if(!strncmp(uevent->subsystem, "block", 5)) {
-        block = 1;
-        base = "/dev/block/";
-        mkdir(base, 0755);
-        if (!strncmp(uevent->path, "/devices/platform/", 18))
-            links = parse_platform_block_device(uevent);
-    } else {
-        block = 0;
-            /* this should probably be configurable somehow */
-        if (!strncmp(uevent->subsystem, "usb", 3)) {
-            if (!strcmp(uevent->subsystem, "usb")) {
-                /* This imitates the file system that would be created
-                 * if we were using devfs instead.
-                 * Minors are broken up into groups of 128, starting at "001"
-                 */
-                int bus_id = uevent->minor / 128 + 1;
-                int device_id = uevent->minor % 128 + 1;
-                /* build directories */
-                mkdir("/dev/bus", 0755);
-                mkdir("/dev/bus/usb", 0755);
-                snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d", bus_id);
-                mkdir(devpath, 0755);
-                snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d/%03d", bus_id, device_id);
-                devpath_ready = 1;
-            } else {
-                /* ignore other USB events */
-                return;
-            }
-        } else if (!strncmp(uevent->subsystem, "graphics", 8)) {
-            base = "/dev/graphics/";
-            mkdir(base, 0755);
-        } else if (!strncmp(uevent->subsystem, "oncrpc", 6)) {
-            base = "/dev/oncrpc/";
-            mkdir(base, 0755);
-        } else if (!strncmp(uevent->subsystem, "adsp", 4)) {
-            base = "/dev/adsp/";
-            mkdir(base, 0755);
-        } else if (!strncmp(uevent->subsystem, "msm_camera", 10)) {
-            base = "/dev/msm_camera/";
-            mkdir(base, 0755);
-        } else if(!strncmp(uevent->subsystem, "input", 5)) {
-            base = "/dev/input/";
-            mkdir(base, 0755);
-        } else if(!strncmp(uevent->subsystem, "mtd", 3)) {
-            base = "/dev/mtd/";
-            mkdir(base, 0755);
-        } else if(!strncmp(uevent->subsystem, "sound", 5)) {
-            base = "/dev/snd/";
-            mkdir(base, 0755);
-        } else if(!strncmp(uevent->subsystem, "misc", 4) &&
-                    !strncmp(name, "log_", 4)) {
-            base = "/dev/log/";
-            mkdir(base, 0755);
-            name += 4;
-        } else
-            base = "/dev/";
-        links = get_character_device_symlinks(uevent);
-    }
-
-    if (!devpath_ready)
-        snprintf(devpath, sizeof(devpath), "%s%s", base, name);
-
-    if(!strcmp(uevent->action, "add")) {
-        make_device(devpath, uevent->path, block, uevent->major, uevent->minor);
+    if(!strcmp(action, "add")) {
+        make_device(devpath, path, block, major, minor);
         if (links) {
             for (i = 0; links[i]; i++)
                 make_link(devpath, links[i]);
         }
     }
 
-    if(!strcmp(uevent->action, "remove")) {
+    if(!strcmp(action, "remove")) {
         if (links) {
             for (i = 0; links[i]; i++)
                 remove_link(devpath, links[i]);
@@ -505,6 +488,138 @@
     }
 }
 
+static void handle_platform_device_event(struct uevent *uevent)
+{
+    const char *name = uevent->path + 18; /* length of /devices/platform/ */
+
+    if (!strcmp(uevent->action, "add"))
+        add_platform_device(name);
+    else if (!strcmp(uevent->action, "remove"))
+        remove_platform_device(name);
+}
+
+static const char *parse_device_name(struct uevent *uevent, unsigned int len)
+{
+    const char *name;
+
+    /* if it's not a /dev device, nothing else to do */
+    if((uevent->major < 0) || (uevent->minor < 0))
+        return NULL;
+
+    /* do we have a name? */
+    name = strrchr(uevent->path, '/');
+    if(!name)
+        return NULL;
+    name++;
+
+    /* too-long names would overrun our buffer */
+    if(strlen(name) > len)
+        return NULL;
+
+    return name;
+}
+
+static void handle_block_device_event(struct uevent *uevent)
+{
+    const char *base = "/dev/block/";
+    const char *name;
+    char devpath[96];
+    char **links = NULL;
+
+    name = parse_device_name(uevent, 64);
+    if (!name)
+        return;
+
+    snprintf(devpath, sizeof(devpath), "%s%s", base, name);
+    mkdir(base, 0755);
+
+    if (!strncmp(uevent->path, "/devices/platform/", 18))
+        links = parse_platform_block_device(uevent);
+
+    handle_device(uevent->action, devpath, uevent->path, 1,
+            uevent->major, uevent->minor, links);
+}
+
+static void handle_generic_device_event(struct uevent *uevent)
+{
+    char *base;
+    const char *name;
+    char devpath[96] = {0};
+    char **links = NULL;
+
+    name = parse_device_name(uevent, 64);
+    if (!name)
+        return;
+
+    if (!strncmp(uevent->subsystem, "usb", 3)) {
+         if (!strcmp(uevent->subsystem, "usb")) {
+             /* This imitates the file system that would be created
+              * if we were using devfs instead.
+              * Minors are broken up into groups of 128, starting at "001"
+              */
+             int bus_id = uevent->minor / 128 + 1;
+             int device_id = uevent->minor % 128 + 1;
+             /* build directories */
+             mkdir("/dev/bus", 0755);
+             mkdir("/dev/bus/usb", 0755);
+             snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d", bus_id);
+             mkdir(devpath, 0755);
+             snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d/%03d", bus_id, device_id);
+         } else {
+             /* ignore other USB events */
+             return;
+         }
+     } else if (!strncmp(uevent->subsystem, "graphics", 8)) {
+         base = "/dev/graphics/";
+         mkdir(base, 0755);
+     } else if (!strncmp(uevent->subsystem, "oncrpc", 6)) {
+         base = "/dev/oncrpc/";
+         mkdir(base, 0755);
+     } else if (!strncmp(uevent->subsystem, "adsp", 4)) {
+         base = "/dev/adsp/";
+         mkdir(base, 0755);
+     } else if (!strncmp(uevent->subsystem, "msm_camera", 10)) {
+         base = "/dev/msm_camera/";
+         mkdir(base, 0755);
+     } else if(!strncmp(uevent->subsystem, "input", 5)) {
+         base = "/dev/input/";
+         mkdir(base, 0755);
+     } else if(!strncmp(uevent->subsystem, "mtd", 3)) {
+         base = "/dev/mtd/";
+         mkdir(base, 0755);
+     } else if(!strncmp(uevent->subsystem, "sound", 5)) {
+         base = "/dev/snd/";
+         mkdir(base, 0755);
+     } else if(!strncmp(uevent->subsystem, "misc", 4) &&
+                 !strncmp(name, "log_", 4)) {
+         base = "/dev/log/";
+         mkdir(base, 0755);
+         name += 4;
+     } else
+         base = "/dev/";
+     links = get_character_device_symlinks(uevent);
+
+     if (!devpath[0])
+         snprintf(devpath, sizeof(devpath), "%s%s", base, name);
+
+     handle_device(uevent->action, devpath, uevent->path, 0,
+             uevent->major, uevent->minor, links);
+}
+
+static void handle_device_event(struct uevent *uevent)
+{
+    if (!strcmp(uevent->action,"add"))
+        fixup_sys_perms(uevent->path);
+
+    if (!strncmp(uevent->subsystem, "block", 5)) {
+        handle_block_device_event(uevent);
+    } else if (!strncmp(uevent->subsystem, "platform", 8)) {
+        handle_platform_device_event(uevent);
+    } else {
+        handle_generic_device_event(uevent);
+    }
+}
+
 static int load_firmware(int fw_fd, int loading_fd, int data_fd)
 {
     struct stat st;
@@ -551,13 +666,19 @@
     return ret;
 }
 
+static int is_booting(void)
+{
+    return access("/dev/.booting", F_OK) == 0;
+}
+
 static void process_firmware_event(struct uevent *uevent)
 {
     char *root, *loading, *data, *file1 = NULL, *file2 = NULL;
     int l, loading_fd, data_fd, fw_fd;
+    int booting = is_booting();
 
-    log_event_print("firmware event { '%s', '%s' }\n",
-                    uevent->path, uevent->firmware);
+    INFO("firmware: loading '%s' for '%s'\n",
+         uevent->firmware, uevent->path);
 
     l = asprintf(&root, SYSFS_PREFIX"%s/", uevent->path);
     if (l == -1)
@@ -587,19 +708,29 @@
     if(data_fd < 0)
         goto loading_close_out;
 
+try_loading_again:
     fw_fd = open(file1, O_RDONLY);
     if(fw_fd < 0) {
         fw_fd = open(file2, O_RDONLY);
         if (fw_fd < 0) {
+            if (booting) {
+                    /* If we're not fully booted, we may be missing
+                     * filesystems needed for firmware, wait and retry.
+                     */
+                usleep(100000);
+                booting = is_booting();
+                goto try_loading_again;
+            }
+            INFO("firmware: could not open '%s' %d\n", uevent->firmware, errno);
             write(loading_fd, "-1", 2);
             goto data_close_out;
         }
     }
 
     if(!load_firmware(fw_fd, loading_fd, data_fd))
-        log_event_print("firmware copy success { '%s', '%s' }\n", root, uevent->firmware);
+        INFO("firmware: copy success { '%s', '%s' }\n", root, uevent->firmware);
     else
-        log_event_print("firmware copy failure { '%s', '%s' }\n", root, uevent->firmware);
+        INFO("firmware: copy failure { '%s', '%s' }\n", root, uevent->firmware);
 
     close(fw_fd);
 data_close_out:
@@ -620,7 +751,6 @@
 static void handle_firmware_event(struct uevent *uevent)
 {
     pid_t pid;
-    int status;
     int ret;
 
     if(strcmp(uevent->subsystem, "firmware"))
@@ -634,10 +764,6 @@
     if (!pid) {
         process_firmware_event(uevent);
         exit(EXIT_SUCCESS);
-    } else {
-        do {
-            ret = waitpid(pid, &status, 0);
-        } while (ret == -1 && errno == EINTR);
     }
 }
 
diff --git a/init/init.c b/init/init.c
index e13d4b1..1e31cf9 100755
--- a/init/init.c
+++ b/init/init.c
@@ -651,6 +651,10 @@
         ERROR("init startup failure\n");
         exit(1);
     }
+
+        /* signal that we hit this point */
+    unlink("/dev/.booting");
+
     return 0;
 }
 
@@ -708,6 +712,9 @@
     mount("proc", "/proc", "proc", 0, NULL);
     mount("sysfs", "/sys", "sysfs", 0, NULL);
 
+        /* indicate that booting is in progress to background fw loaders, etc */
+    close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));
+
         /* We must have some place other than / to create the
          * device nodes for kmsg and null, otherwise we won't
          * be able to remount / read-only later on.
diff --git a/init/ueventd.c b/init/ueventd.c
index 0e97be7..1328d19 100644
--- a/init/ueventd.c
+++ b/init/ueventd.c
@@ -20,6 +20,8 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <ctype.h>
+#include <signal.h>
+
 #include <private/android_filesystem_config.h>
 
 #include "ueventd.h"
@@ -37,6 +39,13 @@
     int nr;
     char tmp[32];
 
+        /* Prevent fire-and-forget children from becoming zombies.
+         * If we should need to wait() for some children in the future
+         * (as opposed to none right now), double-forking here instead
+         * of ignoring SIGCHLD may be the better solution.
+         */
+    signal(SIGCHLD, SIG_IGN);
+
     open_devnull_stdio();
     log_init();
 
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
index 030e677..5991ea8 100644
--- a/libnetutils/dhcp_utils.c
+++ b/libnetutils/dhcp_utils.c
@@ -31,6 +31,7 @@
 static const char DHCP_PROP_NAME_PREFIX[]  = "dhcp";
 static const int NAP_TIME = 200;   /* wait for 200ms at a time */
                                   /* when polling for property values */
+static const char DAEMON_NAME_RENEW[]  = "iprenew";
 static char errmsg[100];
 
 /*
@@ -78,6 +79,15 @@
     snprintf(prop_name, sizeof(prop_name), "%s.%s.gateway", DHCP_PROP_NAME_PREFIX, interface);
     property_get(prop_name, gateway, NULL);
 
+    snprintf(prop_name, sizeof(prop_name), "%s.%s.server", DHCP_PROP_NAME_PREFIX, interface);
+    property_get(prop_name, server, NULL);
+
+    //TODO: Handle IPv6 when we change system property usage
+    if (strcmp(gateway, "0.0.0.0") == 0) {
+        //DHCP server is our best bet as gateway
+        strncpy(gateway, server, PROPERTY_VALUE_MAX);
+    }
+
     snprintf(prop_name, sizeof(prop_name), "%s.%s.mask", DHCP_PROP_NAME_PREFIX, interface);
     if (property_get(prop_name, prop_value, NULL)) {
         int p;
@@ -106,9 +116,6 @@
     snprintf(prop_name, sizeof(prop_name), "%s.%s.dns2", DHCP_PROP_NAME_PREFIX, interface);
     property_get(prop_name, dns2, NULL);
 
-    snprintf(prop_name, sizeof(prop_name), "%s.%s.server", DHCP_PROP_NAME_PREFIX, interface);
-    property_get(prop_name, server, NULL);
-
     snprintf(prop_name, sizeof(prop_name), "%s.%s.leasetime", DHCP_PROP_NAME_PREFIX, interface);
     if (property_get(prop_name, prop_value, NULL)) {
         *lease = atol(prop_value);
@@ -138,6 +145,7 @@
                     uint32_t  *lease)
 {
     char result_prop_name[PROPERTY_KEY_MAX];
+    char daemon_prop_name[PROPERTY_KEY_MAX];
     char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
     char daemon_cmd[PROPERTY_VALUE_MAX * 2];
     const char *ctrl_prop = "ctl.start";
@@ -146,18 +154,23 @@
     snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
             DHCP_PROP_NAME_PREFIX,
             interface);
+
+    snprintf(daemon_prop_name, sizeof(daemon_prop_name), "%s_%s",
+            DAEMON_PROP_NAME,
+            interface);
+
     /* Erase any previous setting of the dhcp result property */
     property_set(result_prop_name, "");
 
     /* Start the daemon and wait until it's ready */
     if (property_get(HOSTNAME_PROP_NAME, prop_value, NULL) && (prop_value[0] != '\0'))
-        snprintf(daemon_cmd, sizeof(daemon_cmd), "%s:-h %s %s", DAEMON_NAME,
+        snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:-h %s %s", DAEMON_NAME, interface,
                  prop_value, interface);
     else
-        snprintf(daemon_cmd, sizeof(daemon_cmd), "%s:%s", DAEMON_NAME, interface);
+        snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:%s", DAEMON_NAME, interface, interface);
     memset(prop_value, '\0', PROPERTY_VALUE_MAX);
     property_set(ctrl_prop, daemon_cmd);
-    if (wait_for_property(DAEMON_PROP_NAME, desired_status, 10) < 0) {
+    if (wait_for_property(daemon_prop_name, desired_status, 10) < 0) {
         snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for dhcpcd to start");
         return -1;
     }
@@ -199,15 +212,24 @@
 int dhcp_stop(const char *interface)
 {
     char result_prop_name[PROPERTY_KEY_MAX];
+    char daemon_prop_name[PROPERTY_KEY_MAX];
+    char daemon_cmd[PROPERTY_VALUE_MAX * 2];
     const char *ctrl_prop = "ctl.stop";
     const char *desired_status = "stopped";
 
     snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
             DHCP_PROP_NAME_PREFIX,
             interface);
+
+    snprintf(daemon_prop_name, sizeof(daemon_prop_name), "%s_%s",
+            DAEMON_PROP_NAME,
+            interface);
+
+    snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME, interface);
+
     /* Stop the daemon and wait until it's reported to be stopped */
-    property_set(ctrl_prop, DAEMON_NAME);
-    if (wait_for_property(DAEMON_PROP_NAME, desired_status, 5) < 0) {
+    property_set(ctrl_prop, daemon_cmd);
+    if (wait_for_property(daemon_prop_name, desired_status, 5) < 0) {
         return -1;
     }
     property_set(result_prop_name, "failed");
@@ -219,12 +241,20 @@
  */
 int dhcp_release_lease(const char *interface)
 {
+    char daemon_prop_name[PROPERTY_KEY_MAX];
+    char daemon_cmd[PROPERTY_VALUE_MAX * 2];
     const char *ctrl_prop = "ctl.stop";
     const char *desired_status = "stopped";
 
+    snprintf(daemon_prop_name, sizeof(daemon_prop_name), "%s_%s",
+            DAEMON_PROP_NAME,
+            interface);
+
+    snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME, interface);
+
     /* Stop the daemon and wait until it's reported to be stopped */
-    property_set(ctrl_prop, DAEMON_NAME);
-    if (wait_for_property(DAEMON_PROP_NAME, desired_status, 5) < 0) {
+    property_set(ctrl_prop, daemon_cmd);
+    if (wait_for_property(daemon_prop_name, desired_status, 5) < 0) {
         return -1;
     }
     return 0;
@@ -233,3 +263,53 @@
 char *dhcp_get_errmsg() {
     return errmsg;
 }
+
+/**
+ * Run WiMAX dhcp renew service.
+ * "wimax_renew" service shoud be included in init.rc.
+ */
+int dhcp_do_request_renew(const char *interface,
+                    in_addr_t *ipaddr,
+                    in_addr_t *gateway,
+                    in_addr_t *mask,
+                    in_addr_t *dns1,
+                    in_addr_t *dns2,
+                    in_addr_t *server,
+                    uint32_t  *lease)
+{
+    char result_prop_name[PROPERTY_KEY_MAX];
+    char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
+    char daemon_cmd[PROPERTY_VALUE_MAX * 2];
+    const char *ctrl_prop = "ctl.start";
+
+    snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
+            DHCP_PROP_NAME_PREFIX,
+            interface);
+
+    /* Erase any previous setting of the dhcp result property */
+    property_set(result_prop_name, "");
+
+    /* Start the renew daemon and wait until it's ready */
+    snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:%s", DAEMON_NAME_RENEW, interface, interface);
+    memset(prop_value, '\0', PROPERTY_VALUE_MAX);
+    property_set(ctrl_prop, daemon_cmd);
+
+    /* Wait for the daemon to return a result */
+    if (wait_for_property(result_prop_name, NULL, 30) < 0) {
+        snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for DHCP Renew to finish");
+        return -1;
+    }
+
+    if (!property_get(result_prop_name, prop_value, NULL)) {
+        /* shouldn't ever happen, given the success of wait_for_property() */
+        snprintf(errmsg, sizeof(errmsg), "%s", "DHCP Renew result property was not set");
+        return -1;
+    }
+    if (strcmp(prop_value, "ok") == 0) {
+        fill_ip_info(interface, ipaddr, gateway, mask, dns1, dns2, server, lease);
+        return 0;
+    } else {
+        snprintf(errmsg, sizeof(errmsg), "DHCP Renew result was %s", prop_value);
+        return -1;
+    }
+}
diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c
index 946c39d..92b9681 100644
--- a/libnetutils/ifc_utils.c
+++ b/libnetutils/ifc_utils.c
@@ -206,6 +206,16 @@
     return ioctl(ifc_ctl_sock, SIOCSIFHWADDR, &ifr);
 }
 
+int ifc_set_mask(const char *name, in_addr_t mask)
+{
+    struct ifreq ifr;
+
+    ifc_init_ifr(name, &ifr);
+    init_sockaddr_in(&ifr.ifr_addr, mask);
+
+    return ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &ifr);
+}
+
 int ifc_set_prefixLength(const char *name, int prefixLength)
 {
     struct ifreq ifr;
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 7112ebf..bd00311 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -326,15 +326,9 @@
 
     fuse->all = &fuse->root;
 
+    memset(&fuse->root, 0, sizeof(fuse->root));
     fuse->root.nid = FUSE_ROOT_ID; /* 1 */
-    fuse->root.next = 0;
-    fuse->root.child = 0;
-    fuse->root.parent = 0;
-
-    fuse->root.all = 0;
     fuse->root.refcount = 2;
-
-    fuse->root.name = 0;
     rename_node(&fuse->root, path);
 }
 
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index ff01172..76542a6 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -54,6 +54,7 @@
 	vmstat \
 	nandread \
 	ionice \
+	touch \
 	lsof
 
 LOCAL_SRC_FILES:= \
diff --git a/toolbox/start.c b/toolbox/start.c
index 3bd9fbb..665a941 100644
--- a/toolbox/start.c
+++ b/toolbox/start.c
@@ -8,13 +8,14 @@
 int start_main(int argc, char *argv[])
 {
     char buf[1024];
+
     if(argc > 1) {
         property_set("ctl.start", argv[1]);
     } else {
-        /* default to "start zygote" "start runtime" */
+        /* defaults to starting the common services stopped by stop.c */
+        property_set("ctl.start", "surfaceflinger");
         property_set("ctl.start", "zygote");
-        property_set("ctl.start", "runtime");
     }
-    
+
     return 0;
 }
diff --git a/toolbox/stop.c b/toolbox/stop.c
index 05baffd..460f377 100644
--- a/toolbox/stop.c
+++ b/toolbox/stop.c
@@ -10,11 +10,10 @@
     if(argc > 1) {
         property_set("ctl.stop", argv[1]);
     } else{
-        /* default to "stop runtime" "stop zygote" */
-        property_set("ctl.stop", "runtime");
+        /* defaults to stopping the common services */
         property_set("ctl.stop", "zygote");
+        property_set("ctl.stop", "surfaceflinger");
     }
 
     return 0;
 }
-
diff --git a/toolbox/touch.c b/toolbox/touch.c
new file mode 100644
index 0000000..b8ab310
--- /dev/null
+++ b/toolbox/touch.c
@@ -0,0 +1,87 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+static void usage(void)
+{
+        fprintf(stderr, "touch: usage: touch [-alm] [-t time_t] <file>\n");
+        exit(1);
+}
+
+int touch_main(int argc, char *argv[])
+{
+        int i, fd, aflag = 0, mflag = 0, debug = 0, flags = 0;
+        struct timespec specified_time, times[2];
+        char *file = 0;
+
+        specified_time.tv_nsec = UTIME_NOW;
+
+        for (i = 1; i < argc; i++) {
+            if (argv[i][0] == '-') {
+                /* an option */
+                const char *arg = argv[i]+1;
+                while (arg[0]) {
+                    switch (arg[0]) {
+                    case 'a': aflag = 1; break;
+                    case 'm': mflag = 1; break;
+                    case 't':
+                        if ((i+1) >= argc)
+                            usage();
+                        specified_time.tv_sec = atol(argv[++i]);
+                        if (specified_time.tv_sec == 0) {
+                            fprintf(stderr, "touch: invalid time_t\n");
+                            exit(1);
+                        }
+                        specified_time.tv_nsec = 0;
+                        break;
+                    case 'l': flags |= AT_SYMLINK_NOFOLLOW; break;
+                    case 'd': debug = 1; break;
+                    default:
+                        usage();
+                    }
+                    arg++;
+                }
+            } else {
+                /* not an option, and only accept one filename */
+                if (i+1 != argc)
+                    usage();
+                file = argv[i];
+            }
+        }
+
+        if (! file) {
+            fprintf(stderr, "touch: no file specified\n");
+            exit(1);
+        }
+
+        if (access(file, F_OK))
+            if ((fd=creat(file, 0666)) != -1)
+                close(fd);
+
+        if ((mflag == 0) && (aflag == 0))
+            aflag = mflag = 1;
+
+        if (aflag)
+            times[0] = specified_time;
+        else
+            times[0].tv_nsec = UTIME_OMIT;
+
+        if (mflag)
+            times[1] = specified_time;
+        else
+            times[1].tv_nsec = UTIME_OMIT;
+
+        if (debug) {
+            fprintf(stderr, "file = %s\n", file);
+            fprintf(stderr, "times[0].tv_sec = %ld, times[0].tv_nsec = %ld\n", times[0].tv_sec, times[0].tv_nsec);
+            fprintf(stderr, "times[1].tv_sec = %ld, times[1].tv_nsec = %ld\n", times[1].tv_sec, times[1].tv_nsec);
+            fprintf(stderr, "flags = 0x%8.8x\n", flags);
+        }
+
+        return utimensat(AT_FDCWD, file, times, flags);
+}
+