Reconcile with gingerbread-release honeycomb-release honeycomb-mr1-release

Change-Id: I673f0a6cc6425eadd0be9ba977be8d499f50ffda
diff --git a/adb/Android.mk b/adb/Android.mk
index 6ed31eb..e893ca9 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -113,6 +113,7 @@
 
 LOCAL_SRC_FILES := \
 	adb.c \
+	backup_service.c \
 	fdevent.c \
 	transport.c \
 	transport_local.c \
@@ -164,6 +165,7 @@
 
 LOCAL_SRC_FILES := \
 	adb.c \
+	backup_service.c \
 	console.c \
 	transport.c \
 	transport_local.c \
diff --git a/adb/adb.c b/adb/adb.c
index 0da7218..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
 }
@@ -682,9 +680,11 @@
     dup2(fd, 1);
     dup2(fd, 2);
     fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
+    adb_close(fd);
 
     fd = unix_open("/dev/null", O_RDONLY);
     dup2(fd, 0);
+    adb_close(fd);
 }
 #endif
 
@@ -805,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') {
@@ -846,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
 
@@ -875,7 +876,7 @@
             // don't run as root if ro.secure is set...
             secure = 1;
 
-            // ... except we allow running as root in userdebug builds if the 
+            // ... except we allow running as root in userdebug builds if the
             // service.adb.root property has been set by the "adb root" command
             property_get("ro.debuggable", value, "");
             if (strcmp(value, "1") == 0) {
@@ -955,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)
@@ -969,6 +972,7 @@
 #endif
         start_logging();
     }
+    D("Event loop starting\n");
 
     fdevent_loop();
 
@@ -1266,9 +1270,10 @@
 
 int main(int argc, char **argv)
 {
-    adb_trace_init();
 #if ADB_HOST
     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"))) {
@@ -1277,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..318a2d8 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
@@ -33,7 +35,7 @@
 #define ADB_VERSION_MAJOR 1         // Used for help/version information
 #define ADB_VERSION_MINOR 0         // Used for help/version information
 
-#define ADB_SERVER_VERSION    26    // Increment this when we want to force users to start a new adb server
+#define ADB_SERVER_VERSION    27    // Increment this when we want to force users to start a new adb server
 
 typedef struct amessage amessage;
 typedef struct apacket apacket;
@@ -302,6 +304,7 @@
 #endif
 
 #if !ADB_HOST
+int backup_service(char* args);
 void framebuffer_service(int fd, void *cookie);
 void log_service(int fd, void *cookie);
 void remount_service(int fd, void *cookie);
@@ -315,13 +318,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 +327,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 +432,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/backup_service.c b/adb/backup_service.c
new file mode 100644
index 0000000..1e55efc
--- /dev/null
+++ b/adb/backup_service.c
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+
+#include "sysdeps.h"
+
+#define TRACE_TAG  TRACE_ADB
+#include "adb.h"
+
+/* returns the data socket passing the backup data here for forwarding */
+int backup_service(char* args) {
+    pid_t pid;
+    int s[2];
+
+    D("backup_service(%s)\n", args);
+
+    // set up the pipe from the subprocess to here
+    // parent will read s[0]; child will write s[1]
+    if (adb_socketpair(s)) {
+        D("can't create backup socketpair\n");
+        fprintf(stderr, "unable to create backup socketpair\n");
+        return -1;
+    }
+
+    // spin off the child process to run the backup command
+    pid = fork();
+    if (pid < 0) {
+        // failure
+        D("can't fork for backup\n");
+        fprintf(stderr, "unable to fork for backup\n");
+        adb_close(s[0]);
+        adb_close(s[1]);
+        return -1;
+    }
+
+    // Great, we're off and running.
+    if (pid == 0) {
+        char* p;
+        int argc;
+        char** backup_args;
+
+        // child -- actually run the backup here
+        argc = 2; // room for the basic 'bu' argv[0] and 'backup' argv[1]
+        for (p = (char*)args; p && *p; ) {
+            argc++;
+            while (*p && *p != ':') p++;
+            if (*p == ':') p++;
+        }
+
+        backup_args = (char**) alloca(argc*sizeof(char*) + 1);
+        backup_args[0] = "bu";
+        backup_args[1] = "backup";
+        argc = 2;   // run through again to build the argv array
+        for (p = (char*)args; *p; ) {
+            backup_args[argc++] = p;
+            while (*p && *p != ':') p++;
+            if (*p == ':') {
+                *p = 0;
+                p++;
+            }
+        }
+        backup_args[argc] = NULL;
+
+        // Close the half of the socket that we don't care about, route 'bu's console
+        // to the output socket, and off we go
+        adb_close(s[0]);
+        dup2(s[1], STDOUT_FILENO);
+
+        // off we go
+        execvp("/system/bin/bu", (char * const *)backup_args);
+        // oops error - close up shop and go home
+        fprintf(stderr, "Unable to exec 'bu', bailing\n");
+        exit(-1);
+    } else {
+        // parent, i.e. adbd -- close the sending half of the socket
+        adb_close(s[1]);
+    }
+
+    // we'll be reading from s[0] as the data is sent by the child process
+    return s[0];
+}
diff --git a/adb/commandline.c b/adb/commandline.c
index 3600e5a..733cbff 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);
@@ -104,7 +98,7 @@
         "                                 Port 5555 is used by default if no port number is specified.\n"
         " disconnect [<host>[:<port>]]  - disconnect from a TCP/IP device.\n"
         "                                 Port 5555 is used by default if no port number is specified.\n"
-        "                                 Using this ocmmand with no additional arguments\n"
+        "                                 Using this command with no additional arguments\n"
         "                                 will disconnect from all connected TCP/IP devices.\n"
         "\n"
         "device commands:\n"
@@ -135,14 +129,22 @@
         "  adb bugreport                - return all information from the device\n"
         "                                 that should be included in a bug report.\n"
         "\n"
+        "  adb backup [-f <file>] [-apk|-noapk] [-shared|-noshared] [-all] [<packages...>]\n"
+        "                               - Write a tarfile backup of the device's data to <file>.\n"
+        "                                 The -f option must come first; if not specified then the data\n"
+        "                                 is written to \"backup.tar\" in the current directory.\n"
+        "                                 (-apk|-noapk enable/disable backup of the .apks themselves\n"
+        "                                    in the tarfile; the default is noapk.)\n"
+        "                                 (-shared|-noshared enable/disable backup of the device's\n"
+        "                                    shared storage / SD card contents; the default is noshared.)\n"
+        "                                 (-all means to back up all installed applications)\n"
+        "                                 (<packages...> is the list of applications to be backed up.  If\n"
+        "                                    the -all or -shared flags are passed, then the package\n"
+        "                                    list is optional.)\n"
+        "\n"
         "  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 +220,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;
         }
@@ -232,6 +236,25 @@
     }
 }
 
+static void copy_to_file(int inFd, int outFd) {
+    char buf[4096];
+    int len;
+
+    D("copy_to_file(%d -> %d)\n", inFd, outFd);
+    for (;;) {
+        len = adb_read(inFd, buf, sizeof(buf));
+        if (len == 0) {
+            break;
+        }
+        if (len < 0) {
+            if (errno == EINTR) continue;
+            D("copy_to_file() : error %d\n", errno);
+            break;
+        }
+        adb_write(outFd, buf, len);
+    }
+}
+
 static void *stdin_read_thread(void *x)
 {
     int fd, fdi;
@@ -246,7 +269,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;
@@ -537,6 +562,45 @@
     return 0;
 }
 
+static int backup(int argc, char** argv) {
+    char buf[4096];
+    const char* filename = "./backup.tar";
+    int fd, outFd;
+
+    if (!strcmp("-f", argv[1])) {
+        if (argc < 3) return usage();
+        filename = argv[2];
+        argc -= 2;
+        argv += 2;
+    }
+
+    outFd = adb_open_mode(filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
+    if (outFd < 0) {
+        fprintf(stderr, "adb: unable to open file %s\n", filename);
+        return -1;
+    }
+
+    snprintf(buf, sizeof(buf), "backup");
+    for (argc--, argv++; argc; argc--, argv++) {
+        strncat(buf, ":", sizeof(buf) - strlen(buf) - 1);
+        strncat(buf, argv[0], sizeof(buf) - strlen(buf) - 1);
+    }
+
+    D("backup. filename=%s buf=%s\n", filename, buf);
+    fd = adb_connect(buf);
+    if (fd < 0) {
+        fprintf(stderr, "adb: unable to connect for backup\n");
+        adb_close(outFd);
+        return -1;
+    }
+
+    copy_to_file(fd, outFd);
+
+    adb_close(fd);
+    adb_close(outFd);
+    return 0;
+}
+
 #define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make"
 static int top_works(const char *top)
 {
@@ -683,6 +747,7 @@
     char buf[4096];
     int no_daemon = 0;
     int is_daemon = 0;
+    int is_server = 0;
     int persist = 0;
     int r;
     int quote;
@@ -719,7 +784,9 @@
 
     /* modifiers and flags */
     while(argc > 0) {
-        if(!strcmp(argv[0],"nodaemon")) {
+        if(!strcmp(argv[0],"server")) {
+            is_server = 1;
+        } else if(!strcmp(argv[0],"nodaemon")) {
             no_daemon = 1;
         } else if (!strcmp(argv[0], "fork-server")) {
             /* this is a special flag used only when the ADB client launches the ADB Server */
@@ -766,7 +833,7 @@
     adb_set_transport(ttype, serial);
     adb_set_tcp_specifics(server_port);
 
-    if ((argc > 0) && (!strcmp(argv[0],"server"))) {
+    if (is_server) {
         if (no_daemon || is_daemon) {
             r = adb_main(is_daemon, server_port);
         } else {
@@ -850,6 +917,7 @@
         }
 
         if(argc < 2) {
+            D("starting interactive shell\n");
             r = interactive_shell();
             if (h) {
                 printf("\x1b[0m");
@@ -874,9 +942,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 {
@@ -893,6 +964,7 @@
                     printf("\x1b[0m");
                     fflush(stdout);
                 }
+                D("interactive shell loop. return r=%d\n", r);
                 return r;
             }
         }
@@ -1088,6 +1160,10 @@
         return adb_connect("host:start-server");
     }
 
+    if (!strcmp(argv[0], "backup")) {
+        return backup(argc, argv);
+    }
+
     if (!strcmp(argv[0], "jdwp")) {
         int  fd = adb_connect("jdwp");
         if (fd >= 0) {
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/framebuffer_service.c b/adb/framebuffer_service.c
index 434eb1c..862dd91 100644
--- a/adb/framebuffer_service.c
+++ b/adb/framebuffer_service.c
@@ -80,20 +80,82 @@
     if(readx(fd_screencap, &h, 4)) goto done;
     if(readx(fd_screencap, &f, 4)) goto done;
 
-    /* for now always assume RGBX_8888 format */
     fbinfo.version = DDMS_RAWIMAGE_VERSION;
-    fbinfo.bpp = 32;
-    fbinfo.size = w * h * 4;
-    fbinfo.width = w;
-    fbinfo.height = h;
-    fbinfo.red_offset = 0;
-    fbinfo.red_length = 8;
-    fbinfo.green_offset = 8;
-    fbinfo.green_length = 8;
-    fbinfo.blue_offset = 16;
-    fbinfo.blue_length = 8;
-    fbinfo.alpha_offset = 24;
-    fbinfo.alpha_length = 8;
+    /* see hardware/hardware.h */
+    switch (f) {
+        case 1: /* RGBA_8888 */
+            fbinfo.bpp = 32;
+            fbinfo.size = w * h * 4;
+            fbinfo.width = w;
+            fbinfo.height = h;
+            fbinfo.red_offset = 0;
+            fbinfo.red_length = 8;
+            fbinfo.green_offset = 8;
+            fbinfo.green_length = 8;
+            fbinfo.blue_offset = 16;
+            fbinfo.blue_length = 8;
+            fbinfo.alpha_offset = 24;
+            fbinfo.alpha_length = 8;
+            break;
+        case 2: /* RGBX_8888 */
+            fbinfo.bpp = 32;
+            fbinfo.size = w * h * 4;
+            fbinfo.width = w;
+            fbinfo.height = h;
+            fbinfo.red_offset = 0;
+            fbinfo.red_length = 8;
+            fbinfo.green_offset = 8;
+            fbinfo.green_length = 8;
+            fbinfo.blue_offset = 16;
+            fbinfo.blue_length = 8;
+            fbinfo.alpha_offset = 24;
+            fbinfo.alpha_length = 0;
+            break;
+        case 3: /* RGB_888 */
+            fbinfo.bpp = 24;
+            fbinfo.size = w * h * 3;
+            fbinfo.width = w;
+            fbinfo.height = h;
+            fbinfo.red_offset = 0;
+            fbinfo.red_length = 8;
+            fbinfo.green_offset = 8;
+            fbinfo.green_length = 8;
+            fbinfo.blue_offset = 16;
+            fbinfo.blue_length = 8;
+            fbinfo.alpha_offset = 24;
+            fbinfo.alpha_length = 0;
+            break;
+        case 4: /* RGB_565 */
+            fbinfo.bpp = 16;
+            fbinfo.size = w * h * 2;
+            fbinfo.width = w;
+            fbinfo.height = h;
+            fbinfo.red_offset = 11;
+            fbinfo.red_length = 5;
+            fbinfo.green_offset = 5;
+            fbinfo.green_length = 6;
+            fbinfo.blue_offset = 0;
+            fbinfo.blue_length = 5;
+            fbinfo.alpha_offset = 0;
+            fbinfo.alpha_length = 0;
+            break;
+        case 5: /* BGRA_8888 */
+            fbinfo.bpp = 32;
+            fbinfo.size = w * h * 4;
+            fbinfo.width = w;
+            fbinfo.height = h;
+            fbinfo.red_offset = 16;
+            fbinfo.red_length = 8;
+            fbinfo.green_offset = 8;
+            fbinfo.green_length = 8;
+            fbinfo.blue_offset = 0;
+            fbinfo.blue_length = 8;
+            fbinfo.alpha_offset = 24;
+            fbinfo.alpha_length = 8;
+           break;
+        default:
+            goto done;
+    }
 
     /* write header */
     if(writex(fd, &fbinfo, sizeof(fbinfo))) goto done;
diff --git a/adb/jdwp_service.c b/adb/jdwp_service.c
index 296f718..cd62b55 100644
--- a/adb/jdwp_service.c
+++ b/adb/jdwp_service.c
@@ -499,6 +499,7 @@
 
     /* only wait for incoming connections */
     fdevent_add(control->fde, FDE_READ);
+    close_on_exec(s);
 
     D("jdwp control socket started (%d)\n", control->listen_socket);
     return 0;
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 487c7d3..ec0b0ba 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,9 +30,10 @@
 #  ifndef HAVE_WINSOCK
 #    include <netinet/in.h>
 #    include <netdb.h>
+#    include <sys/ioctl.h>
 #  endif
 #else
-#  include <sys/reboot.h>
+#  include <cutils/android_reboot.h>
 #endif
 
 typedef struct stinfo stinfo;
@@ -193,8 +194,7 @@
         waitpid(pid, &ret, 0);
     }
 
-    ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
-                    LINUX_REBOOT_CMD_RESTART2, (char *)arg);
+    ret = android_reboot(ANDROID_RB_RESTART2, 0, (char *) arg);
     if (ret < 0) {
         snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno));
         writex(fd, buf, strlen(buf));
@@ -268,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){
@@ -288,38 +289,38 @@
     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);
         dup2(pts, 2);
 
+        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)) {
@@ -407,6 +479,10 @@
         ret = create_service_thread(reboot_service, arg);
     } else if(!strncmp(name, "root:", 5)) {
         ret = create_service_thread(restart_root_service, NULL);
+    } else if(!strncmp(name, "backup:", 7)) {
+        char* arg = strdup(name+7);
+        if (arg == NULL) return -1;
+        ret = backup_service(arg);
     } else if(!strncmp(name, "tcpip:", 6)) {
         int port;
         if (sscanf(name + 6, "%d", &port) == 0) {
diff --git a/adb/sockets.c b/adb/sockets.c
index 43925e4..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;
 
@@ -569,6 +586,32 @@
     return n;
 }
 
+/* skip_host_serial return the position in a string
+   skipping over the 'serial' parameter in the ADB protocol,
+   where parameter string may be a host:port string containing
+   the protocol delimiter (colon). */
+char *skip_host_serial(char *service) {
+    char *first_colon, *serial_end;
+
+    first_colon = strchr(service, ':');
+    if (!first_colon) {
+        /* No colon in service string. */
+        return NULL;
+    }
+    serial_end = first_colon;
+    if (isdigit(serial_end[1])) {
+        serial_end++;
+        while ((*serial_end) && isdigit(*serial_end)) {
+            serial_end++;
+        }
+        if ((*serial_end) != ':') {
+            // Something other than numbers was found, reset the end.
+            serial_end = first_colon;
+        }
+    }
+    return serial_end;
+}
+
 static int smart_socket_enqueue(asocket *s, apacket *p)
 {
     unsigned len;
@@ -624,8 +667,8 @@
         char* serial_end;
         service += strlen("host-serial:");
 
-        // serial number should follow "host:"
-        serial_end = strchr(service, ':');
+        // serial number should follow "host:" and could be a host:port string.
+        serial_end = skip_host_serial(service);
         if (serial_end) {
             *serial_end = 0; // terminate string
             serial = service;
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 6372649..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 );
@@ -387,7 +395,13 @@
 
 static __inline__ int  adb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen)
 {
-    return  accept( serverfd, addr, addrlen );
+    int fd;
+
+    fd = accept(serverfd, addr, addrlen);
+    if (fd >= 0)
+        close_on_exec(fd);
+
+    return fd;
 }
 
 #undef   accept
diff --git a/adb/transport.c b/adb/transport.c
index 62bdfdb..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
 
@@ -79,7 +85,7 @@
 {
     adisconnect*  dis = t->disconnects.next;
 
-    D("run_transport_disconnects: %p (%s)\n", t, t->serial ? t->serial : "unknown" );
+    D("%s: run_transport_disconnects\n", t->serial);
     while (dis != &t->disconnects) {
         adisconnect*  next = dis->next;
         dis->func( dis->opaque, t );
@@ -87,75 +93,91 @@
     }
 }
 
+#if ADB_TRACE
+static void
+dump_packet(const char* name, const char* func, apacket* p)
+{
+    unsigned  command = p->msg.command;
+    int       len     = p->msg.data_length;
+    char      cmd[9];
+    char      arg0[12], arg1[12];
+    int       n;
+
+    for (n = 0; n < 4; n++) {
+        int  b = (command >> (n*8)) & 255;
+        if (b < 32 || b >= 127)
+            break;
+        cmd[n] = (char)b;
+    }
+    if (n == 4) {
+        cmd[4] = 0;
+    } else {
+        /* There is some non-ASCII name in the command, so dump
+            * the hexadecimal value instead */
+        snprintf(cmd, sizeof cmd, "%08x", command);
+    }
+
+    if (p->msg.arg0 < 256U)
+        snprintf(arg0, sizeof arg0, "%d", p->msg.arg0);
+    else
+        snprintf(arg0, sizeof arg0, "0x%x", p->msg.arg0);
+
+    if (p->msg.arg1 < 256U)
+        snprintf(arg1, sizeof arg1, "%d", p->msg.arg1);
+    else
+        snprintf(arg1, sizeof arg1, "0x%x", p->msg.arg1);
+
+    D("%s: %s: [%s] arg0=%s arg1=%s (len=%d) ",
+        name, func, cmd, arg0, arg1, len);
+    dump_hex(p->data, len);
+}
+#endif /* ADB_TRACE */
+
 static int
-read_packet(int  fd, apacket** ppacket)
+read_packet(int  fd, const char* name, apacket** ppacket)
 {
     char *p = (char*)ppacket;  /* really read a packet address */
     int   r;
     int   len = sizeof(*ppacket);
+    char  buff[8];
+    if (!name) {
+        snprintf(buff, sizeof buff, "fd=%d", fd);
+        name = buff;
+    }
     while(len > 0) {
         r = adb_read(fd, p, len);
         if(r > 0) {
             len -= r;
             p   += r;
         } else {
-            D("read_packet: %d error %d %d\n", fd, r, errno);
+            D("%s: read_packet (fd=%d), error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno));
             if((r < 0) && (errno == EINTR)) continue;
             return -1;
         }
     }
 
 #if ADB_TRACE
-    if (ADB_TRACING)
-    {
-        unsigned  command = (*ppacket)->msg.command;
-        int       len     = (*ppacket)->msg.data_length;
-        char      cmd[5];
-        int       n;
-
-        for (n = 0; n < 4; n++) {
-            int  b = (command >> (n*8)) & 255;
-            if (b >= 32 && b < 127)
-                cmd[n] = (char)b;
-            else
-                cmd[n] = '.';
-        }
-        cmd[4] = 0;
-
-        D("read_packet: %d ok: [%08x %s] %08x %08x (%d) ",
-          fd, command, cmd, (*ppacket)->msg.arg0, (*ppacket)->msg.arg1, len);
-        dump_hex((*ppacket)->data, len);
+    if (ADB_TRACING) {
+        dump_packet(name, "from remote", *ppacket);
     }
 #endif
     return 0;
 }
 
 static int
-write_packet(int  fd, apacket** ppacket)
+write_packet(int  fd, const char* name, apacket** ppacket)
 {
     char *p = (char*) ppacket;  /* we really write the packet address */
     int r, len = sizeof(ppacket);
+    char buff[8];
+    if (!name) {
+        snprintf(buff, sizeof buff, "fd=%d", fd);
+        name = buff;
+    }
 
 #if ADB_TRACE
-    if (ADB_TRACING)
-    {
-        unsigned  command = (*ppacket)->msg.command;
-        int       len     = (*ppacket)->msg.data_length;
-        char      cmd[5];
-        int       n;
-
-        for (n = 0; n < 4; n++) {
-            int  b = (command >> (n*8)) & 255;
-            if (b >= 32 && b < 127)
-                cmd[n] = (char)b;
-            else
-                cmd[n] = '.';
-        }
-        cmd[4] = 0;
-
-        D("write_packet: %d [%08x %s] %08x %08x (%d) ",
-          fd, command, cmd, (*ppacket)->msg.arg0, (*ppacket)->msg.arg1, len);
-        dump_hex((*ppacket)->data, len);
+    if (ADB_TRACING) {
+        dump_packet(name, "to remote", *ppacket);
     }
 #endif
     len = sizeof(ppacket);
@@ -165,7 +187,7 @@
             len -= r;
             p += r;
         } else {
-            D("write_packet: %d error %d %d\n", fd, r, errno);
+            D("%s: write_packet (fd=%d) error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno));
             if((r < 0) && (errno == EINTR)) continue;
             return -1;
         }
@@ -175,10 +197,12 @@
 
 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, &p)){
-            D("failed to read packet from transport socket on fd %d\n", fd);
+        if(read_packet(fd, t->serial, &p)){
+            D("%s: failed to read packet from transport socket on fd %d\n", t->serial, fd);
         } else {
             handle_packet(p, (atransport *) _t);
         }
@@ -204,11 +228,13 @@
     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, &p)){
+    if(write_packet(t->transport_socket, t->serial, &p)){
         fatal_errno("cannot enqueue packet on transport socket");
     }
 }
@@ -231,52 +257,51 @@
     atransport *t = _t;
     apacket *p;
 
-    D("from_remote: starting thread for transport %p, on fd %d\n", t, t->fd );
-
-    D("from_remote: transport %p SYNC online (%d)\n", t, t->sync_token + 1);
+    D("%s: starting transport output thread on fd %d, SYNC online (%d)\n",
+       t->serial, t->fd, t->sync_token + 1);
     p = get_apacket();
     p->msg.command = A_SYNC;
     p->msg.arg0 = 1;
     p->msg.arg1 = ++(t->sync_token);
     p->msg.magic = A_SYNC ^ 0xffffffff;
-    if(write_packet(t->fd, &p)) {
+    if(write_packet(t->fd, t->serial, &p)) {
         put_apacket(p);
-        D("from_remote: failed to write SYNC apacket to transport %p", t);
+        D("%s: failed to write SYNC packet\n", t->serial);
         goto oops;
     }
 
-    D("from_remote: data pump  for transport %p\n", t);
+    D("%s: data pump started\n", t->serial);
     for(;;) {
         p = get_apacket();
 
         if(t->read_from_remote(p, t) == 0){
-            D("from_remote: received remote packet, sending to transport %p\n",
-              t);
-            if(write_packet(t->fd, &p)){
+            D("%s: received remote packet, sending to transport\n",
+              t->serial);
+            if(write_packet(t->fd, t->serial, &p)){
                 put_apacket(p);
-                D("from_remote: failed to write apacket to transport %p", t);
+                D("%s: failed to write apacket to transport\n", t->serial);
                 goto oops;
             }
         } else {
-            D("from_remote: remote read failed for transport %p\n", p);
+            D("%s: remote read failed for transport\n", t->serial);
             put_apacket(p);
             break;
         }
     }
 
-    D("from_remote: SYNC offline for transport %p\n", t);
+    D("%s: SYNC offline for transport\n", t->serial);
     p = get_apacket();
     p->msg.command = A_SYNC;
     p->msg.arg0 = 0;
     p->msg.arg1 = 0;
     p->msg.magic = A_SYNC ^ 0xffffffff;
-    if(write_packet(t->fd, &p)) {
+    if(write_packet(t->fd, t->serial, &p)) {
         put_apacket(p);
-        D("from_remote: failed to write SYNC apacket to transport %p", t);
+        D("%s: failed to write SYNC apacket to transport", t->serial);
     }
 
 oops:
-    D("from_remote: thread is exiting for transport %p\n", t);
+    D("%s: transport output thread is exiting\n", t->serial);
     kick_transport(t);
     transport_unref(t);
     return 0;
@@ -288,35 +313,35 @@
     apacket *p;
     int active = 0;
 
-    D("to_remote: starting input_thread for %p, reading from fd %d\n",
-       t, t->fd);
+    D("%s: starting transport input thread, reading from fd %d\n",
+       t->serial, t->fd);
 
     for(;;){
-        if(read_packet(t->fd, &p)) {
-            D("to_remote: failed to read apacket from transport %p on fd %d\n", 
-               t, t->fd );
+        if(read_packet(t->fd, t->serial, &p)) {
+            D("%s: failed to read apacket from transport on fd %d\n",
+               t->serial, t->fd );
             break;
         }
         if(p->msg.command == A_SYNC){
             if(p->msg.arg0 == 0) {
-                D("to_remote: transport %p SYNC offline\n", t);
+                D("%s: transport SYNC offline\n", t->serial);
                 put_apacket(p);
                 break;
             } else {
                 if(p->msg.arg1 == t->sync_token) {
-                    D("to_remote: transport %p SYNC online\n", t);
+                    D("%s: transport SYNC online\n", t->serial);
                     active = 1;
                 } else {
-                    D("to_remote: trandport %p ignoring SYNC %d != %d\n",
-                      t, p->msg.arg1, t->sync_token);
+                    D("%s: transport ignoring SYNC %d != %d\n",
+                      t->serial, p->msg.arg1, t->sync_token);
                 }
             }
         } else {
             if(active) {
-                D("to_remote: transport %p got packet, sending to remote\n", t);
+                D("%s: transport got packet, sending to remote\n", t->serial);
                 t->write_to_remote(p, t);
             } else {
-                D("to_remote: transport %p ignoring packet while offline\n", t);
+                D("%s: transport ignoring packet while offline\n", t->serial);
             }
         }
 
@@ -327,7 +352,7 @@
     // while a client socket is still active.
     close_all_sockets(t);
 
-    D("to_remote: thread is exiting for transport %p, fd %d\n", t, t->fd);
+    D("%s: transport input thread is exiting, fd %d\n", t->serial, t->fd);
     kick_transport(t);
     transport_unref(t);
     return 0;
@@ -508,7 +533,7 @@
             p   += r;
         } else {
             if((r < 0) && (errno == EINTR)) continue;
-            D("transport_read_action: on fd %d, error %d: %s\n", 
+            D("transport_read_action: on fd %d, error %d: %s\n",
               fd, errno, strerror(errno));
             return -1;
         }
@@ -530,7 +555,7 @@
             p   += r;
         } else {
             if((r < 0) && (errno == EINTR)) continue;
-            D("transport_write_action: on fd %d, error %d: %s\n", 
+            D("transport_write_action: on fd %d, error %d: %s\n",
               fd, errno, strerror(errno));
             return -1;
         }
@@ -557,7 +582,7 @@
     t = m.transport;
 
     if(m.action == 0){
-        D("transport: %p removing and free'ing %d\n", t, t->transport_socket);
+        D("transport: %s removing and free'ing %d\n", t->serial, t->transport_socket);
 
             /* IMPORTANT: the remove closes one half of the
             ** socket pair.  The close closes the other half.
@@ -593,12 +618,11 @@
             fatal_errno("cannot open transport socketpair");
         }
 
-        D("transport: %p (%d,%d) starting\n", t, s[0], s[1]);
+        D("transport: %s (%d,%d) starting\n", t->serial, s[0], s[1]);
 
         t->transport_socket = s[0];
         t->fd = s[1];
 
-        D("transport: %p install %d\n", t, t->transport_socket );
         fdevent_install(&(t->transport_fde),
                         t->transport_socket,
                         transport_socket_events,
@@ -653,7 +677,7 @@
     tmsg m;
     m.transport = transport;
     m.action = 1;
-    D("transport: %p registered\n", transport);
+    D("transport: %s registered\n", transport->serial);
     if(transport_write_action(transport_registration_send, &m)) {
         fatal_errno("cannot write transport registration socket\n");
     }
@@ -664,7 +688,7 @@
     tmsg m;
     m.transport = transport;
     m.action = 0;
-    D("transport: %p removed\n", transport);
+    D("transport: %s removed\n", transport->serial);
     if(transport_write_action(transport_registration_send, &m)) {
         fatal_errno("cannot write transport registration socket\n");
     }
@@ -674,15 +698,16 @@
 static void transport_unref_locked(atransport *t)
 {
     t->ref_count--;
-    D("transport: %p R- (ref=%d)\n", t, t->ref_count);
     if (t->ref_count == 0) {
-        D("transport: %p kicking and closing\n", t);
+        D("transport: %s unref (kicking and closing)\n", t->serial);
         if (!t->kicked) {
             t->kicked = 1;
             t->kick(t);
         }
         t->close(t);
         remove_transport(t);
+    } else {
+        D("transport: %s unref (count=%d)\n", t->serial, t->ref_count);
     }
 }
 
@@ -857,7 +882,13 @@
 void register_socket_transport(int s, const char *serial, int port, int local)
 {
     atransport *t = calloc(1, sizeof(atransport));
-    D("transport: %p init'ing for socket %d, on port %d\n", t, s, port);
+    char buff[32];
+
+    if (!serial) {
+        snprintf(buff, sizeof buff, "T-%p", t);
+        serial = buff;
+    }
+    D("transport: %s init'ing for socket %d, on port %d\n", serial, s, port);
     if ( init_socket_transport(t, s, port, local) < 0 ) {
         adb_close(s);
         free(t);
@@ -961,21 +992,26 @@
 #if ADB_TRACE
     int  len0 = len;
 #endif
-    D("readx: %d %p %d\n", fd, ptr, (int)len);
+    D("readx: fd=%d wanted=%d\n", fd, (int)len);
     while(len > 0) {
         r = adb_read(fd, p, len);
         if(r > 0) {
             len -= r;
             p += r;
         } else {
-            D("readx: %d %d %s\n", fd, r, strerror(errno));
-            if((r < 0) && (errno == EINTR)) continue;
+            if (r < 0) {
+                D("readx: fd=%d error %d: %s\n", fd, errno, strerror(errno));
+                if (errno == EINTR)
+                    continue;
+            } else {
+                D("readx: fd=%d disconnected\n", fd);
+            }
             return -1;
         }
     }
 
 #if ADB_TRACE
-    D("readx: %d ok: ", fd);
+    D("readx: fd=%d wanted=%d got=%d\n", fd, len0, len0 - len);
     dump_hex( ptr, len0 );
 #endif
     return 0;
@@ -987,7 +1023,7 @@
     int r;
 
 #if ADB_TRACE
-    D("writex: %d %p %d: ", fd, ptr, (int)len);
+    D("writex: fd=%d len=%d: ", fd, (int)len);
     dump_hex( ptr, len );
 #endif
     while(len > 0) {
@@ -996,13 +1032,16 @@
             len -= r;
             p += r;
         } else {
-            D("writex: %d %d %s\n", fd, r, strerror(errno));
-            if((r < 0) && (errno == EINTR)) continue;
+            if (r < 0) {
+                D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno));
+                if (errno == EINTR)
+                    continue;
+            } else {
+                D("writex: fd=%d disconnected\n", fd);
+            }
             return -1;
         }
     }
-
-    D("writex: %d ok\n", fd);
     return 0;
 }
 
@@ -1039,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..4d55b74 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");
@@ -604,6 +605,7 @@
         ctrl.wIndex = 0;
         ctrl.wLength = sizeof(languages);
         ctrl.data = languages;
+        ctrl.timeout = 1000;
 
         result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
         if (result > 0)
@@ -619,6 +621,7 @@
             ctrl.wIndex = __le16_to_cpu(languages[i]);
             ctrl.wLength = sizeof(buffer);
             ctrl.data = buffer;
+            ctrl.timeout = 1000;
 
             result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
             if (result > 0) {
@@ -685,4 +688,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.c b/adb/usb_vendors.c
index d642566..c09fc71 100644
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -87,6 +87,8 @@
 #define VENDOR_ID_PHILIPS       0x0471
 // Texas Instruments's USB Vendor ID
 #define VENDOR_ID_TI            0x0451
+// Funai's USB Vendor ID
+#define VENDOR_ID_FUNAI         0x0F1C
 
 
 /** built-in vendor list */
@@ -117,6 +119,7 @@
     VENDOR_ID_ASUS,
     VENDOR_ID_PHILIPS,
     VENDOR_ID_TI,
+    VENDOR_ID_FUNAI,
 };
 
 #define BUILT_IN_VENDOR_COUNT    (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[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/Android.mk b/debuggerd/Android.mk
index 752c953..6cfe79b 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -29,7 +29,7 @@
 LOCAL_SRC_FILES += $(TARGET_ARCH)/crashglue.S
 LOCAL_MODULE := crasher
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE_TAGS := optional
 #LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_SHARED_LIBRARIES := libcutils libc
 include $(BUILD_EXECUTABLE)
@@ -45,7 +45,7 @@
 LOCAL_SRC_FILES := vfp-crasher.c vfp.S
 LOCAL_MODULE := vfp-crasher
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE_TAGS := optional
 LOCAL_SHARED_LIBRARIES := libcutils libc
 include $(BUILD_EXECUTABLE)
 endif # ARCH_ARM_HAVE_VFP == true
diff --git a/debuggerd/arm/machine.c b/debuggerd/arm/machine.c
index 4eb97a3..88bf054 100644
--- a/debuggerd/arm/machine.c
+++ b/debuggerd/arm/machine.c
@@ -32,6 +32,7 @@
 #include <cutils/properties.h>
 
 #include <linux/input.h>
+#include <linux/user.h>
 
 #include "utility.h"
 
@@ -53,7 +54,7 @@
                          int unwind_depth, unsigned int sp_list[],
                          bool at_fault)
 {
-    unsigned int sp, pc, p, end, data;
+    unsigned int sp, pc, lr, p, end, data;
     struct pt_regs r;
     int sp_depth;
     bool only_in_tombstone = !at_fault;
@@ -62,23 +63,25 @@
     if(ptrace(PTRACE_GETREGS, pid, 0, &r)) return;
     sp = r.ARM_sp;
     pc = r.ARM_pc;
+    lr = r.ARM_lr;
 
     _LOG(tfd, only_in_tombstone, "\ncode around pc:\n");
 
-    end = p = pc & ~3;
+    p = pc & ~3;
     p -= 32;
-    if (p > end)
+    if (p > pc)
         p = 0;
-    end += 32;
-    if (end < p)
-        end = ~0;
+    end = p + 80;
+    /* 'end - p' has to be multiples of 16 */
+    while (end < p)
+        end -= 16;
 
     /* Dump the code around PC as:
      *  addr       contents
      *  00008d34   fffffcd0 4c0eb530 b0934a0e 1c05447c
      *  00008d44   f7ff18a0 490ced94 68035860 d0012b00
      */
-    while (p <= end) {
+    while (p <  end) {
         int i;
 
         sprintf(code_buffer, "%08x ", p);
@@ -90,23 +93,24 @@
         _LOG(tfd, only_in_tombstone, "%s\n", code_buffer);
     }
 
-    if ((unsigned) r.ARM_lr != pc) {
+    if (lr != pc) {
         _LOG(tfd, only_in_tombstone, "\ncode around lr:\n");
 
-        end = p = r.ARM_lr & ~3;
+        p = lr & ~3;
         p -= 32;
-        if (p > end)
+        if (p > lr)
             p = 0;
-        end += 32;
-        if (end < p)
-            end = ~0;
+        end = p + 80;
+        /* 'end - p' has to be multiples of 16 */
+        while (end < p)
+            end -= 16;
 
         /* Dump the code around LR as:
          *  addr       contents
          *  00008d34   fffffcd0 4c0eb530 b0934a0e 1c05447c
          *  00008d44   f7ff18a0 490ced94 68035860 d0012b00
          */
-        while (p <= end) {
+        while (p < end) {
             int i;
 
             sprintf(code_buffer, "%08x ", p);
@@ -132,10 +136,10 @@
         }
     }
     else {
-        end = sp | 0x000000ff;
-        end += 0xff;
-        if (end < sp)
-            end = ~0;
+        end = p + 256;
+        /* 'end - p' has to be multiples of 4 */
+        if (end < p)
+            end = ~7;
     }
 
     _LOG(tfd, only_in_tombstone, "\nstack:\n");
@@ -173,8 +177,9 @@
     /* print another 64-byte of stack data after the last frame */
 
     end = p+64;
+    /* 'end - p' has to be multiples of 4 */
     if (end < p)
-        end = ~0;
+        end = ~7;
 
     while (p <= end) {
          data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
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/debuggerd/symbol_table.c b/debuggerd/symbol_table.c
index fd008fe..23572a3 100644
--- a/debuggerd/symbol_table.c
+++ b/debuggerd/symbol_table.c
@@ -50,7 +50,7 @@
     int length;
     char *base;
 
-    XLOG("Creating symbol table for %s\n", filename);
+    XLOG2("Creating symbol table for %s\n", filename);
     int fd = open(filename, O_RDONLY);
 
     if(fd < 0) {
@@ -126,7 +126,7 @@
                 dynsymbol_count++;
             }
         }
-        XLOG("Dynamic Symbol count: %d\n", dynsymbol_count);
+        XLOG2("Dynamic Symbol count: %d\n", dynsymbol_count);
     }
 
     if (sym_idx != -1) {
@@ -139,7 +139,7 @@
                 symbol_count++;
             }
         }
-        XLOG("Symbol count: %d\n", symbol_count);
+        XLOG2("Symbol count: %d\n", symbol_count);
     }
 
     // Now, create an entry in our symbol table structure for each symbol...
@@ -160,7 +160,7 @@
                 table->symbols[j].name = strdup(dynstr + dynsyms[i].st_name);
                 table->symbols[j].addr = dynsyms[i].st_value;
                 table->symbols[j].size = dynsyms[i].st_size;
-                XLOG("name: %s, addr: %x, size: %x\n",
+                XLOG2("name: %s, addr: %x, size: %x\n",
                     table->symbols[j].name, table->symbols[j].addr, table->symbols[j].size);
                 j++;
             }
@@ -176,7 +176,7 @@
                 table->symbols[j].name = strdup(str + syms[i].st_name);
                 table->symbols[j].addr = syms[i].st_value;
                 table->symbols[j].size = syms[i].st_size;
-                XLOG("name: %s, addr: %x, size: %x\n",
+                XLOG2("name: %s, addr: %x, size: %x\n",
                     table->symbols[j].name, table->symbols[j].addr, table->symbols[j].size);
                 j++;
             }
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 0682b85..45e2067 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -57,10 +57,19 @@
 extern void _LOG(int tfd, bool in_tombstone_only, const char *fmt, ...);
 
 #define LOG(fmt...) _LOG(-1, 0, fmt)
+
+/* Set to 1 for normal debug traces */
 #if 0
 #define XLOG(fmt...) _LOG(-1, 0, fmt)
 #else
 #define XLOG(fmt...) do {} while(0)
 #endif
 
+/* Set to 1 for chatty debug traces. Includes all resolved dynamic symbols */
+#if 0
+#define XLOG2(fmt...) _LOG(-1, 0, fmt)
+#else
+#define XLOG2(fmt...) do {} while(0)
+#endif
+
 #endif
diff --git a/fastboot/engine.c b/fastboot/engine.c
index 28a0ad9..6d94035 100644
--- a/fastboot/engine.c
+++ b/fastboot/engine.c
@@ -69,6 +69,7 @@
     Action *next;
 
     char cmd[64];    
+    const char *prod;
     void *data;
     unsigned size;
 
@@ -183,6 +184,16 @@
         return status;
     }
 
+    if (a->prod) {
+        if (strcmp(a->prod, cur_product) != 0) {
+            double split = now();
+            fprintf(stderr,"IGNORE, product is %s required only for %s [%7.3fs]\n",
+                    cur_product, a->prod, (split - a->start));
+            a->start = split;
+            return 0;
+        }
+    }
+
     yes = match(resp, value, count);
     if (invert) yes = !yes;
 
@@ -214,10 +225,12 @@
     return cb_check(a, status, resp, 1);
 }
 
-void fb_queue_require(const char *var, int invert, unsigned nvalues, const char **value)
+void fb_queue_require(const char *prod, const char *var,
+		int invert, unsigned nvalues, const char **value)
 {
     Action *a;
     a = queue_action(OP_QUERY, "getvar:%s", var);
+    a->prod = prod;
     a->data = value;
     a->size = nvalues;
     a->msg = mkmsg("checking %s", var);
@@ -244,6 +257,25 @@
     a->func = cb_display;
 }
 
+static int cb_save(Action *a, int status, char *resp)
+{
+    if (status) {
+        fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
+        return status;
+    }
+    strncpy(a->data, resp, a->size);
+    return 0;
+}
+
+void fb_queue_query_save(const char *var, char *dest, unsigned dest_size)
+{
+    Action *a;
+    a = queue_action(OP_QUERY, "getvar:%s", var);
+    a->data = (void *)dest;
+    a->size = dest_size;
+    a->func = cb_save;
+}
+
 static int cb_do_nothing(Action *a, int status, char *resp)
 {
     fprintf(stderr,"\n");
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index 973510a..4a2de20 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -9,7 +9,7 @@
  *    notice, this list of conditions and the following disclaimer.
  *  * Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the 
+ *    the documentation and/or other materials provided with the
  *    distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
@@ -19,7 +19,7 @@
  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
@@ -42,6 +42,8 @@
 
 #include "fastboot.h"
 
+char cur_product[FB_RESPONSE_SZ + 1];
+
 void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline);
 
 boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size,
@@ -68,7 +70,7 @@
     fprintf(stderr,"\n");
     va_end(ap);
     exit(1);
-}    
+}
 
 void get_my_path(char *path);
 
@@ -99,13 +101,13 @@
                 "../../../target/product/%s/%s", product, fn);
         return strdup(path);
     }
-        
+
     dir = getenv("ANDROID_PRODUCT_OUT");
     if((dir == 0) || (dir[0] == 0)) {
         die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
         return 0;
     }
-    
+
     sprintf(path, "%s/%s", dir, fn);
     return strdup(path);
 }
@@ -189,12 +191,12 @@
     int announce = 1;
 
     if(usb) return usb;
-    
+
     for(;;) {
         usb = usb_open(match_fastboot);
         if(usb) return usb;
         if(announce) {
-            announce = 0;    
+            announce = 0;
             fprintf(stderr,"< waiting for device >\n");
         }
         sleep(1);
@@ -226,6 +228,7 @@
             "  continue                                 continue with autoboot\n"
             "  reboot                                   reboot device normally\n"
             "  reboot-bootloader                        reboot device into bootloader\n"
+            "  help                                     show this help message\n"
             "\n"
             "options:\n"
             "  -w                                       erase userdata and cache\n"
@@ -236,7 +239,6 @@
             "  -b <base_addr>                           specify a custom kernel base address\n"
             "  -n <page size>                           specify the nand page size. default: 2048\n"
         );
-    exit(1);
 }
 
 void *load_bootable_image(unsigned page_size, const char *kernel, const char *ramdisk,
@@ -257,16 +259,16 @@
         fprintf(stderr, "cannot load '%s'\n", kernel);
         return 0;
     }
-    
+
         /* is this actually a boot image? */
     if(!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
         if(cmdline) bootimg_set_cmdline((boot_img_hdr*) kdata, cmdline);
-        
+
         if(ramdisk) {
             fprintf(stderr, "cannot boot a boot.img *and* ramdisk\n");
             return 0;
         }
-        
+
         *sz = ksize;
         return kdata;
     }
@@ -288,7 +290,7 @@
     if(cmdline) bootimg_set_cmdline((boot_img_hdr*) bdata, cmdline);
     fprintf(stderr,"creating boot image - %d bytes\n", bsize);
     *sz = bsize;
-    
+
     return bdata;
 }
 
@@ -297,7 +299,7 @@
     void *data;
     zipentry_t entry;
     unsigned datasz;
-    
+
     entry = lookup_zipentry(zip, name);
     if (entry == NULL) {
         fprintf(stderr, "archive does not contain '%s'\n", name);
@@ -340,16 +342,25 @@
 {
     char *val[MAX_OPTIONS];
     const char **out;
+    char *prod = NULL;
     unsigned n, count;
     char *x;
     int invert = 0;
-    
+
     if (!strncmp(name, "reject ", 7)) {
         name += 7;
         invert = 1;
     } else if (!strncmp(name, "require ", 8)) {
         name += 8;
         invert = 0;
+    } else if (!strncmp(name, "require-for-product:", 20)) {
+        // Get the product and point name past it
+        prod = name + 20;
+        name = strchr(name, ' ');
+        if (!name) return -1;
+        *name = 0;
+        name += 1;
+        invert = 0;
     }
 
     x = strchr(name, '=');
@@ -363,10 +374,10 @@
         *x = 0;
         val[count] = x + 1;
     }
-    
+
     name = strip(name);
     for(n = 0; n < count; n++) val[n] = strip(val[n]);
-    
+
     name = strip(name);
     if (name == 0) return -1;
 
@@ -381,7 +392,7 @@
         if (out[n] == 0) return -1;
     }
 
-    fb_queue_require(name, invert, n, out);
+    fb_queue_require(prod, name, invert, n, out);
     return 0;
 }
 
@@ -432,6 +443,8 @@
 
     queue_info_dump();
 
+    fb_queue_query_save("product", cur_product, sizeof(cur_product));
+
     zdata = load_file(fn, &zsize);
     if (zdata == 0) die("failed to load '%s'", fn);
 
@@ -477,11 +490,11 @@
     void *data;
     unsigned sz;
     char *xtn;
-	
+
     xtn = strrchr(fn, '.');
     if (!xtn) return;
     if (strcmp(xtn, ".img")) return;
-	
+
     strcpy(xtn,".sig");
     data = load_file(fn, &sz);
     strcpy(xtn,".img");
@@ -498,6 +511,8 @@
 
     queue_info_dump();
 
+    fb_queue_query_save("product", cur_product, sizeof(cur_product));
+
     fname = find_item("info", product);
     if (fname == 0) die("cannot find android-info.txt");
     data = load_file(fname, &sz);
@@ -521,18 +536,18 @@
     data = load_file(fname, &sz);
     if (data == 0) die("could not load system.img");
     do_send_signature(fname);
-    fb_queue_flash("system", data, sz);   
+    fb_queue_flash("system", data, sz);
 }
 
 #define skip(n) do { argc -= (n); argv += (n); } while (0)
-#define require(n) do { if (argc < (n)) usage(); } while (0)
+#define require(n) do { if (argc < (n)) {usage(); exit(1);}} while (0)
 
 int do_oem_command(int argc, char **argv)
 {
     int i;
     char command[256];
     if (argc <= 1) return 0;
-    
+
     command[0] = 0;
     while(1) {
         strcat(command,*argv);
@@ -541,7 +556,7 @@
         strcat(command," ");
     }
 
-    fb_queue_command(command,"");    
+    fb_queue_command(command,"");
     return 0;
 }
 
@@ -566,6 +581,12 @@
         return 0;
     }
 
+    if (!strcmp(*argv, "help")) {
+        usage();
+        return 0;
+    }
+
+
     serial = getenv("ANDROID_SERIAL");
 
     while (argc > 0) {
@@ -690,7 +711,7 @@
             argc = do_oem_command(argc, argv);
         } else {
             usage();
-	    return 1;
+            return 1;
         }
     }
 
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index a4b27a0..9e043fe 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -43,8 +43,10 @@
 /* engine.c - high level command queue engine */
 void fb_queue_flash(const char *ptn, void *data, unsigned sz);;
 void fb_queue_erase(const char *ptn);
-void fb_queue_require(const char *var, int invert, unsigned nvalues, const char **value);
+void fb_queue_require(const char *prod, const char *var, int invert,
+        unsigned nvalues, const char **value);
 void fb_queue_display(const char *var, const char *prettyname);
+void fb_queue_query_save(const char *var, char *dest, unsigned dest_size);
 void fb_queue_reboot(void);
 void fb_queue_command(const char *cmd, const char *msg);
 void fb_queue_download(const char *name, void *data, unsigned size);
@@ -54,4 +56,7 @@
 /* util stuff */
 void die(const char *fmt, ...);
 
+/* Current product */
+extern char cur_product[FB_RESPONSE_SZ + 1];
+
 #endif
diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c
index 78b7b98..1ba87e6 100644
--- a/fastboot/usb_linux.c
+++ b/fastboot/usb_linux.c
@@ -61,6 +61,11 @@
 #define DBG1(x...)
 #endif
 
+/* The max bulk size for linux is 16384 which is defined
+ * in drivers/usb/core/devio.c.
+ */
+#define MAX_USBFS_BULK_SIZE (16 * 1024)
+
 struct usb_handle 
 {
     char fname[64];
@@ -289,7 +294,7 @@
     
     while(len > 0) {
         int xfer;
-        xfer = (len > 4096) ? 4096 : len;
+        xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
         
         bulk.ep = h->ep_out;
         bulk.len = xfer;
@@ -323,7 +328,7 @@
     }
     
     while(len > 0) {
-        int xfer = (len > 4096) ? 4096 : len;
+        int xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
         
         bulk.ep = h->ep_in;
         bulk.len = xfer;
diff --git a/fastboot/usb_windows.c b/fastboot/usb_windows.c
index 54008a4..1050293 100644
--- a/fastboot/usb_windows.c
+++ b/fastboot/usb_windows.c
@@ -42,6 +42,7 @@
 #define DBG(x...)
 #endif
 
+#define MAX_USBFS_BULK_SIZE (1024 * 1024)
 
 /** Structure usb_handle describes our connection to the usb device via
   AdbWinApi.dll. This structure is returned from usb_open() routine and
@@ -160,7 +161,7 @@
     if (NULL != handle) {
         // Perform write
         while(len > 0) {
-            int xfer = (len > 4096) ? 4096 : len;
+            int xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
             ret = AdbWriteEndpointSync(handle->adb_write_pipe,
                                    (void*)data,
                                    (unsigned long)xfer,
@@ -200,7 +201,7 @@
     DBG("usb_read %d\n", len);
     if (NULL != handle) {
         while (1) {
-            int xfer = (len > 4096) ? 4096 : len;
+            int xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
 
 	        ret = AdbReadEndpointSync(handle->adb_read_pipe,
 	                              (void*)data,
diff --git a/gpttool/Android.mk b/gpttool/Android.mk
new file mode 100644
index 0000000..a9fffe9
--- /dev/null
+++ b/gpttool/Android.mk
@@ -0,0 +1,14 @@
+ifeq ($(HOST_OS),linux)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := gpttool.c
+LOCAL_STATIC_LIBRARIES := libz
+
+LOCAL_MODULE := gpttool
+LOCAL_MODULE_TAGS := eng
+
+include $(BUILD_HOST_EXECUTABLE)
+
+endif
diff --git a/gpttool/gpttool.c b/gpttool/gpttool.c
new file mode 100644
index 0000000..05d5177
--- /dev/null
+++ b/gpttool/gpttool.c
@@ -0,0 +1,376 @@
+/* system/core/gpttool/gpttool.c
+**
+** Copyright 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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <zlib.h>
+
+#include <linux/fs.h>
+
+#include <sys/stat.h>
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+typedef unsigned long long u64;
+
+const u8 partition_type_uuid[16] = {
+	0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44,
+	0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7,
+};
+
+
+#define EFI_VERSION 0x00010000
+#define EFI_MAGIC "EFI PART"
+#define EFI_ENTRIES 128
+#define EFI_NAMELEN 36
+
+struct efi_header {
+	u8 magic[8];
+
+	u32 version;
+	u32 header_sz;
+
+	u32 crc32;
+	u32 reserved;
+
+	u64 header_lba;
+	u64 backup_lba;
+	u64 first_lba;
+	u64 last_lba;
+
+	u8 volume_uuid[16];
+
+	u64 entries_lba;
+
+	u32 entries_count;
+	u32 entries_size;
+	u32 entries_crc32;
+} __attribute__((packed));
+
+struct efi_entry {
+	u8 type_uuid[16];
+	u8 uniq_uuid[16];
+	u64 first_lba;
+	u64 last_lba;
+	u64 attr;
+	u16 name[EFI_NAMELEN];
+};
+
+struct ptable {
+	u8 mbr[512];
+	union {
+		struct efi_header header;
+		u8 block[512];
+	};
+	struct efi_entry entry[EFI_ENTRIES];	
+};
+
+void get_uuid(u8 *uuid)
+{
+	int fd;
+	fd = open("/dev/urandom", O_RDONLY);
+	read(fd, uuid, 16);
+	close(fd);
+}
+
+void init_mbr(u8 *mbr, u32 blocks)
+{
+	mbr[0x1be] = 0x00; // nonbootable
+	mbr[0x1bf] = 0xFF; // bogus CHS
+	mbr[0x1c0] = 0xFF;
+	mbr[0x1c1] = 0xFF;
+
+	mbr[0x1c2] = 0xEE; // GPT partition
+	mbr[0x1c3] = 0xFF; // bogus CHS
+	mbr[0x1c4] = 0xFF;
+	mbr[0x1c5] = 0xFF;
+
+	mbr[0x1c6] = 0x01; // start
+	mbr[0x1c7] = 0x00;
+	mbr[0x1c8] = 0x00;
+	mbr[0x1c9] = 0x00;
+
+	memcpy(mbr + 0x1ca, &blocks, sizeof(u32));
+
+	mbr[0x1fe] = 0x55;
+	mbr[0x1ff] = 0xaa;
+}
+
+int add_ptn(struct ptable *ptbl, u64 first, u64 last, const char *name)
+{
+	struct efi_header *hdr = &ptbl->header;
+	struct efi_entry *entry = ptbl->entry;
+	unsigned n;
+
+	if (first < 34) {
+		fprintf(stderr,"partition '%s' overlaps partition table\n", name);
+		return -1;
+	}
+
+	if (last > hdr->last_lba) {
+		fprintf(stderr,"partition '%s' does not fit on disk\n", name);
+		return -1;
+	}
+	for (n = 0; n < EFI_ENTRIES; n++, entry++) {
+		if (entry->type_uuid[0])
+			continue;
+		memcpy(entry->type_uuid, partition_type_uuid, 16);
+		get_uuid(entry->uniq_uuid);
+		entry->first_lba = first;
+		entry->last_lba = last;
+		for (n = 0; (n < EFI_NAMELEN) && *name; n++)
+			entry->name[n] = *name++;
+		return 0;
+	}
+	fprintf(stderr,"out of partition table entries\n");
+	return -1;
+}
+
+int usage(void)
+{
+	fprintf(stderr,
+		"usage: gpttool write <disk> [ <partition> ]*\n"
+		"       gpttool read <disk>\n"
+		"       gpttool test [ <partition> ]*\n"
+		"\n"
+		"partition:  [<name>]:<size>[kmg] | @<file-of-partitions>\n"
+		);
+	return 0;
+}
+
+void show(struct ptable *ptbl)
+{
+	struct efi_entry *entry = ptbl->entry;
+	unsigned n, m;
+	char name[EFI_NAMELEN];
+
+	fprintf(stderr,"ptn  start block   end block     name\n");
+	fprintf(stderr,"---- ------------- ------------- --------------------\n");
+
+	for (n = 0; n < EFI_ENTRIES; n++, entry++) {
+		if (entry->type_uuid[0] == 0)
+			break;
+		for (m = 0; m < EFI_NAMELEN; m++) {
+			name[m] = entry->name[m] & 127;
+		}
+		name[m] = 0;
+		fprintf(stderr,"#%03d %13lld %13lld %s\n",
+			n + 1, entry->first_lba, entry->last_lba, name);
+	}
+}
+
+u64 find_next_lba(struct ptable *ptbl)
+{
+	struct efi_entry *entry = ptbl->entry;
+	unsigned n;
+	u64 a = 0;
+	for (n = 0; n < EFI_ENTRIES; n++, entry++) {
+		if ((entry->last_lba + 1) > a)
+			a = entry->last_lba + 1;
+	}
+	return a;
+}
+
+u64 next_lba = 0;
+
+u64 parse_size(char *sz)
+{
+	int l = strlen(sz);
+	u64 n = strtoull(sz, 0, 10);
+	if (l) {
+		switch(sz[l-1]){
+		case 'k':
+		case 'K':
+			n *= 1024;
+			break;
+		case 'm':
+		case 'M':
+			n *= (1024 * 1024);
+			break;
+		case 'g':
+		case 'G':
+			n *= (1024 * 1024 * 1024);
+			break;
+		}
+	}
+	return n;
+}
+
+int parse_ptn(struct ptable *ptbl, char *x)
+{
+	char *y = strchr(x, ':');
+	u64 sz;
+
+	if (!y) {
+		fprintf(stderr,"invalid partition entry: %s\n", x);
+		return -1;
+	}
+	*y++ = 0;
+
+	if (*y == 0) {
+		sz = ptbl->header.last_lba - next_lba;
+	} else {
+		sz = parse_size(y);
+		if (sz & 511) {
+			fprintf(stderr,"partition size must be multiple of 512\n");
+			return -1;
+		}
+		sz /= 512;
+	}
+
+	if (sz == 0) {
+		fprintf(stderr,"zero size partitions not allowed\n");
+		return -1;
+	}
+
+	if (x[0] && add_ptn(ptbl, next_lba, next_lba + sz - 1, x))
+		return -1;
+
+	next_lba = next_lba + sz;
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	struct ptable ptbl;
+	struct efi_entry *entry;
+	struct efi_header *hdr = &ptbl.header;
+	struct stat s;
+	u32 n;
+	u64 sz, blk;
+	int fd;
+	const char *device;
+	int real_disk = 0;
+
+	if (argc < 2)
+		return usage();
+
+	if (!strcmp(argv[1], "write")) {
+		if (argc < 3)
+			return usage();
+		device = argv[2];
+		argc -= 2;
+		argv += 2;
+		real_disk = 1;
+	} else if (!strcmp(argv[1], "test")) {
+		argc -= 1;
+		argv += 1;
+		real_disk = 0;
+		sz = 2097152 * 16;
+		fprintf(stderr,"< simulating 16GB disk >\n\n");
+	} else {
+		return usage();
+	}
+
+	if (real_disk) {
+		if (!strcmp(device, "/dev/sda") || 
+		    !strcmp(device, "/dev/sdb")) {
+			fprintf(stderr,"error: refusing to partition sda or sdb\n");
+			return -1;
+		}
+		
+		fd = open(device, O_RDWR);
+		if (fd < 0) {
+			fprintf(stderr,"error: cannot open '%s'\n", device);
+			return -1;
+		}
+		if (ioctl(fd, BLKGETSIZE64, &sz)) {
+			fprintf(stderr,"error: cannot query block device size\n");
+			return -1;
+		}
+		sz /= 512;
+		fprintf(stderr,"blocks %lld\n", sz);
+	}
+
+	memset(&ptbl, 0, sizeof(ptbl));
+
+	init_mbr(ptbl.mbr, sz - 1);
+
+	memcpy(hdr->magic, EFI_MAGIC, sizeof(hdr->magic));
+	hdr->version = EFI_VERSION;
+	hdr->header_sz = sizeof(struct efi_header);
+	hdr->header_lba = 1;
+	hdr->backup_lba = sz - 1;
+	hdr->first_lba = 34;
+	hdr->last_lba = sz - 1;
+	get_uuid(hdr->volume_uuid);
+	hdr->entries_lba = 2;
+	hdr->entries_count = 128;
+	hdr->entries_size = sizeof(struct efi_entry);
+
+	while (argc > 1) {
+		if (argv[1][0] == '@') {
+			char line[256], *p;
+			FILE *f;
+			f = fopen(argv[1] + 1, "r");
+			if (!f) {
+				fprintf(stderr,"cannot read partitions from '%s\n", argv[1]);
+				return -1;
+			}
+			while (fgets(line, sizeof(line), f)) {
+				p = line + strlen(line);
+				while (p > line) {
+					p--;
+					if (*p > ' ')
+						break;
+					*p = 0;
+				}
+				p = line;
+				while (*p && (*p <= ' '))
+					p++;
+				if (*p == '#')
+					continue;
+				if (*p == 0)
+					continue;
+				if (parse_ptn(&ptbl, p))
+					return -1;
+			}
+			fclose(f);
+		} else {	
+			if (parse_ptn(&ptbl, argv[1]))
+				return -1;
+		}
+		argc--;
+		argv++;
+	}
+
+	n = crc32(0, Z_NULL, 0);
+	n = crc32(n, (void*) ptbl.entry, sizeof(ptbl.entry));
+	hdr->entries_crc32 = n;
+
+	n = crc32(0, Z_NULL, 0);
+	n = crc32(n, (void*) &ptbl.header, sizeof(ptbl.header));
+	hdr->crc32 = n;
+
+	show(&ptbl);
+
+	if (real_disk) {
+  		write(fd, &ptbl, sizeof(ptbl));
+		fsync(fd);
+
+		if (ioctl(fd, BLKRRPART, 0)) {
+			fprintf(stderr,"could not re-read partition table\n");
+		}
+		close(fd);
+	}
+	return 0;
+}
diff --git a/include/cutils/android_reboot.h b/include/cutils/android_reboot.h
new file mode 100644
index 0000000..0c79be7
--- /dev/null
+++ b/include/cutils/android_reboot.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 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_ANDROID_REBOOT_H__
+#define __CUTILS_ANDROID_REBOOT_H__
+
+__BEGIN_DECLS
+
+/* Commands */
+#define ANDROID_RB_RESTART  0xDEAD0001
+#define ANDROID_RB_POWEROFF 0xDEAD0002
+#define ANDROID_RB_RESTART2 0xDEAD0003
+
+/* Flags */
+#define ANDROID_RB_FLAG_NO_SYNC       0x1
+#define ANDROID_RB_FLAG_NO_REMOUNT_RO 0x2
+
+int android_reboot(int cmd, int flags, char *arg);
+
+__END_DECLS
+
+#endif /* __CUTILS_ANDROID_REBOOT_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/cutils/native_handle.h b/include/cutils/native_handle.h
index 89d6b65..268c5d3 100644
--- a/include/cutils/native_handle.h
+++ b/include/cutils/native_handle.h
@@ -21,7 +21,7 @@
 extern "C" {
 #endif
 
-typedef struct
+typedef struct native_handle
 {
     int version;        /* sizeof(native_handle_t) */
     int numFds;         /* number of file-descriptors at &data[0] */
@@ -29,10 +29,6 @@
     int data[0];        /* numFds + numInts ints */
 } native_handle_t;
 
-
-/* keep the old definition for backward source-compatibility */
-typedef native_handle_t native_handle;
-
 /*
  * native_handle_close
  * 
diff --git a/include/cutils/str_parms.h b/include/cutils/str_parms.h
new file mode 100644
index 0000000..247c996
--- /dev/null
+++ b/include/cutils/str_parms.h
@@ -0,0 +1,49 @@
+/*
+ * 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_STR_PARMS_H
+#define __CUTILS_STR_PARMS_H
+
+#include <stdint.h>
+
+struct str_parms;
+
+struct str_parms *str_parms_create(void);
+struct str_parms *str_parms_create_str(const char *_string);
+void str_parms_destroy(struct str_parms *str_parms);
+
+void str_parms_del(struct str_parms *str_parms, const char *key);
+
+int str_parms_add_str(struct str_parms *str_parms, const char *key,
+                      const char *value);
+int str_parms_add_int(struct str_parms *str_parms, const char *key, int value);
+
+int str_parms_add_float(struct str_parms *str_parms, const char *key,
+                        float value);
+
+int str_parms_get_str(struct str_parms *str_parms, const char *key,
+                      char *out_val, int len);
+int str_parms_get_int(struct str_parms *str_parms, const char *key,
+                      int *out_val);
+int str_parms_get_float(struct str_parms *str_parms, const char *key,
+                        float *out_val);
+
+char *str_parms_to_str(struct str_parms *str_parms);
+
+/* debug */
+void str_parms_dump(struct str_parms *str_parms);
+
+#endif /* __CUTILS_STR_PARMS_H */
diff --git a/include/cutils/uevent.h b/include/cutils/uevent.h
new file mode 100644
index 0000000..587149c
--- /dev/null
+++ b/include/cutils/uevent.h
@@ -0,0 +1,32 @@
+/*
+ * 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_UEVENT_H
+#define __CUTILS_UEVENT_H
+
+#include <sys/socket.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ssize_t uevent_checked_recv(int socket, void *buffer, size_t length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_UEVENT_H */
diff --git a/include/netutils/dhcp.h b/include/netutils/dhcp.h
index 96798c5..bd16240 100644
--- a/include/netutils/dhcp.h
+++ b/include/netutils/dhcp.h
@@ -24,12 +24,12 @@
 
 extern int do_dhcp(char *iname);
 extern int dhcp_do_request(const char *ifname,
-                          in_addr_t *ipaddr,
-                          in_addr_t *gateway,
-                          in_addr_t *mask,
-                          in_addr_t *dns1,
-                          in_addr_t *dns2,
-                          in_addr_t *server,
+                          char *ipaddr,
+                          char *gateway,
+                          uint32_t *prefixLength,
+                          char *dns1,
+                          char *dns2,
+                          char *server,
                           uint32_t  *lease);
 extern int dhcp_stop(const char *ifname);
 extern int dhcp_release_lease(const char *ifname);
diff --git a/include/netutils/ifc.h b/include/netutils/ifc.h
index e245262..36827ee 100644
--- a/include/netutils/ifc.h
+++ b/include/netutils/ifc.h
@@ -36,8 +36,10 @@
 
 extern int ifc_reset_connections(const char *ifname);
 
+extern int ifc_get_addr(const char *name, in_addr_t *addr);
 extern int ifc_set_addr(const char *name, in_addr_t addr);
-extern int ifc_set_mask(const char *name, in_addr_t mask);
+extern int ifc_get_prefixLength(const char *name, uint32_t *prefixLength);
+extern int ifc_set_prefixLength(const char *name, uint32_t prefixLength);
 extern int ifc_set_hwaddr(const char *name, const void *ptr);
 
 /* This function is deprecated. Use ifc_add_route instead. */
@@ -56,7 +58,7 @@
                         in_addr_t *flags);
 
 extern int ifc_configure(const char *ifname, in_addr_t address,
-                         in_addr_t netmask, in_addr_t gateway,
+                         uint32_t prefixLength, in_addr_t gateway,
                          in_addr_t dns1, in_addr_t dns2);
 
 __END_DECLS
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index a12f731..55d9220 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -53,11 +53,12 @@
 #define AID_KEYSTORE      1017  /* keystore subsystem */
 #define AID_USB           1018  /* USB devices */
 #define AID_DRM           1019  /* DRM server */
-#define AID_DRMIO         1020  /* DRM IO server */
+#define AID_KEYCHAIN      1020  /* keychain service */
 #define AID_GPS           1021  /* GPS daemon */
-#define AID_NFC           1022  /* nfc subsystem */
+#define AID_UNUSED1       1022  /* deprecated, DO NOT USE */
 #define AID_MEDIA_RW      1023  /* internal media storage write access */
 #define AID_MTP           1024  /* MTP USB driver access */
+#define AID_NFC           1025  /* nfc subsystem */
 
 #define AID_SHELL         2000  /* adb and debug shell user */
 #define AID_CACHE         2001  /* cache access */
@@ -100,7 +101,7 @@
     { "install",   AID_INSTALL, },
     { "media",     AID_MEDIA, },
     { "drm",       AID_DRM, },
-    { "drmio",     AID_DRMIO, },
+    { "keychain",  AID_KEYCHAIN, },
     { "nfc",       AID_NFC, },
     { "shell",     AID_SHELL, },
     { "cache",     AID_CACHE, },
@@ -202,6 +203,7 @@
 		 * in user builds. */
     { 06750, AID_ROOT,      AID_SHELL,     "system/bin/run-as" },
     { 00755, AID_ROOT,      AID_SHELL,     "system/bin/*" },
+    { 00755, AID_ROOT,      AID_ROOT,      "system/lib/valgrind/*" },
     { 00755, AID_ROOT,      AID_SHELL,     "system/xbin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     "system/vendor/bin/*" },
     { 00750, AID_ROOT,      AID_SHELL,     "sbin/*" },
diff --git a/include/system/audio.h b/include/system/audio.h
new file mode 100644
index 0000000..8f2ac0c
--- /dev/null
+++ b/include/system/audio.h
@@ -0,0 +1,393 @@
+/*
+ * 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 ANDROID_AUDIO_CORE_H
+#define ANDROID_AUDIO_CORE_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <cutils/bitops.h>
+
+__BEGIN_DECLS
+
+/* The enums were moved here mostly from
+ * frameworks/base/include/media/AudioSystem.h
+ */
+
+typedef int audio_io_handle_t;
+
+/* Audio stream types */
+typedef enum {
+    AUDIO_STREAM_DEFAULT          = -1,
+    AUDIO_STREAM_VOICE_CALL       = 0,
+    AUDIO_STREAM_SYSTEM           = 1,
+    AUDIO_STREAM_RING             = 2,
+    AUDIO_STREAM_MUSIC            = 3,
+    AUDIO_STREAM_ALARM            = 4,
+    AUDIO_STREAM_NOTIFICATION     = 5,
+    AUDIO_STREAM_BLUETOOTH_SCO    = 6,
+    AUDIO_STREAM_ENFORCED_AUDIBLE = 7, /* Sounds that cannot be muted by user and must be routed to speaker */
+    AUDIO_STREAM_DTMF             = 8,
+    AUDIO_STREAM_TTS              = 9,
+
+    AUDIO_STREAM_CNT,
+    AUDIO_STREAM_MAX              = AUDIO_STREAM_CNT - 1,
+} audio_stream_type_t;
+
+/* Do not change these values without updating their counterparts
+ * in media/java/android/media/MediaRecorder.java!
+ */
+typedef enum {
+    AUDIO_SOURCE_DEFAULT             = 0,
+    AUDIO_SOURCE_MIC                 = 1,
+    AUDIO_SOURCE_VOICE_UPLINK        = 2,
+    AUDIO_SOURCE_VOICE_DOWNLINK      = 3,
+    AUDIO_SOURCE_VOICE_CALL          = 4,
+    AUDIO_SOURCE_CAMCORDER           = 5,
+    AUDIO_SOURCE_VOICE_RECOGNITION   = 6,
+    AUDIO_SOURCE_VOICE_COMMUNICATION = 7,
+
+    AUDIO_SOURCE_CNT,
+    AUDIO_SOURCE_MAX                 = AUDIO_SOURCE_CNT - 1,
+} audio_source_t;
+
+/* special audio session values
+ * (XXX: should this be living in the audio effects land?)
+ */
+typedef enum {
+    /* session for effects attached to a particular output stream
+     * (value must be less than 0)
+     */
+    AUDIO_SESSION_OUTPUT_STAGE = -1,
+
+    /* session for effects applied to output mix. These effects can
+     * be moved by audio policy manager to another output stream
+     * (value must be 0)
+     */
+    AUDIO_SESSION_OUTPUT_MIX = 0,
+} audio_session_t;
+
+/* Audio sub formats (see enum audio_format). */
+
+/* PCM sub formats */
+typedef enum {
+    AUDIO_FORMAT_PCM_SUB_16_BIT          = 0x1, /* DO NOT CHANGE */
+    AUDIO_FORMAT_PCM_SUB_8_BIT           = 0x2, /* DO NOT CHANGE */
+} audio_format_pcm_sub_fmt_t;
+
+/* MP3 sub format field definition : can use 11 LSBs in the same way as MP3
+ * frame header to specify bit rate, stereo mode, version...
+ */
+typedef enum {
+    AUDIO_FORMAT_MP3_SUB_NONE            = 0x0,
+} audio_format_mp3_sub_fmt_t;
+
+/* AMR NB/WB sub format field definition: specify frame block interleaving,
+ * bandwidth efficient or octet aligned, encoding mode for recording...
+ */
+typedef enum {
+    AUDIO_FORMAT_AMR_SUB_NONE            = 0x0,
+} audio_format_amr_sub_fmt_t;
+
+/* AAC sub format field definition: specify profile or bitrate for recording... */
+typedef enum {
+    AUDIO_FORMAT_AAC_SUB_NONE            = 0x0,
+} audio_format_aac_sub_fmt_t;
+
+/* VORBIS sub format field definition: specify quality for recording... */
+typedef enum {
+    AUDIO_FORMAT_VORBIS_SUB_NONE         = 0x0,
+} audio_format_vorbis_sub_fmt_t;
+
+/* Audio format consists in a main format field (upper 8 bits) and a sub format
+ * field (lower 24 bits).
+ *
+ * The main format indicates the main codec type. The sub format field
+ * indicates options and parameters for each format. The sub format is mainly
+ * used for record to indicate for instance the requested bitrate or profile.
+ * It can also be used for certain formats to give informations not present in
+ * the encoded audio stream (e.g. octet alignement for AMR).
+ */
+typedef enum {
+    AUDIO_FORMAT_INVALID             = 0xFFFFFFFFUL,
+    AUDIO_FORMAT_DEFAULT             = 0,
+    AUDIO_FORMAT_PCM                 = 0x00000000UL, /* DO NOT CHANGE */
+    AUDIO_FORMAT_MP3                 = 0x01000000UL,
+    AUDIO_FORMAT_AMR_NB              = 0x02000000UL,
+    AUDIO_FORMAT_AMR_WB              = 0x03000000UL,
+    AUDIO_FORMAT_AAC                 = 0x04000000UL,
+    AUDIO_FORMAT_HE_AAC_V1           = 0x05000000UL,
+    AUDIO_FORMAT_HE_AAC_V2           = 0x06000000UL,
+    AUDIO_FORMAT_VORBIS              = 0x07000000UL,
+    AUDIO_FORMAT_MAIN_MASK           = 0xFF000000UL,
+    AUDIO_FORMAT_SUB_MASK            = 0x00FFFFFFUL,
+
+    /* Aliases */
+    AUDIO_FORMAT_PCM_16_BIT          = (AUDIO_FORMAT_PCM |
+                                        AUDIO_FORMAT_PCM_SUB_16_BIT),
+    AUDIO_FORMAT_PCM_8_BIT           = (AUDIO_FORMAT_PCM |
+                                        AUDIO_FORMAT_PCM_SUB_8_BIT),
+} audio_format_t;
+
+/* Channel mask definitions must be kept in sync with JAVA values in
+ * frameworks/base/media/java/android/media/AudioFormat.java */
+typedef enum {
+    /* output channels */
+    AUDIO_CHANNEL_OUT_FRONT_LEFT            = 0x4,
+    AUDIO_CHANNEL_OUT_FRONT_RIGHT           = 0x8,
+    AUDIO_CHANNEL_OUT_FRONT_CENTER          = 0x10,
+    AUDIO_CHANNEL_OUT_LOW_FREQUENCY         = 0x20,
+    AUDIO_CHANNEL_OUT_BACK_LEFT             = 0x40,
+    AUDIO_CHANNEL_OUT_BACK_RIGHT            = 0x80,
+    AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER  = 0x100,
+    AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200,
+    AUDIO_CHANNEL_OUT_BACK_CENTER           = 0x400,
+
+    AUDIO_CHANNEL_OUT_MONO     = AUDIO_CHANNEL_OUT_FRONT_LEFT,
+    AUDIO_CHANNEL_OUT_STEREO   = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
+                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT),
+    AUDIO_CHANNEL_OUT_QUAD     = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
+                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT |
+                                  AUDIO_CHANNEL_OUT_BACK_LEFT |
+                                  AUDIO_CHANNEL_OUT_BACK_RIGHT),
+    AUDIO_CHANNEL_OUT_SURROUND = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
+                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT |
+                                  AUDIO_CHANNEL_OUT_FRONT_CENTER |
+                                  AUDIO_CHANNEL_OUT_BACK_CENTER),
+    AUDIO_CHANNEL_OUT_5POINT1  = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
+                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT |
+                                  AUDIO_CHANNEL_OUT_FRONT_CENTER |
+                                  AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
+                                  AUDIO_CHANNEL_OUT_BACK_LEFT |
+                                  AUDIO_CHANNEL_OUT_BACK_RIGHT),
+    AUDIO_CHANNEL_OUT_7POINT1  = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
+                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT |
+                                  AUDIO_CHANNEL_OUT_FRONT_CENTER |
+                                  AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
+                                  AUDIO_CHANNEL_OUT_BACK_LEFT |
+                                  AUDIO_CHANNEL_OUT_BACK_RIGHT |
+                                  AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER |
+                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER),
+    AUDIO_CHANNEL_OUT_ALL      = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
+                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT |
+                                  AUDIO_CHANNEL_OUT_FRONT_CENTER |
+                                  AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
+                                  AUDIO_CHANNEL_OUT_BACK_LEFT |
+                                  AUDIO_CHANNEL_OUT_BACK_RIGHT |
+                                  AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER |
+                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER |
+                                  AUDIO_CHANNEL_OUT_BACK_CENTER),
+
+    /* input channels */
+    AUDIO_CHANNEL_IN_LEFT            = 0x4,
+    AUDIO_CHANNEL_IN_RIGHT           = 0x8,
+    AUDIO_CHANNEL_IN_FRONT           = 0x10,
+    AUDIO_CHANNEL_IN_BACK            = 0x20,
+    AUDIO_CHANNEL_IN_LEFT_PROCESSED  = 0x40,
+    AUDIO_CHANNEL_IN_RIGHT_PROCESSED = 0x80,
+    AUDIO_CHANNEL_IN_FRONT_PROCESSED = 0x100,
+    AUDIO_CHANNEL_IN_BACK_PROCESSED  = 0x200,
+    AUDIO_CHANNEL_IN_PRESSURE        = 0x400,
+    AUDIO_CHANNEL_IN_X_AXIS          = 0x800,
+    AUDIO_CHANNEL_IN_Y_AXIS          = 0x1000,
+    AUDIO_CHANNEL_IN_Z_AXIS          = 0x2000,
+    AUDIO_CHANNEL_IN_VOICE_UPLINK    = 0x4000,
+    AUDIO_CHANNEL_IN_VOICE_DNLINK    = 0x8000,
+
+    AUDIO_CHANNEL_IN_MONO   = AUDIO_CHANNEL_IN_FRONT,
+    AUDIO_CHANNEL_IN_STEREO = (AUDIO_CHANNEL_IN_LEFT | AUDIO_CHANNEL_IN_RIGHT),
+    AUDIO_CHANNEL_IN_ALL    = (AUDIO_CHANNEL_IN_LEFT |
+                               AUDIO_CHANNEL_IN_RIGHT |
+                               AUDIO_CHANNEL_IN_FRONT |
+                               AUDIO_CHANNEL_IN_BACK|
+                               AUDIO_CHANNEL_IN_LEFT_PROCESSED |
+                               AUDIO_CHANNEL_IN_RIGHT_PROCESSED |
+                               AUDIO_CHANNEL_IN_FRONT_PROCESSED |
+                               AUDIO_CHANNEL_IN_BACK_PROCESSED|
+                               AUDIO_CHANNEL_IN_PRESSURE |
+                               AUDIO_CHANNEL_IN_X_AXIS |
+                               AUDIO_CHANNEL_IN_Y_AXIS |
+                               AUDIO_CHANNEL_IN_Z_AXIS |
+                               AUDIO_CHANNEL_IN_VOICE_UPLINK |
+                               AUDIO_CHANNEL_IN_VOICE_DNLINK),
+} audio_channels_t;
+
+typedef enum {
+    AUDIO_MODE_INVALID          = -2,
+    AUDIO_MODE_CURRENT          = -1,
+    AUDIO_MODE_NORMAL           = 0,
+    AUDIO_MODE_RINGTONE         = 1,
+    AUDIO_MODE_IN_CALL          = 2,
+    AUDIO_MODE_IN_COMMUNICATION = 3,
+
+    AUDIO_MODE_CNT,
+    AUDIO_MODE_MAX              = AUDIO_MODE_CNT - 1,
+} audio_mode_t;
+
+typedef enum {
+    AUDIO_IN_ACOUSTICS_AGC_ENABLE    = 0x0001,
+    AUDIO_IN_ACOUSTICS_AGC_DISABLE   = 0,
+    AUDIO_IN_ACOUSTICS_NS_ENABLE     = 0x0002,
+    AUDIO_IN_ACOUSTICS_NS_DISABLE    = 0,
+    AUDIO_IN_ACOUSTICS_TX_IIR_ENABLE = 0x0004,
+    AUDIO_IN_ACOUSTICS_TX_DISABLE    = 0,
+} audio_in_acoustics_t;
+
+typedef enum {
+    /* output devices */
+    AUDIO_DEVICE_OUT_EARPIECE                  = 0x1,
+    AUDIO_DEVICE_OUT_SPEAKER                   = 0x2,
+    AUDIO_DEVICE_OUT_WIRED_HEADSET             = 0x4,
+    AUDIO_DEVICE_OUT_WIRED_HEADPHONE           = 0x8,
+    AUDIO_DEVICE_OUT_BLUETOOTH_SCO             = 0x10,
+    AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET     = 0x20,
+    AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT      = 0x40,
+    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP            = 0x80,
+    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
+    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER    = 0x200,
+    AUDIO_DEVICE_OUT_AUX_DIGITAL               = 0x400,
+    AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET         = 0x800,
+    AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET         = 0x1000,
+    AUDIO_DEVICE_OUT_DEFAULT                   = 0x8000,
+    AUDIO_DEVICE_OUT_ALL      = (AUDIO_DEVICE_OUT_EARPIECE |
+                                 AUDIO_DEVICE_OUT_SPEAKER |
+                                 AUDIO_DEVICE_OUT_WIRED_HEADSET |
+                                 AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+                                 AUDIO_DEVICE_OUT_BLUETOOTH_SCO |
+                                 AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
+                                 AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT |
+                                 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
+                                 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+                                 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER |
+                                 AUDIO_DEVICE_OUT_AUX_DIGITAL |
+                                 AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
+                                 AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET |
+                                 AUDIO_DEVICE_OUT_DEFAULT),
+    AUDIO_DEVICE_OUT_ALL_A2DP = (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
+                                 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+                                 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
+    AUDIO_DEVICE_OUT_ALL_SCO  = (AUDIO_DEVICE_OUT_BLUETOOTH_SCO |
+                                 AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
+                                 AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT),
+
+    /* input devices */
+    AUDIO_DEVICE_IN_COMMUNICATION         = 0x10000,
+    AUDIO_DEVICE_IN_AMBIENT               = 0x20000,
+    AUDIO_DEVICE_IN_BUILTIN_MIC           = 0x40000,
+    AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000,
+    AUDIO_DEVICE_IN_WIRED_HEADSET         = 0x100000,
+    AUDIO_DEVICE_IN_AUX_DIGITAL           = 0x200000,
+    AUDIO_DEVICE_IN_VOICE_CALL            = 0x400000,
+    AUDIO_DEVICE_IN_BACK_MIC              = 0x800000,
+    AUDIO_DEVICE_IN_DEFAULT               = 0x80000000,
+
+    AUDIO_DEVICE_IN_ALL     = (AUDIO_DEVICE_IN_COMMUNICATION |
+                               AUDIO_DEVICE_IN_AMBIENT |
+                               AUDIO_DEVICE_IN_BUILTIN_MIC |
+                               AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET |
+                               AUDIO_DEVICE_IN_WIRED_HEADSET |
+                               AUDIO_DEVICE_IN_AUX_DIGITAL |
+                               AUDIO_DEVICE_IN_VOICE_CALL |
+                               AUDIO_DEVICE_IN_BACK_MIC |
+                               AUDIO_DEVICE_IN_DEFAULT),
+    AUDIO_DEVICE_IN_ALL_SCO = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
+} audio_devices_t;
+
+static inline bool audio_is_output_device(audio_devices_t device)
+{
+    if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_OUT_ALL) == 0))
+        return true;
+    else
+        return false;
+}
+
+static inline bool audio_is_input_device(audio_devices_t device)
+{
+    if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_IN_ALL) == 0))
+        return true;
+    else
+        return false;
+}
+
+static inline bool audio_is_a2dp_device(audio_devices_t device)
+{
+    if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_A2DP))
+        return true;
+    else
+        return false;
+}
+
+static inline bool audio_is_bluetooth_sco_device(audio_devices_t device)
+{
+    if ((popcount(device) == 1) && (device & (AUDIO_DEVICE_OUT_ALL_SCO |
+                   AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)))
+        return true;
+    else
+        return false;
+}
+
+static inline bool audio_is_input_channel(uint32_t channel)
+{
+    if ((channel & ~AUDIO_CHANNEL_IN_ALL) == 0)
+        return true;
+    else
+        return false;
+}
+
+static inline bool audio_is_output_channel(uint32_t channel)
+{
+    if ((channel & ~AUDIO_CHANNEL_OUT_ALL) == 0)
+        return true;
+    else
+        return false;
+}
+
+static inline bool audio_is_valid_format(uint32_t format)
+{
+    switch (format & AUDIO_FORMAT_MAIN_MASK) {
+    case AUDIO_FORMAT_PCM:
+    case AUDIO_FORMAT_MP3:
+    case AUDIO_FORMAT_AMR_NB:
+    case AUDIO_FORMAT_AMR_WB:
+    case AUDIO_FORMAT_AAC:
+    case AUDIO_FORMAT_HE_AAC_V1:
+    case AUDIO_FORMAT_HE_AAC_V2:
+    case AUDIO_FORMAT_VORBIS:
+        return true;
+    default:
+        return false;
+    }
+}
+
+static inline bool audio_is_linear_pcm(uint32_t format)
+{
+    switch (format) {
+    case AUDIO_FORMAT_PCM_16_BIT:
+    case AUDIO_FORMAT_PCM_8_BIT:
+        return true;
+    default:
+        return false;
+    }
+}
+
+
+__END_DECLS
+
+#endif  // ANDROID_AUDIO_CORE_H
diff --git a/include/system/camera.h b/include/system/camera.h
new file mode 100644
index 0000000..58e0c6f
--- /dev/null
+++ b/include/system/camera.h
@@ -0,0 +1,130 @@
+/*
+ * 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 SYSTEM_CORE_INCLUDE_ANDROID_CAMERA_H
+#define SYSTEM_CORE_INCLUDE_ANDROID_CAMERA_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <cutils/native_handle.h>
+#include <hardware/hardware.h>
+#include <hardware/gralloc.h>
+
+__BEGIN_DECLS
+
+/**
+ * A set of bit masks for specifying how the received preview frames are
+ * handled before the previewCallback() call.
+ *
+ * The least significant 3 bits of an "int" value are used for this purpose:
+ *
+ * ..... 0 0 0
+ *       ^ ^ ^
+ *       | | |---------> determine whether the callback is enabled or not
+ *       | |-----------> determine whether the callback is one-shot or not
+ *       |-------------> determine whether the frame is copied out or not
+ *
+ * WARNING: When a frame is sent directly without copying, it is the frame
+ * receiver's responsiblity to make sure that the frame data won't get
+ * corrupted by subsequent preview frames filled by the camera. This flag is
+ * recommended only when copying out data brings significant performance price
+ * and the handling/processing of the received frame data is always faster than
+ * the preview frame rate so that data corruption won't occur.
+ *
+ * For instance,
+ * 1. 0x00 disables the callback. In this case, copy out and one shot bits
+ *    are ignored.
+ * 2. 0x01 enables a callback without copying out the received frames. A
+ *    typical use case is the Camcorder application to avoid making costly
+ *    frame copies.
+ * 3. 0x05 is enabling a callback with frame copied out repeatedly. A typical
+ *    use case is the Camera application.
+ * 4. 0x07 is enabling a callback with frame copied out only once. A typical
+ *    use case is the Barcode scanner application.
+ */
+
+enum {
+    CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK = 0x01,
+    CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK = 0x02,
+    CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK = 0x04,
+    /** Typical use cases */
+    CAMERA_FRAME_CALLBACK_FLAG_NOOP = 0x00,
+    CAMERA_FRAME_CALLBACK_FLAG_CAMCORDER = 0x01,
+    CAMERA_FRAME_CALLBACK_FLAG_CAMERA = 0x05,
+    CAMERA_FRAME_CALLBACK_FLAG_BARCODE_SCANNER = 0x07
+};
+
+/** msgType in notifyCallback and dataCallback functions */
+enum {
+    CAMERA_MSG_ERROR = 0x0001,
+    CAMERA_MSG_SHUTTER = 0x0002,
+    CAMERA_MSG_FOCUS = 0x0004,
+    CAMERA_MSG_ZOOM = 0x0008,
+    CAMERA_MSG_PREVIEW_FRAME = 0x0010,
+    CAMERA_MSG_VIDEO_FRAME = 0x0020,
+    CAMERA_MSG_POSTVIEW_FRAME = 0x0040,
+    CAMERA_MSG_RAW_IMAGE = 0x0080,
+    CAMERA_MSG_COMPRESSED_IMAGE = 0x0100,
+    CAMERA_MSG_RAW_IMAGE_NOTIFY = 0x0200,
+    CAMERA_MSG_ALL_MSGS = 0xFFFF
+};
+
+/** cmdType in sendCommand functions */
+enum {
+    CAMERA_CMD_START_SMOOTH_ZOOM = 1,
+    CAMERA_CMD_STOP_SMOOTH_ZOOM = 2,
+    /** Set the clockwise rotation of preview display (setPreviewDisplay) in
+     * degrees. This affects the preview frames and the picture displayed after
+     * snapshot. This method is useful for portrait mode applications. Note
+     * that preview display of front-facing cameras is flipped horizontally
+     * before the rotation, that is, the image is reflected along the central
+     * vertical axis of the camera sensor. So the users can see themselves as
+     * looking into a mirror.
+     *
+     * This does not affect the order of byte array of
+     * CAMERA_MSG_PREVIEW_FRAME, CAMERA_MSG_VIDEO_FRAME,
+     * CAMERA_MSG_POSTVIEW_FRAME, CAMERA_MSG_RAW_IMAGE, or
+     * CAMERA_MSG_COMPRESSED_IMAGE. This is not allowed to be set during
+     * preview
+     */
+    CAMERA_CMD_SET_DISPLAY_ORIENTATION = 3,
+
+    /** cmdType to disable/enable shutter sound. In sendCommand passing arg1 =
+     * 0 will disable, while passing arg1 = 1 will enable the shutter sound.
+     */
+    CAMERA_CMD_ENABLE_SHUTTER_SOUND = 4,
+
+    /* cmdType to play recording sound */
+    CAMERA_CMD_PLAY_RECORDING_SOUND = 5,
+};
+
+/** camera fatal errors */
+enum {
+    CAMERA_ERROR_UNKNOWN = 1,
+    CAMERA_ERROR_SERVER_DIED = 100
+};
+
+enum {
+    CAMERA_FACING_BACK = 0, /** The facing of the camera is opposite to that of
+                 * the screen. */
+    CAMERA_FACING_FRONT = 1 /** The facing of the camera is the same as that of
+                 * the screen. */
+};
+
+__END_DECLS
+
+#endif /* SYSTEM_CORE_INCLUDE_ANDROID_CAMERA_H */
diff --git a/include/system/graphics.h b/include/system/graphics.h
new file mode 100644
index 0000000..d39bd4e
--- /dev/null
+++ b/include/system/graphics.h
@@ -0,0 +1,105 @@
+/*
+ * 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 SYSTEM_CORE_INCLUDE_ANDROID_GRAPHICS_H
+#define SYSTEM_CORE_INCLUDE_ANDROID_GRAPHICS_H
+
+__BEGIN_DECLS
+
+/**
+ * pixel format definitions
+ */
+
+enum {
+    HAL_PIXEL_FORMAT_RGBA_8888          = 1,
+    HAL_PIXEL_FORMAT_RGBX_8888          = 2,
+    HAL_PIXEL_FORMAT_RGB_888            = 3,
+    HAL_PIXEL_FORMAT_RGB_565            = 4,
+    HAL_PIXEL_FORMAT_BGRA_8888          = 5,
+    HAL_PIXEL_FORMAT_RGBA_5551          = 6,
+    HAL_PIXEL_FORMAT_RGBA_4444          = 7,
+
+    /* 0x8 - 0xFF range unavailable */
+
+    /*
+     * 0x100 - 0x1FF
+     *
+     * This range is reserved for pixel formats that are specific to the HAL
+     * implementation.  Implementations can use any value in this range to
+     * communicate video pixel formats between their HAL modules.  These formats
+     * must not have an alpha channel.  Additionally, an EGLimage created from a
+     * gralloc buffer of one of these formats must be supported for use with the
+     * GL_OES_EGL_image_external OpenGL ES extension.
+     */
+
+    /*
+     * Android YUV format:
+     *
+     * This format is exposed outside of the HAL to software decoders and
+     * applications.  EGLImageKHR must support it in conjunction with the
+     * OES_EGL_image_external extension.
+     *
+     * YV12 is a 4:2:0 YCrCb planar format comprised of a WxH Y plane followed
+     * by (W/2) x (H/2) Cr and Cb planes.
+     *
+     * This format assumes
+     * - an even width
+     * - an even height
+     * - a horizontal stride multiple of 16 pixels
+     * - a vertical stride equal to the height
+     *
+     *   y_size = stride * height
+     *   c_size = ALIGN(stride/2, 16) * height/2
+     *   size = y_size + c_size * 2
+     *   cr_offset = y_size
+     *   cb_offset = y_size + c_size
+     *
+     */
+    HAL_PIXEL_FORMAT_YV12   = 0x32315659, // YCrCb 4:2:0 Planar
+
+
+
+    /* Legacy formats (deprecated), used by ImageFormat.java */
+    HAL_PIXEL_FORMAT_YCbCr_422_SP       = 0x10, // NV16
+    HAL_PIXEL_FORMAT_YCrCb_420_SP       = 0x11, // NV21
+    HAL_PIXEL_FORMAT_YCbCr_422_I        = 0x14, // YUY2
+};
+
+
+/**
+ * Transformation definitions
+ *
+ * IMPORTANT NOTE:
+ * HAL_TRANSFORM_ROT_90 is applied CLOCKWISE and AFTER HAL_TRANSFORM_FLIP_{H|V}.
+ *
+ */
+
+enum {
+    /* flip source image horizontally (around the vertical axis) */
+    HAL_TRANSFORM_FLIP_H    = 0x01,
+    /* flip source image vertically (around the horizontal axis)*/
+    HAL_TRANSFORM_FLIP_V    = 0x02,
+    /* rotate source image 90 degrees clockwise */
+    HAL_TRANSFORM_ROT_90    = 0x04,
+    /* rotate source image 180 degrees */
+    HAL_TRANSFORM_ROT_180   = 0x03,
+    /* rotate source image 270 degrees clockwise */
+    HAL_TRANSFORM_ROT_270   = 0x07,
+};
+
+__END_DECLS
+
+#endif /* SYSTEM_CORE_INCLUDE_ANDROID_GRAPHICS_H */
diff --git a/include/system/window.h b/include/system/window.h
new file mode 100644
index 0000000..4b0381b
--- /dev/null
+++ b/include/system/window.h
@@ -0,0 +1,457 @@
+/*
+ * 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 SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H
+#define SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <system/graphics.h>
+#include <cutils/native_handle.h>
+
+__BEGIN_DECLS
+
+/*****************************************************************************/
+
+#define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d) \
+    (((unsigned)(a)<<24)|((unsigned)(b)<<16)|((unsigned)(c)<<8)|(unsigned)(d))
+
+#define ANDROID_NATIVE_WINDOW_MAGIC \
+    ANDROID_NATIVE_MAKE_CONSTANT('_','w','n','d')
+
+#define ANDROID_NATIVE_BUFFER_MAGIC \
+    ANDROID_NATIVE_MAKE_CONSTANT('_','b','f','r')
+
+// ---------------------------------------------------------------------------
+
+typedef const native_handle_t* buffer_handle_t;
+
+// ---------------------------------------------------------------------------
+
+typedef struct android_native_rect_t
+{
+    int32_t left;
+    int32_t top;
+    int32_t right;
+    int32_t bottom;
+} android_native_rect_t;
+
+// ---------------------------------------------------------------------------
+
+typedef struct android_native_base_t
+{
+    /* a magic value defined by the actual EGL native type */
+    int magic;
+
+    /* the sizeof() of the actual EGL native type */
+    int version;
+
+    void* reserved[4];
+
+    /* reference-counting interface */
+    void (*incRef)(struct android_native_base_t* base);
+    void (*decRef)(struct android_native_base_t* base);
+} android_native_base_t;
+
+typedef struct ANativeWindowBuffer
+{
+#ifdef __cplusplus
+    ANativeWindowBuffer() {
+        common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
+        common.version = sizeof(ANativeWindowBuffer);
+        memset(common.reserved, 0, sizeof(common.reserved));
+    }
+
+    // Implement the methods that sp<ANativeWindowBuffer> expects so that it
+    // can be used to automatically refcount ANativeWindowBuffer's.
+    void incStrong(const void* id) const {
+        common.incRef(const_cast<android_native_base_t*>(&common));
+    }
+    void decStrong(const void* id) const {
+        common.decRef(const_cast<android_native_base_t*>(&common));
+    }
+#endif
+
+    struct android_native_base_t common;
+
+    int width;
+    int height;
+    int stride;
+    int format;
+    int usage;
+
+    void* reserved[2];
+
+    buffer_handle_t handle;
+
+    void* reserved_proc[8];
+} ANativeWindowBuffer_t;
+
+// Old typedef for backwards compatibility.
+typedef ANativeWindowBuffer_t android_native_buffer_t;
+
+// ---------------------------------------------------------------------------
+
+/* attributes queriable with query() */
+enum {
+    NATIVE_WINDOW_WIDTH     = 0,
+    NATIVE_WINDOW_HEIGHT,
+    NATIVE_WINDOW_FORMAT,
+
+    /* The minimum number of buffers that must remain un-dequeued after a buffer
+     * has been queued.  This value applies only if set_buffer_count was used to
+     * override the number of buffers and if a buffer has since been queued.
+     * Users of the set_buffer_count ANativeWindow method should query this
+     * value before calling set_buffer_count.  If it is necessary to have N
+     * buffers simultaneously dequeued as part of the steady-state operation,
+     * and this query returns M then N+M buffers should be requested via
+     * native_window_set_buffer_count.
+     *
+     * Note that this value does NOT apply until a single buffer has been
+     * queued.  In particular this means that it is possible to:
+     *
+     * 1. Query M = min undequeued buffers
+     * 2. Set the buffer count to N + M
+     * 3. Dequeue all N + M buffers
+     * 4. Cancel M buffers
+     * 5. Queue, dequeue, queue, dequeue, ad infinitum
+     */
+    NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+
+    /* Check whether queueBuffer operations on the ANativeWindow send the buffer
+     * to the window compositor.  The query sets the returned 'value' argument
+     * to 1 if the ANativeWindow DOES send queued buffers directly to the window
+     * compositor and 0 if the buffers do not go directly to the window
+     * compositor.
+     *
+     * This can be used to determine whether protected buffer content should be
+     * sent to the ANativeWindow.  Note, however, that a result of 1 does NOT
+     * indicate that queued buffers will be protected from applications or users
+     * capturing their contents.  If that behavior is desired then some other
+     * mechanism (e.g. the GRALLOC_USAGE_PROTECTED flag) should be used in
+     * conjunction with this query.
+     */
+    NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
+
+    /* Get the concrete type of a ANativeWindow.  See below for the list of
+     * possible return values.
+     *
+     * This query should not be used outside the Android framework and will
+     * likely be removed in the near future.
+     */
+    NATIVE_WINDOW_CONCRETE_TYPE,
+};
+
+/* valid operations for the (*perform)() hook */
+enum {
+    NATIVE_WINDOW_SET_USAGE  = 0,
+    NATIVE_WINDOW_CONNECT,
+    NATIVE_WINDOW_DISCONNECT,
+    NATIVE_WINDOW_SET_CROP,
+    NATIVE_WINDOW_SET_BUFFER_COUNT,
+    NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
+    NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
+    NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP,
+};
+
+/* parameter for NATIVE_WINDOW_[DIS]CONNECT */
+enum {
+    NATIVE_WINDOW_API_EGL = 1
+};
+
+/* parameter for NATIVE_WINDOW_SET_BUFFERS_TRANSFORM */
+enum {
+    /* flip source image horizontally */
+    NATIVE_WINDOW_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H ,
+    /* flip source image vertically */
+    NATIVE_WINDOW_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V,
+    /* rotate source image 90 degrees clock-wise */
+    NATIVE_WINDOW_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
+    /* rotate source image 180 degrees */
+    NATIVE_WINDOW_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
+    /* rotate source image 270 degrees clock-wise */
+    NATIVE_WINDOW_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,
+};
+
+/* values returned by the NATIVE_WINDOW_CONCRETE_TYPE query */
+enum {
+    NATIVE_WINDOW_FRAMEBUFFER,                  // FramebufferNativeWindow
+    NATIVE_WINDOW_SURFACE,                      // Surface
+    NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT,       // SurfaceTextureClient
+};
+
+/* parameter for NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
+ *
+ * Special timestamp value to indicate that timestamps should be auto-generated
+ * by the native window when queueBuffer is called.  This is equal to INT64_MIN,
+ * defined directly to avoid problems with C99/C++ inclusion of stdint.h.
+ */
+static const int64_t NATIVE_WINDOW_TIMESTAMP_AUTO = (-9223372036854775807LL-1);
+
+struct ANativeWindow
+{
+#ifdef __cplusplus
+    ANativeWindow()
+        : flags(0), minSwapInterval(0), maxSwapInterval(0), xdpi(0), ydpi(0)
+    {
+        common.magic = ANDROID_NATIVE_WINDOW_MAGIC;
+        common.version = sizeof(ANativeWindow);
+        memset(common.reserved, 0, sizeof(common.reserved));
+    }
+
+    // Implement the methods that sp<ANativeWindow> expects so that it
+    // can be used to automatically refcount ANativeWindow's.
+    void incStrong(const void* id) const {
+        common.incRef(const_cast<android_native_base_t*>(&common));
+    }
+    void decStrong(const void* id) const {
+        common.decRef(const_cast<android_native_base_t*>(&common));
+    }
+#endif
+
+    struct android_native_base_t common;
+
+    /* flags describing some attributes of this surface or its updater */
+    const uint32_t flags;
+
+    /* min swap interval supported by this updated */
+    const int   minSwapInterval;
+
+    /* max swap interval supported by this updated */
+    const int   maxSwapInterval;
+
+    /* horizontal and vertical resolution in DPI */
+    const float xdpi;
+    const float ydpi;
+
+    /* Some storage reserved for the OEM's driver. */
+    intptr_t    oem[4];
+
+    /*
+     * Set the swap interval for this surface.
+     *
+     * Returns 0 on success or -errno on error.
+     */
+    int     (*setSwapInterval)(struct ANativeWindow* window,
+                int interval);
+
+    /*
+     * hook called by EGL to acquire a buffer. After this call, the buffer
+     * is not locked, so its content cannot be modified.
+     * this call may block if no buffers are available.
+     *
+     * Returns 0 on success or -errno on error.
+     */
+    int     (*dequeueBuffer)(struct ANativeWindow* window,
+                struct ANativeWindowBuffer** buffer);
+
+    /*
+     * hook called by EGL to lock a buffer. This MUST be called before modifying
+     * the content of a buffer. The buffer must have been acquired with
+     * dequeueBuffer first.
+     *
+     * Returns 0 on success or -errno on error.
+     */
+    int     (*lockBuffer)(struct ANativeWindow* window,
+                struct ANativeWindowBuffer* buffer);
+   /*
+    * hook called by EGL when modifications to the render buffer are done.
+    * This unlocks and post the buffer.
+    *
+    * Buffers MUST be queued in the same order than they were dequeued.
+    *
+    * Returns 0 on success or -errno on error.
+    */
+    int     (*queueBuffer)(struct ANativeWindow* window,
+                struct ANativeWindowBuffer* buffer);
+
+    /*
+     * hook used to retrieve information about the native window.
+     *
+     * Returns 0 on success or -errno on error.
+     */
+    int     (*query)(const struct ANativeWindow* window,
+                int what, int* value);
+
+    /*
+     * hook used to perform various operations on the surface.
+     * (*perform)() is a generic mechanism to add functionality to
+     * ANativeWindow while keeping backward binary compatibility.
+     *
+     * DO NOT CALL THIS HOOK DIRECTLY.  Instead, use the helper functions
+     * defined below.
+     *
+     *  (*perform)() returns -ENOENT if the 'what' parameter is not supported
+     *  by the surface's implementation.
+     *
+     * The valid operations are:
+     *     NATIVE_WINDOW_SET_USAGE
+     *     NATIVE_WINDOW_CONNECT
+     *     NATIVE_WINDOW_DISCONNECT
+     *     NATIVE_WINDOW_SET_CROP
+     *     NATIVE_WINDOW_SET_BUFFER_COUNT
+     *     NATIVE_WINDOW_SET_BUFFERS_GEOMETRY
+     *     NATIVE_WINDOW_SET_BUFFERS_TRANSFORM
+     *     NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
+     *
+     */
+
+    int     (*perform)(struct ANativeWindow* window,
+                int operation, ... );
+
+    /*
+     * hook used to cancel a buffer that has been dequeued.
+     * No synchronization is performed between dequeue() and cancel(), so
+     * either external synchronization is needed, or these functions must be
+     * called from the same thread.
+     */
+    int     (*cancelBuffer)(struct ANativeWindow* window,
+                struct ANativeWindowBuffer* buffer);
+
+
+    void* reserved_proc[2];
+};
+
+ /* Backwards compatibility: use ANativeWindow (struct ANativeWindow in C).
+  * android_native_window_t is deprecated.
+  */
+typedef struct ANativeWindow ANativeWindow;
+typedef struct ANativeWindow android_native_window_t;
+
+/*
+ *  native_window_set_usage(..., usage)
+ *  Sets the intended usage flags for the next buffers
+ *  acquired with (*lockBuffer)() and on.
+ *  By default (if this function is never called), a usage of
+ *      GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE
+ *  is assumed.
+ *  Calling this function will usually cause following buffers to be
+ *  reallocated.
+ */
+
+static inline int native_window_set_usage(
+        struct ANativeWindow* window, int usage)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_USAGE, usage);
+}
+
+/*
+ * native_window_connect(..., NATIVE_WINDOW_API_EGL)
+ * Must be called by EGL when the window is made current.
+ * Returns -EINVAL if for some reason the window cannot be connected, which
+ * can happen if it's connected to some other API.
+ */
+static inline int native_window_connect(
+        struct ANativeWindow* window, int api)
+{
+    return window->perform(window, NATIVE_WINDOW_CONNECT, api);
+}
+
+/*
+ * native_window_disconnect(..., NATIVE_WINDOW_API_EGL)
+ * Must be called by EGL when the window is made not current.
+ * An error is returned if for instance the window wasn't connected in the
+ * first place.
+ */
+static inline int native_window_disconnect(
+        struct ANativeWindow* window, int api)
+{
+    return window->perform(window, NATIVE_WINDOW_DISCONNECT, api);
+}
+
+/*
+ * native_window_set_crop(..., crop)
+ * Sets which region of the next queued buffers needs to be considered.
+ * A buffer's crop region is scaled to match the surface's size.
+ *
+ * The specified crop region applies to all buffers queued after it is called.
+ *
+ * if 'crop' is NULL, subsequently queued buffers won't be cropped.
+ *
+ * An error is returned if for instance the crop region is invalid,
+ * out of the buffer's bound or if the window is invalid.
+ */
+static inline int native_window_set_crop(
+        struct ANativeWindow* window,
+        android_native_rect_t const * crop)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_CROP, crop);
+}
+
+/*
+ * native_window_set_buffer_count(..., count)
+ * Sets the number of buffers associated with this native window.
+ */
+static inline int native_window_set_buffer_count(
+        struct ANativeWindow* window,
+        size_t bufferCount)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFER_COUNT, bufferCount);
+}
+
+/*
+ * native_window_set_buffers_geometry(..., int w, int h, int format)
+ * All buffers dequeued after this call will have the geometry specified.
+ * In particular, all buffers will have a fixed-size, independent form the
+ * native-window size. They will be appropriately scaled to the window-size
+ * upon composition.
+ *
+ * If all parameters are 0, the normal behavior is restored. That is,
+ * dequeued buffers following this call will be sized to the window's size.
+ *
+ * Calling this function will reset the window crop to a NULL value, which
+ * disables cropping of the buffers.
+ */
+static inline int native_window_set_buffers_geometry(
+        struct ANativeWindow* window,
+        int w, int h, int format)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
+            w, h, format);
+}
+
+/*
+ * native_window_set_buffers_transform(..., int transform)
+ * All buffers queued after this call will be displayed transformed according
+ * to the transform parameter specified.
+ */
+static inline int native_window_set_buffers_transform(
+        struct ANativeWindow* window,
+        int transform)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
+            transform);
+}
+
+/*
+ * native_window_set_buffers_timestamp(..., int64_t timestamp)
+ * All buffers queued after this call will be associated with the timestamp
+ * parameter specified. If the timestamp is set to NATIVE_WINDOW_TIMESTAMP_AUTO
+ * (the default), timestamps will be generated automatically when queueBuffer is
+ * called. The timestamp is measured in nanoseconds, and must be monotonically
+ * increasing.
+ */
+static inline int native_window_set_buffers_timestamp(
+        struct ANativeWindow* window,
+        int64_t timestamp)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP,
+            timestamp);
+}
+
+__END_DECLS
+
+#endif SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H
diff --git a/include/sysutils/SocketClient.h b/include/sysutils/SocketClient.h
index 2fcc331..d6bb7d5 100644
--- a/include/sysutils/SocketClient.h
+++ b/include/sysutils/SocketClient.h
@@ -19,6 +19,10 @@
     /* Peer group ID */
     gid_t mGid;
 
+    /* Reference count (starts at 1) */
+    pthread_mutex_t mRefCountMutex;
+    int mRefCount;
+
 public:
     SocketClient(int sock);
     virtual ~SocketClient() {}
@@ -34,6 +38,13 @@
 
     // Sending binary data:
     int sendData(const void *data, int len);
+
+    // Optional reference counting.  Reference count starts at 1.  If
+    // it's decremented to 0, it deletes itself.
+    // SocketListener creates a SocketClient (at refcount 1) and calls
+    // decRef() when it's done with the client.
+    void incRef();
+    bool decRef(); // returns true at 0 (but note: SocketClient already deleted)
 };
 
 typedef android::List<SocketClient *> SocketClientCollection;
diff --git a/include/usbhost/usbhost.h b/include/usbhost/usbhost.h
index 7ef7ace..9a6b59c 100644
--- a/include/usbhost/usbhost.h
+++ b/include/usbhost/usbhost.h
@@ -47,6 +47,7 @@
     int actual_length;
     int max_packet_size;
     void *private_data; /* struct usbdevfs_urb* */
+    int endpoint;
     void *client_data;  /* free for use by client */
 };
 
@@ -125,15 +126,6 @@
 
 const struct usb_device_descriptor* usb_device_get_device_descriptor(struct usb_device *device);
 
-/* Sends a control message to the specified device on endpoint zero */
-int usb_device_send_control(struct usb_device *device,
-                            int requestType,
-                            int request,
-                            int value,
-                            int index,
-                            int length,
-                            void* buffer);
-
 /* Returns a USB descriptor string for the given string ID.
  * Used to implement usb_device_get_manufacturer_name,
  * usb_device_get_product_name and usb_device_get_serial.
@@ -177,6 +169,32 @@
 /* Releases the specified interface of a USB device */
 int usb_device_release_interface(struct usb_device *device, unsigned int interface);
 
+/* Requests the kernel to connect or disconnect its driver for the specified interface.
+ * This can be used to ask the kernel to disconnect its driver for a device
+ * so usb_device_claim_interface can claim it instead.
+ */
+int usb_device_connect_kernel_driver(struct usb_device *device,
+        unsigned int interface, int connect);
+
+/* Sends a control message to the specified device on endpoint zero */
+int usb_device_control_transfer(struct usb_device *device,
+                            int requestType,
+                            int request,
+                            int value,
+                            int index,
+                            void* buffer,
+                            int length,
+                            unsigned int timeout);
+
+/* Reads or writes on a bulk endpoint.
+ * Returns number of bytes transferred, or negative value for error.
+ */
+int usb_device_bulk_transfer(struct usb_device *device,
+                            int endpoint,
+                            void* buffer,
+                            int length,
+                            unsigned int timeout);
+
 /* Creates a new usb_request. */
 struct usb_request *usb_request_new(struct usb_device *dev,
         const struct usb_endpoint_descriptor *ep_desc);
diff --git a/init/builtins.c b/init/builtins.c
index 490ad48..f2f76b7 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -322,7 +322,7 @@
             return -1;
         }
 
-        return 0;
+        goto exit_success;
     } else if (!strncmp(source, "loop@", 5)) {
         int mode, loop, fd;
         struct loop_info info;
@@ -353,7 +353,7 @@
                     }
 
                     close(loop);
-                    return 0;
+                    goto exit_success;
                 }
             }
 
@@ -393,12 +393,6 @@
             } else {
                 return -1;
             }
-        } else {
-            if (!strcmp(target, DATA_MNT_POINT)) {
-                /* We succeeded in mounting /data, so it's not encrypted */
-                property_set("ro.crypto.state", "unencrypted");
-                action_for_each_trigger("nonencrypted", action_add_queue_tail);
-            }
         }
 
         if (!strcmp(target, DATA_MNT_POINT)) {
@@ -414,8 +408,27 @@
             snprintf(fs_flags, sizeof(fs_flags), "0x%8.8x", flags);
             property_set("ro.crypto.fs_flags", fs_flags);
         }
-        return 0;
     }
+
+exit_success:
+    /* If not running encrypted, then set the property saying we are
+     * unencrypted, and also trigger the action for a nonencrypted system.
+     */
+    if (!strcmp(target, DATA_MNT_POINT)) {
+        const char *prop;
+
+        prop = property_get("ro.crypto.state");
+        if (! prop) {
+            prop = "notset";
+        }
+        if (strcmp(prop, "encrypted")) {
+            property_set("ro.crypto.state", "unencrypted");
+            action_for_each_trigger("nonencrypted", action_add_queue_tail);
+        }
+    }
+
+    return 0;
+
 }
 
 int do_setkey(int nargs, char **args)
@@ -619,6 +632,14 @@
     return -1;
 }
 
+int do_load_persist_props(int nargs, char **args) {
+    if (nargs == 1) {
+        load_persist_props();
+        return 0;
+    }
+    return -1;
+}
+
 int do_wait(int nargs, char **args)
 {
     if (nargs == 2) {
diff --git a/init/devices.c b/init/devices.c
index 036b8f7..a200c95 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -34,6 +34,8 @@
 #include <asm/page.h>
 #include <sys/wait.h>
 
+#include <cutils/uevent.h>
+
 #include "devices.h"
 #include "util.h"
 #include "log.h"
@@ -97,8 +99,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 +221,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 +403,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 +423,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 +462,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 +490,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 +668,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 +710,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 +753,6 @@
 static void handle_firmware_event(struct uevent *uevent)
 {
     pid_t pid;
-    int status;
     int ret;
 
     if(strcmp(uevent->subsystem, "firmware"))
@@ -634,45 +766,15 @@
     if (!pid) {
         process_firmware_event(uevent);
         exit(EXIT_SUCCESS);
-    } else {
-        do {
-            ret = waitpid(pid, &status, 0);
-        } while (ret == -1 && errno == EINTR);
     }
 }
 
 #define UEVENT_MSG_LEN  1024
 void handle_device_fd()
 {
-    for(;;) {
-        char msg[UEVENT_MSG_LEN+2];
-        char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
-        struct iovec iov = {msg, sizeof(msg)};
-        struct sockaddr_nl snl;
-        struct msghdr hdr = {&snl, sizeof(snl), &iov, 1, cred_msg, sizeof(cred_msg), 0};
-
-        ssize_t n = recvmsg(device_fd, &hdr, 0);
-        if (n <= 0) {
-            break;
-        }
-
-        if ((snl.nl_groups != 1) || (snl.nl_pid != 0)) {
-            /* ignoring non-kernel netlink multicast message */
-            continue;
-        }
-
-        struct cmsghdr * cmsg = CMSG_FIRSTHDR(&hdr);
-        if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
-            /* no sender credentials received, ignore message */
-            continue;
-        }
-
-        struct ucred * cred = (struct ucred *)CMSG_DATA(cmsg);
-        if (cred->uid != 0) {
-            /* message from non-root user, ignore */
-            continue;
-        }
-
+    char msg[UEVENT_MSG_LEN+2];
+    int n;
+    while ((n = uevent_checked_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) {
         if(n >= UEVENT_MSG_LEN)   /* overflow -- discard */
             continue;
 
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/init_parser.c b/init/init_parser.c
index 0898ae8..e8e65ac 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -113,6 +113,7 @@
         break;
     case 'l':
         if (!strcmp(s, "oglevel")) return K_loglevel;
+        if (!strcmp(s, "oad_persist_props")) return K_load_persist_props;
         break;
     case 'm':
         if (!strcmp(s, "kdir")) return K_mkdir;
diff --git a/init/keywords.h b/init/keywords.h
index c977fd7..95acd01 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -30,6 +30,7 @@
 int do_chown(int nargs, char **args);
 int do_chmod(int nargs, char **args);
 int do_loglevel(int nargs, char **args);
+int do_load_persist_props(int nargs, char **args);
 int do_wait(int nargs, char **args);
 #define __MAKE_KEYWORD_ENUM__
 #define KEYWORD(symbol, flags, nargs, func) K_##symbol,
@@ -81,6 +82,7 @@
     KEYWORD(chown,       COMMAND, 2, do_chown)
     KEYWORD(chmod,       COMMAND, 2, do_chmod)
     KEYWORD(loglevel,    COMMAND, 1, do_loglevel)
+    KEYWORD(load_persist_props,    COMMAND, 0, do_load_persist_props)
     KEYWORD(ioprio,      OPTION,  0, 0)
 #ifdef __MAKE_KEYWORD_ENUM__
     KEYWORD_COUNT,
diff --git a/init/property_service.c b/init/property_service.c
index 0bd2597..c8d6c09 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -61,6 +61,7 @@
     { "net.rmnet0.",      AID_RADIO,    0 },
     { "net.gprs.",        AID_RADIO,    0 },
     { "net.ppp",          AID_RADIO,    0 },
+    { "net.qmi",          AID_RADIO,    0 },
     { "ril.",             AID_RADIO,    0 },
     { "gsm.",             AID_RADIO,    0 },
     { "persist.radio",    AID_RADIO,    0 },
@@ -188,15 +189,6 @@
     __futex_wake(&pi->serial, INT32_MAX);
 }
 
-static int property_write(prop_info *pi, const char *value)
-{
-    int valuelen = strlen(value);
-    if(valuelen >= PROP_VALUE_MAX) return -1;
-    update_prop_info(pi, value, valuelen);
-    return 0;
-}
-
-
 /*
  * Checks permissions for starting/stoping system services.
  * AID_SYSTEM and AID_ROOT are always allowed.
@@ -383,8 +375,8 @@
     }
 
     r = recv(s, &msg, sizeof(msg), 0);
-    close(s);
     if(r != sizeof(prop_msg)) {
+        close(s);
         ERROR("sys_prop: mis-match msg size recieved: %d expected: %d\n",
               r, sizeof(prop_msg));
         return;
@@ -396,6 +388,9 @@
         msg.value[PROP_VALUE_MAX-1] = 0;
 
         if(memcmp(msg.name,"ctl.",4) == 0) {
+            // Keep the old close-socket-early behavior when handling
+            // ctl.* properties.
+            close(s);
             if (check_control_perms(msg.value, cr.uid, cr.gid)) {
                 handle_control_message((char*) msg.name + 4, (char*) msg.value);
             } else {
@@ -409,10 +404,16 @@
                 ERROR("sys_prop: permission denied uid:%d  name:%s\n",
                       cr.uid, msg.name);
             }
+
+            // Note: bionic's property client code assumes that the
+            // property server will not close the socket until *AFTER*
+            // the property is written to memory.
+            close(s);
         }
         break;
 
     default:
+        close(s);
         break;
     }
 }
@@ -514,6 +515,18 @@
     return property_area_inited;
 }
 
+/* When booting an encrypted system, /data is not mounted when the
+ * property service is started, so any properties stored there are
+ * not loaded.  Vold triggers init to load these properties once it
+ * has mounted /data.
+ */
+void load_persist_props(void)
+{
+    load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
+    /* Read persistent properties after all default values have been loaded. */
+    load_persistent_properties();
+}
+
 void start_property_service(void)
 {
     int fd;
diff --git a/init/property_service.h b/init/property_service.h
index 045d20a..bc97cc4 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -19,6 +19,7 @@
 
 extern void handle_property_set_fd(void);
 extern void property_init(void);
+extern void load_persist_props(void);
 extern void start_property_service(void);
 void get_property_workspace(int *fd, int *sz);
 extern const char* property_get(const char *name);
diff --git a/init/signal_handler.c b/init/signal_handler.c
index 833e59d..f89d058 100644
--- a/init/signal_handler.c
+++ b/init/signal_handler.c
@@ -23,7 +23,7 @@
 #include <sys/socket.h>
 #include <sys/wait.h>
 #include <cutils/sockets.h>
-#include <sys/reboot.h>
+#include <cutils/android_reboot.h>
 
 #include "init.h"
 #include "list.h"
@@ -96,9 +96,7 @@
                 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");
+                android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
                 return 0;
             }
         } else {
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/libcutils/Android.mk b/libcutils/Android.mk
index 3dc3d69..3b8cbbb 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -46,7 +46,8 @@
 	properties.c \
 	threads.c \
 	sched_policy.c \
-	iosched_policy.c
+	iosched_policy.c \
+	str_parms.c
 
 commonHostSources := \
         ashmem-host.c
@@ -109,7 +110,7 @@
 # ========================================================
 include $(CLEAR_VARS)
 LOCAL_MODULE := libcutils
-LOCAL_SRC_FILES := $(commonSources) ashmem-dev.c mq.c
+LOCAL_SRC_FILES := $(commonSources) ashmem-dev.c mq.c android_reboot.c uevent.c
 
 ifeq ($(TARGET_ARCH),arm)
 LOCAL_SRC_FILES += arch-arm/memset32.S
@@ -138,4 +139,12 @@
 LOCAL_CFLAGS += $(targetSmpFlag)
 include $(BUILD_SHARED_LIBRARY)
 
+include $(CLEAR_VARS)
+LOCAL_MODULE := tst_str_parms
+LOCAL_CFLAGS += -DTEST_STR_PARMS
+LOCAL_SRC_FILES := str_parms.c hashmap.c memory.c
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
+
 endif #!sim
diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c
new file mode 100644
index 0000000..33a7358
--- /dev/null
+++ b/libcutils/android_reboot.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright 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.
+ */
+
+#include <unistd.h>
+#include <sys/reboot.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <cutils/android_reboot.h>
+
+/* Check to see if /proc/mounts contains any writeable filesystems
+ * backed by a block device.
+ * Return true if none found, else return false.
+ */
+static int remount_ro_done(void)
+{
+    FILE *f;
+    char mount_dev[256];
+    char mount_dir[256];
+    char mount_type[256];
+    char mount_opts[256];
+    int mount_freq;
+    int mount_passno;
+    int match;
+    int found_rw_fs = 0;
+
+    f = fopen("/proc/mounts", "r");
+    if (! f) {
+        /* If we can't read /proc/mounts, just give up */
+        return 1;
+    }
+
+    do {
+        match = fscanf(f, "%255s %255s %255s %255s %d %d\n",
+                       mount_dev, mount_dir, mount_type,
+                       mount_opts, &mount_freq, &mount_passno);
+        mount_dev[255] = 0;
+        mount_dir[255] = 0;
+        mount_type[255] = 0;
+        mount_opts[255] = 0;
+        if ((match == 6) && !strncmp(mount_dev, "/dev/block", 10) && strstr(mount_opts, "rw")) {
+            found_rw_fs = 1;
+            break;
+        }
+    } while (match != EOF);
+
+    fclose(f);
+
+    return !found_rw_fs;
+}
+
+/* Remounting filesystems read-only is difficult when there are files
+ * opened for writing or pending deletes on the filesystem.  There is
+ * no way to force the remount with the mount(2) syscall.  The magic sysrq
+ * 'u' command does an emergency remount read-only on all writable filesystems
+ * that have a block device (i.e. not tmpfs filesystems) by calling
+ * emergency_remount(), which knows how to force the remount to read-only.
+ * Unfortunately, that is asynchronous, and just schedules the work and
+ * returns.  The best way to determine if it is done is to read /proc/mounts
+ * repeatedly until there are no more writable filesystems mounted on
+ * block devices.
+ */
+static void remount_ro(void)
+{
+    int fd, cnt = 0;
+
+    /* Trigger the remount of the filesystems as read-only,
+     * which also marks them clean.
+     */
+    fd = open("/proc/sysrq-trigger", O_WRONLY);
+    if (fd < 0) {
+        return;
+    }
+    write(fd, "u", 1);
+    close(fd);
+
+
+    /* Now poll /proc/mounts till it's done */
+    while (!remount_ro_done() && (cnt < 50)) {
+        usleep(100000);
+        cnt++;
+    }
+
+    return;
+}
+
+
+int android_reboot(int cmd, int flags, char *arg)
+{
+    int ret;
+
+    if (!(flags & ANDROID_RB_FLAG_NO_SYNC))
+        sync();
+
+    if (!(flags & ANDROID_RB_FLAG_NO_REMOUNT_RO))
+        remount_ro();
+
+    switch (cmd) {
+        case ANDROID_RB_RESTART:
+            ret = reboot(RB_AUTOBOOT);
+            break;
+
+        case ANDROID_RB_POWEROFF:
+            ret = reboot(RB_POWER_OFF);
+            break;
+
+        case ANDROID_RB_RESTART2:
+            ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
+                           LINUX_REBOOT_CMD_RESTART2, arg);
+            break;
+
+        default:
+            ret = -1;
+    }
+
+    return ret;
+}
+
diff --git a/libcutils/hashmap.c b/libcutils/hashmap.c
index e29bc24..65539ea 100644
--- a/libcutils/hashmap.c
+++ b/libcutils/hashmap.c
@@ -310,10 +310,11 @@
     for (i = 0; i < map->bucketCount; i++) {
         Entry* entry = map->buckets[i];
         while (entry != NULL) {
+            Entry *next = entry->next;
             if (!callback(entry->key, entry->value, context)) {
                 return;
             }
-            entry = entry->next;
+            entry = next;
         }
     }
 }
diff --git a/libcutils/properties.c b/libcutils/properties.c
index 547cc6d..98f356b 100644
--- a/libcutils/properties.c
+++ b/libcutils/properties.c
@@ -31,47 +31,9 @@
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
 #include <sys/_system_properties.h>
 
-static int send_prop_msg(prop_msg *msg)
-{
-    int s;
-    int r;
-    
-    s = socket_local_client(PROP_SERVICE_NAME, 
-                            ANDROID_SOCKET_NAMESPACE_RESERVED,
-                            SOCK_STREAM);
-    if(s < 0) return -1;
-    
-    while((r = send(s, msg, sizeof(prop_msg), 0)) < 0) {
-        if((errno == EINTR) || (errno == EAGAIN)) continue;
-        break;
-    }
-
-    if(r == sizeof(prop_msg)) {
-        r = 0;
-    } else {
-        r = -1;
-    }
-
-    close(s);
-    return r;
-}
-
 int property_set(const char *key, const char *value)
 {
-    prop_msg msg;
-    unsigned resp;
-
-    if(key == 0) return -1;
-    if(value == 0) value = "";
-    
-    if(strlen(key) >= PROP_NAME_MAX) return -1;
-    if(strlen(value) >= PROP_VALUE_MAX) return -1;
-    
-    msg.cmd = PROP_MSG_SETPROP;
-    strcpy((char*) msg.name, key);
-    strcpy((char*) msg.value, value);
-
-    return send_prop_msg(&msg);
+    return __system_property_set(key, value);
 }
 
 int property_get(const char *key, char *value, const char *default_value)
diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c
new file mode 100644
index 0000000..dfa1f73
--- /dev/null
+++ b/libcutils/str_parms.c
@@ -0,0 +1,329 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "str_params"
+//#define LOG_NDEBUG 0
+
+#define _GNU_SOURCE 1
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cutils/hashmap.h>
+#include <cutils/log.h>
+#include <cutils/memory.h>
+
+#include <cutils/str_parms.h>
+
+struct str_parms {
+    Hashmap *map;
+};
+
+
+static bool str_eq(void *key_a, void *key_b)
+{
+    return !strcmp((const char *)key_a, (const char *)key_b);
+}
+
+/* use djb hash unless we find it inadequate */
+static int str_hash_fn(void *str)
+{
+    uint32_t hash = 5381;
+    char *p;
+
+    for (p = str; p && *p; p++)
+        hash = ((hash << 5) + hash) + *p;
+    return (int)hash;
+}
+
+struct str_parms *str_parms_create(void)
+{
+    struct str_parms *str_parms;
+
+    str_parms = calloc(1, sizeof(struct str_parms));
+    if (!str_parms)
+        return NULL;
+
+    str_parms->map = hashmapCreate(5, str_hash_fn, str_eq);
+    if (!str_parms->map)
+        goto err;
+
+    return str_parms;
+
+err:
+    free(str_parms);
+    return NULL;
+}
+
+static bool remove_pair(void *key, void *value, void *context)
+{
+    struct str_parms *str_parms = context;
+
+    hashmapRemove(str_parms->map, key);
+    free(key);
+    free(value);
+    return true;
+}
+
+void str_parms_destroy(struct str_parms *str_parms)
+{
+    hashmapForEach(str_parms->map, remove_pair, str_parms);
+    hashmapFree(str_parms->map);
+    free(str_parms);
+}
+
+struct str_parms *str_parms_create_str(const char *_string)
+{
+    struct str_parms *str_parms;
+    char *str;
+    char *kvpair;
+    char *tmpstr;
+    int items = 0;
+
+    str_parms = str_parms_create();
+    if (!str_parms)
+        goto err_create_str_parms;
+
+    str = strdup(_string);
+    if (!str)
+        goto err_strdup;
+
+    LOGV("%s: source string == '%s'\n", __func__, _string);
+
+    kvpair = strtok_r(str, ";", &tmpstr);
+    while (kvpair && *kvpair) {
+        char *eq = strchr(kvpair, '='); /* would love strchrnul */
+        char *value;
+        char *key;
+        void *old_val;
+
+        if (eq == kvpair)
+            goto next_pair;
+
+        if (eq) {
+            key = strndup(kvpair, eq - kvpair);
+            if (*(++eq))
+                value = strdup(eq);
+            else
+                value = strdup("");
+        } else {
+            key = strdup(kvpair);
+            value = strdup("");
+        }
+
+        /* if we replaced a value, free it */
+        old_val = hashmapPut(str_parms->map, key, value);
+        if (old_val)
+            free(old_val);
+
+        items++;
+next_pair:
+        kvpair = strtok_r(NULL, ";", &tmpstr);
+    }
+
+    if (!items)
+        LOGV("%s: no items found in string\n", __func__);
+
+    free(str);
+
+    return str_parms;
+
+err_strdup:
+    str_parms_destroy(str_parms);
+err_create_str_parms:
+    return NULL;
+}
+
+void str_parms_del(struct str_parms *str_parms, const char *key)
+{
+    hashmapRemove(str_parms->map, (void *)key);
+}
+
+int str_parms_add_str(struct str_parms *str_parms, const char *key,
+                      const char *value)
+{
+    void *old_val;
+    char *tmp;
+
+    tmp = strdup(value);
+    old_val = hashmapPut(str_parms->map, (void *)key, tmp);
+
+    if (old_val) {
+        free(old_val);
+    } else if (errno == ENOMEM) {
+        free(tmp);
+        return -ENOMEM;
+    }
+    return 0;
+}
+
+int str_parms_add_int(struct str_parms *str_parms, const char *key, int value)
+{
+    char val_str[12];
+    int ret;
+
+    ret = snprintf(val_str, sizeof(val_str), "%d", value);
+    if (ret < 0)
+        return -EINVAL;
+
+    ret = str_parms_add_str(str_parms, key, val_str);
+    return ret;
+}
+
+int str_parms_add_float(struct str_parms *str_parms, const char *key,
+                        float value)
+{
+    char val_str[23];
+    int ret;
+
+    ret = snprintf(val_str, sizeof(val_str), "%.10f", value);
+    if (ret < 0)
+        return -EINVAL;
+
+    ret = str_parms_add_str(str_parms, key, val_str);
+    return ret;
+}
+
+int str_parms_get_str(struct str_parms *str_parms, const char *key, char *val,
+                      int len)
+{
+    char *value;
+
+    value = hashmapGet(str_parms->map, (void *)key);
+    if (value)
+        return strlcpy(val, value, len);
+
+    return -ENOENT;
+}
+
+int str_parms_get_int(struct str_parms *str_parms, const char *key, int *val)
+{
+    char *value;
+    char *end;
+
+    value = hashmapGet(str_parms->map, (void *)key);
+    if (!value)
+        return -ENOENT;
+
+    *val = (int)strtol(value, &end, 0);
+    if (*value != '\0' && *end == '\0')
+        return 0;
+
+    return -EINVAL;
+}
+
+int str_parms_get_float(struct str_parms *str_parms, const char *key,
+                        float *val)
+{
+    float out;
+    char *value;
+    char *end;
+
+    value = hashmapGet(str_parms->map, (void *)key);
+    if (!value)
+        return -ENOENT;
+
+    out = strtof(value, &end);
+    if (*value != '\0' && *end == '\0')
+        return 0;
+
+    return -EINVAL;
+}
+
+static bool combine_strings(void *key, void *value, void *context)
+{
+    char **old_str = context;
+    char *new_str;
+    int ret;
+
+    ret = asprintf(&new_str, "%s%s%s=%s",
+                   *old_str ? *old_str : "",
+                   *old_str ? ";" : "",
+                   (char *)key,
+                   (char *)value);
+    if (*old_str)
+        free(*old_str);
+
+    if (ret >= 0) {
+        *old_str = new_str;
+        return true;
+    }
+
+    *old_str = NULL;
+    return false;
+}
+
+char *str_parms_to_str(struct str_parms *str_parms)
+{
+    char *str = NULL;
+
+    if (hashmapSize(str_parms->map) > 0)
+        hashmapForEach(str_parms->map, combine_strings, &str);
+    else
+        str = strdup("");
+    return str;
+}
+
+static bool dump_entry(void *key, void *value, void *context)
+{
+    LOGI("key: '%s' value: '%s'\n", (char *)key, (char *)value);
+    return true;
+}
+
+void str_parms_dump(struct str_parms *str_parms)
+{
+    hashmapForEach(str_parms->map, dump_entry, str_parms);
+}
+
+#ifdef TEST_STR_PARMS
+static void test_str_parms_str(const char *str)
+{
+    struct str_parms *str_parms;
+    char *out_str;
+    int ret;
+
+    str_parms = str_parms_create_str(str);
+    str_parms_dump(str_parms);
+    out_str = str_parms_to_str(str_parms);
+    str_parms_destroy(str_parms);
+    LOGI("%s: '%s' stringified is '%s'", __func__, str, out_str);
+    free(out_str);
+}
+
+int main(void)
+{
+    struct str_parms *str_parms;
+
+    test_str_parms_str("");
+    test_str_parms_str(";");
+    test_str_parms_str("=");
+    test_str_parms_str("=;");
+    test_str_parms_str("=bar");
+    test_str_parms_str("=bar;");
+    test_str_parms_str("foo=");
+    test_str_parms_str("foo=;");
+    test_str_parms_str("foo=bar");
+    test_str_parms_str("foo=bar;");
+    test_str_parms_str("foo=bar;baz");
+    test_str_parms_str("foo=bar;baz=");
+    test_str_parms_str("foo=bar;baz=bat");
+    test_str_parms_str("foo=bar;baz=bat;");
+
+    return 0;
+}
+#endif
diff --git a/libcutils/uevent.c b/libcutils/uevent.c
new file mode 100644
index 0000000..3533c00
--- /dev/null
+++ b/libcutils/uevent.c
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#include <cutils/uevent.h>
+
+#include <errno.h>
+#include <strings.h>
+
+#include <linux/netlink.h>
+
+/**
+ * Like recv(), but checks that messages actually originate from the kernel.
+ */
+ssize_t uevent_checked_recv(int socket, void *buffer, size_t length) {
+    struct iovec iov = { buffer, length };
+    struct sockaddr_nl addr;
+    char control[CMSG_SPACE(sizeof(struct ucred))];
+    struct msghdr hdr = {
+        &addr,
+        sizeof(addr),
+        &iov,
+        1,
+        control,
+        sizeof(control),
+        0,
+    };
+
+    ssize_t n = recvmsg(socket, &hdr, 0);
+    if (n <= 0) {
+        return n;
+    }
+
+    if (addr.nl_groups == 0 || addr.nl_pid != 0) {
+        /* ignoring non-kernel or unicast netlink message */
+        goto out;
+    }
+
+    struct cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr);
+    if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
+        /* ignoring netlink message with no sender credentials */
+        goto out;
+    }
+
+    struct ucred *cred = (struct ucred *)CMSG_DATA(cmsg);
+    if (cred->uid != 0) {
+        /* ignoring netlink message from non-root user */
+        goto out;
+    }
+
+    return n;
+
+out:
+    /* clear residual potentially malicious data */
+    bzero(buffer, length);
+    errno = EIO;
+    return -1;
+}
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
index 1802688..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];
 
 /*
@@ -60,60 +61,66 @@
     return -1; /* failure */
 }
 
-static void fill_ip_info(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,
+static int fill_ip_info(const char *interface,
+                     char *ipaddr,
+                     char *gateway,
+                     uint32_t *prefixLength,
+                     char *dns1,
+                     char *dns2,
+                     char *server,
                      uint32_t  *lease)
 {
     char prop_name[PROPERTY_KEY_MAX];
     char prop_value[PROPERTY_VALUE_MAX];
-    struct in_addr addr;
-    in_addr_t iaddr;
 
     snprintf(prop_name, sizeof(prop_name), "%s.%s.ipaddress", DHCP_PROP_NAME_PREFIX, interface);
-    if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
-        *ipaddr = addr.s_addr;
-    } else {
-        *ipaddr = 0;
-    }
+    property_get(prop_name, ipaddr, NULL);
+
     snprintf(prop_name, sizeof(prop_name), "%s.%s.gateway", DHCP_PROP_NAME_PREFIX, interface);
-    if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
-        *gateway = addr.s_addr;
-    } else {
-        *gateway = 0;
+    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) && inet_aton(prop_value, &addr)) {
-        *mask = addr.s_addr;
-    } else {
-        *mask = 0;
+    if (property_get(prop_name, prop_value, NULL)) {
+        int p;
+        // this conversion is v4 only, but this dhcp client is v4 only anyway
+        in_addr_t mask = ntohl(inet_addr(prop_value));
+        // Check netmask is a valid IP address.  ntohl gives NONE response (all 1's) for
+        // non 255.255.255.255 inputs.  if we get that value check if it is legit..
+        if (mask == INADDR_NONE && strcmp(prop_value, "255.255.255.255") != 0) {
+            snprintf(errmsg, sizeof(errmsg), "DHCP gave invalid net mask %s", prop_value);
+            return -1;
+        }
+        for (p = 0; p < 32; p++) {
+            if (mask == 0) break;
+            // check for non-contiguous netmask, e.g., 255.254.255.0
+            if ((mask & 0x80000000) == 0) {
+                snprintf(errmsg, sizeof(errmsg), "DHCP gave invalid net mask %s", prop_value);
+                return -1;
+            }
+            mask = mask << 1;
+        }
+        *prefixLength = p;
     }
     snprintf(prop_name, sizeof(prop_name), "%s.%s.dns1", DHCP_PROP_NAME_PREFIX, interface);
-    if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
-        *dns1 = addr.s_addr;
-    } else {
-        *dns1 = 0;
-    }
+    property_get(prop_name, dns1, NULL);
+
     snprintf(prop_name, sizeof(prop_name), "%s.%s.dns2", DHCP_PROP_NAME_PREFIX, interface);
-    if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
-        *dns2 = addr.s_addr;
-    } else {
-        *dns2 = 0;
-    }
-    snprintf(prop_name, sizeof(prop_name), "%s.%s.server", DHCP_PROP_NAME_PREFIX, interface);
-    if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
-        *server = addr.s_addr;
-    } else {
-        *server = 0;
-    }
+    property_get(prop_name, dns2, 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);
     }
+    return 0;
 }
 
 static const char *ipaddr_to_string(in_addr_t addr)
@@ -129,15 +136,16 @@
  * configuring the interface.
  */
 int dhcp_do_request(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,
+                    char *ipaddr,
+                    char *gateway,
+                    uint32_t *prefixLength,
+                    char *dns1,
+                    char *dns2,
+                    char *server,
                     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;
     }
@@ -175,8 +188,13 @@
     }
     if (strcmp(prop_value, "ok") == 0) {
         char dns_prop_name[PROPERTY_KEY_MAX];
-        fill_ip_info(interface, ipaddr, gateway, mask, dns1, dns2, server, lease);
-        /* copy the dhcp.XXX.dns properties to net.XXX.dns */
+        if (fill_ip_info(interface, ipaddr, gateway, prefixLength, dns1, dns2, server, lease)
+                == -1) {
+            return -1;
+        }
+
+        /* copy dns data to system properties - TODO - remove this after we have async
+         * notification of renewal's */
         snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns1", interface);
         property_set(dns_prop_name, *dns1 ? ipaddr_to_string(*dns1) : "");
         snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns2", interface);
@@ -194,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");
@@ -214,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;
@@ -228,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/dhcpclient.c b/libnetutils/dhcpclient.c
index ff00432..5039e26 100644
--- a/libnetutils/dhcpclient.c
+++ b/libnetutils/dhcpclient.c
@@ -93,6 +93,8 @@
     return inet_ntoa(in_addr);
 }
 
+extern int ipv4NetmaskToPrefixLength(in_addr_t mask);
+
 typedef struct dhcp_info dhcp_info;
 
 struct dhcp_info {
@@ -100,7 +102,7 @@
 
     uint32_t ipaddr;
     uint32_t gateway;
-    uint32_t netmask;
+    uint32_t prefixLength;
 
     uint32_t dns1;
     uint32_t dns2;
@@ -111,13 +113,13 @@
 
 dhcp_info last_good_info;
 
-void get_dhcp_info(uint32_t *ipaddr, uint32_t *gateway, uint32_t *mask,
+void get_dhcp_info(uint32_t *ipaddr, uint32_t *gateway, uint32_t *prefixLength,
                    uint32_t *dns1, uint32_t *dns2, uint32_t *server,
                    uint32_t *lease)
 {
     *ipaddr = last_good_info.ipaddr;
     *gateway = last_good_info.gateway;
-    *mask = last_good_info.netmask;
+    *prefixLength = last_good_info.prefixLength;
     *dns1 = last_good_info.dns1;
     *dns2 = last_good_info.dns2;
     *server = last_good_info.serveraddr;
@@ -127,7 +129,7 @@
 static int dhcp_configure(const char *ifname, dhcp_info *info)
 {
     last_good_info = *info;
-    return ifc_configure(ifname, info->ipaddr, info->netmask, info->gateway,
+    return ifc_configure(ifname, info->ipaddr, info->prefixLength, info->gateway,
                          info->dns1, info->dns2);
 }
 
@@ -153,8 +155,7 @@
             dhcp_type_to_name(info->type), info->type);
     strcpy(addr, ipaddr(info->ipaddr));
     strcpy(gway, ipaddr(info->gateway));
-    strcpy(mask, ipaddr(info->netmask));
-    LOGD("ip %s gw %s mask %s", addr, gway, mask);
+    LOGD("ip %s gw %s prefixLength %d", addr, gway, info->prefixLength);
     if (info->dns1) LOGD("dns1: %s", ipaddr(info->dns1));
     if (info->dns2) LOGD("dns2: %s", ipaddr(info->dns2));
     LOGD("server %s, lease %d seconds",
@@ -196,7 +197,7 @@
         }
         switch(opt) {
         case OPT_SUBNET_MASK:
-            if (optlen >= 4) memcpy(&info->netmask, x, 4);
+            if (optlen >= 4) info->prefixLength = ipv4NetmaskToPrefixLength((int)x);
             break;
         case OPT_GATEWAY:
             if (optlen >= 4) memcpy(&info->gateway, x, 4);
diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c
index 95a144c..2e3df00 100644
--- a/libnetutils/ifc_utils.c
+++ b/libnetutils/ifc_utils.c
@@ -25,6 +25,7 @@
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#include <net/if.h>
 
 #include <linux/if.h>
 #include <linux/if_ether.h>
@@ -50,6 +51,33 @@
 static int ifc_ctl_sock6 = -1;
 void printerr(char *fmt, ...);
 
+in_addr_t prefixLengthToIpv4Netmask(int prefix_length)
+{
+    in_addr_t mask = 0;
+
+    // C99 (6.5.7): shifts of 32 bits have undefined results
+    if (prefix_length <= 0 || prefix_length > 32) {
+        return 0;
+    }
+
+    mask = ~mask << (32 - prefix_length);
+    mask = htonl(mask);
+
+    return mask;
+}
+
+int ipv4NetmaskToPrefixLength(in_addr_t mask)
+{
+    mask = ntohl(mask);
+    int prefixLength = 0;
+    uint32_t m = (uint32_t)mask;
+    while (m & 0x80000000) {
+        prefixLength++;
+        m = m << 1;
+    }
+    return prefixLength;
+}
+
 static const char *ipaddr_to_string(in_addr_t addr)
 {
     struct in_addr in_addr;
@@ -126,7 +154,7 @@
     if(r < 0) return -1;
 
     *if_indexp = ifr.ifr_ifindex;
-    return 0;    
+    return 0;
 }
 
 static int ifc_set_flags(const char *name, unsigned set, unsigned clr)
@@ -163,7 +191,7 @@
 
     ifc_init_ifr(name, &ifr);
     init_sockaddr_in(&ifr.ifr_addr, addr);
-    
+
     return ioctl(ifc_ctl_sock, SIOCSIFADDR, &ifr);
 }
 
@@ -184,11 +212,41 @@
 
     ifc_init_ifr(name, &ifr);
     init_sockaddr_in(&ifr.ifr_addr, mask);
-    
+
     return ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &ifr);
 }
 
-int ifc_get_info(const char *name, in_addr_t *addr, in_addr_t *mask, unsigned *flags)
+int ifc_set_prefixLength(const char *name, int prefixLength)
+{
+    struct ifreq ifr;
+    // TODO - support ipv6
+    if (prefixLength > 32 || prefixLength < 0) return -1;
+
+    in_addr_t mask = prefixLengthToIpv4Netmask(prefixLength);
+    ifc_init_ifr(name, &ifr);
+    init_sockaddr_in(&ifr.ifr_addr, mask);
+
+    return ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &ifr);
+}
+
+int ifc_get_addr(const char *name, in_addr_t *addr)
+{
+    struct ifreq ifr;
+    int ret = 0;
+
+    ifc_init_ifr(name, &ifr);
+    if (addr != NULL) {
+        ret = ioctl(ifc_ctl_sock, SIOCGIFADDR, &ifr);
+        if (ret < 0) {
+            *addr = 0;
+        } else {
+            *addr = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
+        }
+    }
+    return ret;
+}
+
+int ifc_get_info(const char *name, in_addr_t *addr, int *prefixLength, unsigned *flags)
 {
     struct ifreq ifr;
     ifc_init_ifr(name, &ifr);
@@ -200,12 +258,13 @@
             *addr = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
         }
     }
-    
-    if (mask != NULL) {
+
+    if (prefixLength != NULL) {
         if(ioctl(ifc_ctl_sock, SIOCGIFNETMASK, &ifr) < 0) {
-            *mask = 0;
+            *prefixLength = 0;
         } else {
-            *mask = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
+            *prefixLength = ipv4NetmaskToPrefixLength((int)
+                    ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr);
         }
     }
 
@@ -220,22 +279,7 @@
     return 0;
 }
 
-in_addr_t get_ipv4_netmask(int prefix_length)
-{
-    in_addr_t mask = 0;
-
-    // C99 (6.5.7): shifts of 32 bits have undefined results
-    if (prefix_length == 0) {
-        return 0;
-    }
-
-    mask = ~mask << (32 - prefix_length);
-    mask = htonl(mask);
-
-    return mask;
-}
-
-int ifc_add_ipv4_route(const char *ifname, struct in_addr dst, int prefix_length,
+int ifc_act_on_ipv4_route(int action, const char *ifname, struct in_addr dst, int prefix_length,
       struct in_addr gw)
 {
     struct rtentry rt;
@@ -247,7 +291,7 @@
     rt.rt_dst.sa_family = AF_INET;
     rt.rt_dev = (void*) ifname;
 
-    netmask = get_ipv4_netmask(prefix_length);
+    netmask = prefixLengthToIpv4Netmask(prefix_length);
     init_sockaddr_in(&rt.rt_genmask, netmask);
     init_sockaddr_in(&rt.rt_dst, dst.s_addr);
     rt.rt_flags = RTF_UP;
@@ -267,7 +311,7 @@
         return -errno;
     }
 
-    result = ioctl(ifc_ctl_sock, SIOCADDRT, &rt);
+    result = ioctl(ifc_ctl_sock, action, &rt);
     if (result < 0) {
         if (errno == EEXIST) {
             result = 0;
@@ -286,17 +330,7 @@
     in_dst.s_addr = 0;
     in_gw.s_addr = gw;
 
-    return ifc_add_ipv4_route(name, in_dst, 0, in_gw);
-}
-
-int ifc_add_host_route(const char *name, in_addr_t dst)
-{
-    struct in_addr in_dst, in_gw;
-
-    in_dst.s_addr = dst;
-    in_gw.s_addr = 0;
-
-    return ifc_add_ipv4_route(name, in_dst, 32, in_gw);
+    return ifc_act_on_route(SIOCADDRT, name, in_dst, 0, in_gw);
 }
 
 int ifc_enable(const char *ifname)
@@ -311,11 +345,20 @@
 
 int ifc_disable(const char *ifname)
 {
+    unsigned addr, count;
     int result;
 
     ifc_init();
     result = ifc_down(ifname);
+
     ifc_set_addr(ifname, 0);
+    for (count=0, addr=1;((addr != 0) && (count < 255)); count++) {
+       if (ifc_get_addr(ifname, &addr) < 0)
+            break;
+       if (addr)
+          ifc_set_addr(ifname, 0);
+    }
+
     ifc_close();
     return result;
 }
@@ -323,17 +366,34 @@
 int ifc_reset_connections(const char *ifname)
 {
 #ifdef HAVE_ANDROID_OS
-    int result;
+    int result, success;
     in_addr_t myaddr;
     struct ifreq ifr;
+    struct in6_ifreq ifr6;
 
+    /* IPv4. Clear connections on the IP address. */
     ifc_init();
     ifc_get_info(ifname, &myaddr, NULL, NULL);
     ifc_init_ifr(ifname, &ifr);
     init_sockaddr_in(&ifr.ifr_addr, myaddr);
     result = ioctl(ifc_ctl_sock, SIOCKILLADDR,  &ifr);
     ifc_close();
-    
+
+    /*
+     * IPv6. On Linux, when an interface goes down it loses all its IPv6
+     * addresses, so we don't know which connections belonged to that interface
+     * So we clear all unused IPv6 connections on the device by specifying an
+     * empty IPv6 address.
+     */
+    ifc_init6();
+    // This implicitly specifies an address of ::, i.e., kill all IPv6 sockets.
+    memset(&ifr6, 0, sizeof(ifr6));
+    success = ioctl(ifc_ctl_sock6, SIOCKILLADDR,  &ifr6);
+    if (result == 0) {
+        result = success;
+    }
+    ifc_close6();
+
     return result;
 #else
     return 0;
@@ -389,67 +449,6 @@
 }
 
 /*
- * Return the address of the default gateway
- *
- * TODO: factor out common code from this and remove_host_routes()
- * so that we only scan /proc/net/route in one place.
- */
-int ifc_get_default_route(const char *ifname)
-{
-    char name[64];
-    in_addr_t dest, gway, mask;
-    int flags, refcnt, use, metric, mtu, win, irtt;
-    int result;
-    FILE *fp;
-
-    fp = fopen("/proc/net/route", "r");
-    if (fp == NULL)
-        return 0;
-    /* Skip the header line */
-    if (fscanf(fp, "%*[^\n]\n") < 0) {
-        fclose(fp);
-        return 0;
-    }
-    ifc_init();
-    result = 0;
-    for (;;) {
-        int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n",
-                           name, &dest, &gway, &flags, &refcnt, &use, &metric, &mask,
-                           &mtu, &win, &irtt);
-        if (nread != 11) {
-            break;
-        }
-        if ((flags & (RTF_UP|RTF_GATEWAY)) == (RTF_UP|RTF_GATEWAY)
-                && dest == 0
-                && strcmp(ifname, name) == 0) {
-            result = gway;
-            break;
-        }
-    }
-    fclose(fp);
-    ifc_close();
-    return result;
-}
-
-/*
- * Sets the specified gateway as the default route for the named interface.
- */
-int ifc_set_default_route(const char *ifname, in_addr_t gateway)
-{
-    struct in_addr addr;
-    int result;
-
-    ifc_init();
-    addr.s_addr = gateway;
-    if ((result = ifc_create_default_route(ifname, gateway)) < 0) {
-        LOGD("failed to add %s as default route for %s: %s",
-             inet_ntoa(addr), ifname, strerror(errno));
-    }
-    ifc_close();
-    return result;
-}
-
-/*
  * Removes the default route for the named interface.
  */
 int ifc_remove_default_route(const char *ifname)
@@ -472,7 +471,7 @@
 int
 ifc_configure(const char *ifname,
         in_addr_t address,
-        in_addr_t netmask,
+        uint32_t prefixLength,
         in_addr_t gateway,
         in_addr_t dns1,
         in_addr_t dns2) {
@@ -491,8 +490,8 @@
         ifc_close();
         return -1;
     }
-    if (ifc_set_mask(ifname, netmask)) {
-        printerr("failed to set netmask %s: %s\n", ipaddr_to_string(netmask), strerror(errno));
+    if (ifc_set_prefixLength(ifname, prefixLength)) {
+        printerr("failed to set prefixLength %d: %s\n", prefixLength, strerror(errno));
         ifc_close();
         return -1;
     }
@@ -512,7 +511,7 @@
     return 0;
 }
 
-int ifc_add_ipv6_route(const char *ifname, struct in6_addr dst, int prefix_length,
+int ifc_act_on_ipv6_route(int action, const char *ifname, struct in6_addr dst, int prefix_length,
       struct in6_addr gw)
 {
     struct in6_rtmsg rtmsg;
@@ -547,7 +546,7 @@
         return -errno;
     }
 
-    result = ioctl(ifc_ctl_sock6, SIOCADDRT, &rtmsg);
+    result = ioctl(ifc_ctl_sock6, action, &rtmsg);
     if (result < 0) {
         if (errno == EEXIST) {
             result = 0;
@@ -559,8 +558,8 @@
     return result;
 }
 
-int ifc_add_route(const char *ifname, const char *dst, int prefix_length,
-      const char *gw)
+int ifc_act_on_route(int action, const char *ifname, const char *dst, int prefix_length,
+        const char *gw)
 {
     int ret = 0;
     struct sockaddr_in ipv4_dst, ipv4_gw;
@@ -578,7 +577,7 @@
         return -EINVAL;
     }
 
-    if (gw == NULL) {
+    if (gw == NULL || (strlen(gw) == 0)) {
         if (addr_ai->ai_family == AF_INET6) {
             gw = "::";
         } else if (addr_ai->ai_family == AF_INET) {
@@ -586,6 +585,13 @@
         }
     }
 
+    if (((addr_ai->ai_family == AF_INET6) && (prefix_length < 0 || prefix_length > 128)) ||
+            ((addr_ai->ai_family == AF_INET) && (prefix_length < 0 || prefix_length > 32))) {
+        printerr("ifc_add_route: invalid prefix length");
+        freeaddrinfo(addr_ai);
+        return -EINVAL;
+    }
+
     ret = getaddrinfo(gw, NULL, &hints, &gw_ai);
     if (ret != 0) {
         printerr("getaddrinfo failed: invalid gateway %s\n", gw);
@@ -603,13 +609,13 @@
     if (addr_ai->ai_family == AF_INET6) {
         memcpy(&ipv6_dst, addr_ai->ai_addr, sizeof(struct sockaddr_in6));
         memcpy(&ipv6_gw, gw_ai->ai_addr, sizeof(struct sockaddr_in6));
-        ret = ifc_add_ipv6_route(ifname, ipv6_dst.sin6_addr, prefix_length,
-              ipv6_gw.sin6_addr);
+        ret = ifc_act_on_ipv6_route(action, ifname, ipv6_dst.sin6_addr,
+                prefix_length, ipv6_gw.sin6_addr);
     } else if (addr_ai->ai_family == AF_INET) {
         memcpy(&ipv4_dst, addr_ai->ai_addr, sizeof(struct sockaddr_in));
         memcpy(&ipv4_gw, gw_ai->ai_addr, sizeof(struct sockaddr_in));
-        ret = ifc_add_ipv4_route(ifname, ipv4_dst.sin_addr, prefix_length,
-              ipv4_gw.sin_addr);
+        ret = ifc_act_on_ipv4_route(action, ifname, ipv4_dst.sin_addr,
+                prefix_length, ipv4_gw.sin_addr);
     } else {
         printerr("ifc_add_route: getaddrinfo returned un supported address family %d\n",
                   addr_ai->ai_family);
@@ -620,3 +626,13 @@
     freeaddrinfo(gw_ai);
     return ret;
 }
+
+int ifc_add_route(const char *ifname, const char *dst, int prefix_length, const char *gw)
+{
+    return ifc_act_on_route(SIOCADDRT, ifname, dst, prefix_length, gw);
+}
+
+int ifc_remove_route(const char *ifname, const char*dst, int prefix_length, const char *gw)
+{
+    return ifc_act_on_route(SIOCDELRT, ifname, dst, prefix_length, gw);
+}
diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
index 931d648..8fba147 100644
--- a/libpixelflinger/scanline.cpp
+++ b/libpixelflinger/scanline.cpp
@@ -1,6 +1,6 @@
 /* libs/pixelflinger/scanline.cpp
 **
-** Copyright 2006, The Android Open Source Project
+** Copyright 2006-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. 
@@ -57,6 +57,11 @@
 
 #define DEBUG__CODEGEN_ONLY     0
 
+/* Set to 1 to dump to the log the states that need a new
+ * code-generated scanline callback, i.e. those that don't
+ * have a corresponding shortcut function.
+ */
+#define DEBUG_NEEDS  0
 
 #define ASSEMBLY_SCRATCH_SIZE   2048
 
@@ -79,8 +84,21 @@
 static void scanline_perspective(context_t* c);
 static void scanline_perspective_single(context_t* c);
 static void scanline_t32cb16blend(context_t* c);
+static void scanline_t32cb16blend_dither(context_t* c);
+static void scanline_t32cb16blend_srca(context_t* c);
+static void scanline_t32cb16blend_clamp(context_t* c);
+static void scanline_t32cb16blend_clamp_dither(context_t* c);
+static void scanline_t32cb16blend_clamp_mod(context_t* c);
+static void scanline_x32cb16blend_clamp_mod(context_t* c);
+static void scanline_t32cb16blend_clamp_mod_dither(context_t* c);
+static void scanline_x32cb16blend_clamp_mod_dither(context_t* c);
 static void scanline_t32cb16(context_t* c);
+static void scanline_t32cb16_dither(context_t* c);
+static void scanline_t32cb16_clamp(context_t* c);
+static void scanline_t32cb16_clamp_dither(context_t* c);
 static void scanline_col32cb16blend(context_t* c);
+static void scanline_t16cb16_clamp(context_t* c);
+static void scanline_t16cb16blend_clamp_mod(context_t* c);
 static void scanline_memcpy(context_t* c);
 static void scanline_memset8(context_t* c);
 static void scanline_memset16(context_t* c);
@@ -99,6 +117,13 @@
 
 // ----------------------------------------------------------------------------
 
+static inline uint16_t  convertAbgr8888ToRgb565(uint32_t  pix)
+{
+    return uint16_t( ((pix << 8) & 0xf800) |
+                      ((pix >> 5) & 0x07e0) |
+                      ((pix >> 19) & 0x001f) );
+}
+
 struct shortcut_t {
     needs_filter_t  filter;
     const char*     desc;
@@ -107,13 +132,95 @@
 };
 
 // Keep in sync with needs
+
+/* To understand the values here, have a look at:
+ *     system/core/include/private/pixelflinger/ggl_context.h
+ *
+ * Especially the lines defining and using GGL_RESERVE_NEEDS
+ *
+ * Quick reminders:
+ *   - the last nibble of the first value is the destination buffer format.
+ *   - the last nibble of the third value is the source texture format
+ *   - formats: 4=rgb565 1=abgr8888 2=xbgr8888
+ *
+ * In the descriptions below:
+ *
+ *   SRC      means we copy the source pixels to the destination
+ *
+ *   SRC_OVER means we blend the source pixels to the destination
+ *            with dstFactor = 1-srcA, srcFactor=1  (premultiplied source).
+ *            This mode is otherwise called 'blend'.
+ *
+ *   SRCA_OVER means we blend the source pixels to the destination
+ *             with dstFactor=srcA*(1-srcA) srcFactor=srcA (non-premul source).
+ *             This mode is otherwise called 'blend_srca'
+ *
+ *   clamp    means we fetch source pixels from a texture with u/v clamping
+ *
+ *   mod      means the source pixels are modulated (multiplied) by the
+ *            a/r/g/b of the current context's color. Typically used for
+ *            fade-in / fade-out.
+ *
+ *   dither   means we dither 32 bit values to 16 bits
+ */
 static shortcut_t shortcuts[] = {
     { { { 0x03515104, 0x00000077, { 0x00000A01, 0x00000000 } },
         { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
-        "565 fb, 8888 tx, blend", scanline_t32cb16blend, init_y_noop },
+        "565 fb, 8888 tx, blend SRC_OVER", scanline_t32cb16blend, init_y_noop },
     { { { 0x03010104, 0x00000077, { 0x00000A01, 0x00000000 } },
         { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
-        "565 fb, 8888 tx", scanline_t32cb16, init_y_noop  },  
+        "565 fb, 8888 tx, SRC", scanline_t32cb16, init_y_noop  },
+    /* same as first entry, but with dithering */
+    { { { 0x03515104, 0x00000177, { 0x00000A01, 0x00000000 } },
+        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
+        "565 fb, 8888 tx, blend SRC_OVER dither", scanline_t32cb16blend_dither, init_y_noop },
+    /* same as second entry, but with dithering */
+    { { { 0x03010104, 0x00000177, { 0x00000A01, 0x00000000 } },
+        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
+        "565 fb, 8888 tx, SRC dither", scanline_t32cb16_dither, init_y_noop  },
+    /* this is used during the boot animation - CHEAT: ignore dithering */
+    { { { 0x03545404, 0x00000077, { 0x00000A01, 0x00000000 } },
+        { 0xFFFFFFFF, 0xFFFFFEFF, { 0xFFFFFFFF, 0x0000003F } } },
+        "565 fb, 8888 tx, blend dst:ONE_MINUS_SRCA src:SRCA", scanline_t32cb16blend_srca, init_y_noop },
+    /* special case for arbitrary texture coordinates (think scaling) */
+    { { { 0x03515104, 0x00000077, { 0x00000001, 0x00000000 } },
+        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
+        "565 fb, 8888 tx, SRC_OVER clamp", scanline_t32cb16blend_clamp, init_y },
+    { { { 0x03515104, 0x00000177, { 0x00000001, 0x00000000 } },
+        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
+        "565 fb, 8888 tx, SRC_OVER clamp dither", scanline_t32cb16blend_clamp_dither, init_y },
+    /* another case used during emulation */
+    { { { 0x03515104, 0x00000077, { 0x00001001, 0x00000000 } },
+        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
+        "565 fb, 8888 tx, SRC_OVER clamp modulate", scanline_t32cb16blend_clamp_mod, init_y },
+    /* and this */
+    { { { 0x03515104, 0x00000077, { 0x00001002, 0x00000000 } },
+        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
+        "565 fb, x888 tx, SRC_OVER clamp modulate", scanline_x32cb16blend_clamp_mod, init_y },
+    { { { 0x03515104, 0x00000177, { 0x00001001, 0x00000000 } },
+        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
+        "565 fb, 8888 tx, SRC_OVER clamp modulate dither", scanline_t32cb16blend_clamp_mod_dither, init_y },
+    { { { 0x03515104, 0x00000177, { 0x00001002, 0x00000000 } },
+        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
+        "565 fb, x888 tx, SRC_OVER clamp modulate dither", scanline_x32cb16blend_clamp_mod_dither, init_y },
+    { { { 0x03010104, 0x00000077, { 0x00000001, 0x00000000 } },
+        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
+        "565 fb, 8888 tx, SRC clamp", scanline_t32cb16_clamp, init_y  },
+    { { { 0x03010104, 0x00000077, { 0x00000002, 0x00000000 } },
+        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
+        "565 fb, x888 tx, SRC clamp", scanline_t32cb16_clamp, init_y  },
+    { { { 0x03010104, 0x00000177, { 0x00000001, 0x00000000 } },
+        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
+        "565 fb, 8888 tx, SRC clamp dither", scanline_t32cb16_clamp_dither, init_y  },
+    { { { 0x03010104, 0x00000177, { 0x00000002, 0x00000000 } },
+        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
+        "565 fb, x888 tx, SRC clamp dither", scanline_t32cb16_clamp_dither, init_y  },
+    { { { 0x03010104, 0x00000077, { 0x00000004, 0x00000000 } },
+        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
+        "565 fb, 565 tx, SRC clamp", scanline_t16cb16_clamp, init_y  },
+    { { { 0x03515104, 0x00000077, { 0x00001004, 0x00000000 } },
+        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
+        "565 fb, 565 tx, SRC_OVER clamp", scanline_t16cb16blend_clamp_mod, init_y  },
     { { { 0x03515104, 0x00000077, { 0x00000000, 0x00000000 } },
         { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0xFFFFFFFF } } },
         "565 fb, 8888 fixed color", scanline_col32cb16blend, init_y_packed  },  
@@ -243,6 +350,12 @@
         }
     }
 
+#ifdef DEBUG_NEEDS
+    LOGI("Needs: n=0x%08x p=0x%08x t0=0x%08x t1=0x%08x",
+         c->state.needs.n, c->state.needs.p,
+         c->state.needs.t[0], c->state.needs.t[1]);
+#endif
+
 #endif // DEBUG__CODEGEN_ONLY
 
     c->init_y = init_y;
@@ -797,6 +910,678 @@
 #pragma mark Scanline
 #endif
 
+/* Used to parse a 32-bit source texture linearly. Usage is:
+ *
+ * horz_iterator32  hi(context);
+ * while (...) {
+ *    uint32_t  src_pixel = hi.get_pixel32();
+ *    ...
+ * }
+ *
+ * Use only for one-to-one texture mapping.
+ */
+struct horz_iterator32 {
+    horz_iterator32(context_t* c) {
+        const int x = c->iterators.xl;
+        const int y = c->iterators.y;
+        texture_t& tx = c->state.texture[0];
+        const int32_t u = (tx.shade.is0>>16) + x;
+        const int32_t v = (tx.shade.it0>>16) + y;
+        m_src = reinterpret_cast<uint32_t*>(tx.surface.data)+(u+(tx.surface.stride*v));
+    }
+    uint32_t  get_pixel32() {
+        return *m_src++;
+    }
+protected:
+    uint32_t* m_src;
+};
+
+/* A variant for 16-bit source textures. */
+struct horz_iterator16 {
+    horz_iterator16(context_t* c) {
+        const int x = c->iterators.xl;
+        const int y = c->iterators.y;
+        texture_t& tx = c->state.texture[0];
+        const int32_t u = (tx.shade.is0>>16) + x;
+        const int32_t v = (tx.shade.it0>>16) + y;
+        m_src = reinterpret_cast<uint16_t*>(tx.surface.data)+(u+(tx.surface.stride*v));
+    }
+    uint16_t  get_pixel16() {
+        return *m_src++;
+    }
+protected:
+    uint16_t* m_src;
+};
+
+/* A clamp iterator is used to iterate inside a texture with GGL_CLAMP.
+ * After initialization, call get_src16() or get_src32() to get the current
+ * texture pixel value.
+ */
+struct clamp_iterator {
+    clamp_iterator(context_t* c) {
+        const int xs = c->iterators.xl;
+        texture_t& tx = c->state.texture[0];
+        texture_iterators_t& ti = tx.iterators;
+        m_s = (xs * ti.dsdx) + ti.ydsdy;
+        m_t = (xs * ti.dtdx) + ti.ydtdy;
+        m_ds = ti.dsdx;
+        m_dt = ti.dtdx;
+        m_width_m1 = tx.surface.width - 1;
+        m_height_m1 = tx.surface.height - 1;
+        m_data = tx.surface.data;
+        m_stride = tx.surface.stride;
+    }
+    uint16_t get_pixel16() {
+        int  u, v;
+        get_uv(u, v);
+        uint16_t* src = reinterpret_cast<uint16_t*>(m_data) + (u + (m_stride*v));
+        return src[0];
+    }
+    uint32_t get_pixel32() {
+        int  u, v;
+        get_uv(u, v);
+        uint32_t* src = reinterpret_cast<uint32_t*>(m_data) + (u + (m_stride*v));
+        return src[0];
+    }
+private:
+    void   get_uv(int& u, int& v) {
+        int  uu = m_s >> 16;
+        int  vv = m_t >> 16;
+        if (uu < 0)
+            uu = 0;
+        if (uu > m_width_m1)
+            uu = m_width_m1;
+        if (vv < 0)
+            vv = 0;
+        if (vv > m_height_m1)
+            vv = m_height_m1;
+        u = uu;
+        v = vv;
+        m_s += m_ds;
+        m_t += m_dt;
+    }
+
+    GGLfixed  m_s, m_t;
+    GGLfixed  m_ds, m_dt;
+    int       m_width_m1, m_height_m1;
+    uint8_t*  m_data;
+    int       m_stride;
+};
+
+/*
+ * The 'horizontal clamp iterator' variant corresponds to the case where
+ * the 'v' coordinate doesn't change. This is useful to avoid one mult and
+ * extra adds / checks per pixels, if the blending/processing operation after
+ * this is very fast.
+ */
+static int is_context_horizontal(const context_t* c) {
+    return (c->state.texture[0].iterators.dtdx == 0);
+}
+
+struct horz_clamp_iterator {
+    uint16_t  get_pixel16() {
+        int  u = m_s >> 16;
+        m_s += m_ds;
+        if (u < 0)
+            u = 0;
+        if (u > m_width_m1)
+            u = m_width_m1;
+        const uint16_t* src = reinterpret_cast<const uint16_t*>(m_data);
+        return src[u];
+    }
+    uint32_t  get_pixel32() {
+        int  u = m_s >> 16;
+        m_s += m_ds;
+        if (u < 0)
+            u = 0;
+        if (u > m_width_m1)
+            u = m_width_m1;
+        const uint32_t* src = reinterpret_cast<const uint32_t*>(m_data);
+        return src[u];
+    }
+protected:
+    void init(const context_t* c, int shift);
+    GGLfixed       m_s;
+    GGLfixed       m_ds;
+    int            m_width_m1;
+    const uint8_t* m_data;
+};
+
+void horz_clamp_iterator::init(const context_t* c, int shift)
+{
+    const int xs = c->iterators.xl;
+    const texture_t& tx = c->state.texture[0];
+    const texture_iterators_t& ti = tx.iterators;
+    m_s = (xs * ti.dsdx) + ti.ydsdy;
+    m_ds = ti.dsdx;
+    m_width_m1 = tx.surface.width-1;
+    m_data = tx.surface.data;
+
+    GGLfixed t = (xs * ti.dtdx) + ti.ydtdy;
+    int      v = t >> 16;
+    if (v < 0)
+        v = 0;
+    else if (v >= (int)tx.surface.height)
+        v = (int)tx.surface.height-1;
+
+    m_data += (tx.surface.stride*v) << shift;
+}
+
+struct horz_clamp_iterator16 : horz_clamp_iterator {
+    horz_clamp_iterator16(const context_t* c) {
+        init(c,1);
+    };
+};
+
+struct horz_clamp_iterator32 : horz_clamp_iterator {
+    horz_clamp_iterator32(context_t* c) {
+        init(c,2);
+    };
+};
+
+/* This is used to perform dithering operations.
+ */
+struct ditherer {
+    ditherer(const context_t* c) {
+        const int x = c->iterators.xl;
+        const int y = c->iterators.y;
+        m_line = &c->ditherMatrix[ ((y & GGL_DITHER_MASK)<<GGL_DITHER_ORDER_SHIFT) ];
+        m_index = x & GGL_DITHER_MASK;
+    }
+    void step(void) {
+        m_index++;
+    }
+    int  get_value(void) {
+        int ret = m_line[m_index & GGL_DITHER_MASK];
+        m_index++;
+        return ret;
+    }
+    uint16_t abgr8888ToRgb565(uint32_t s) {
+        uint32_t r = s & 0xff;
+        uint32_t g = (s >> 8) & 0xff;
+        uint32_t b = (s >> 16) & 0xff;
+        return rgb888ToRgb565(r,g,b);
+    }
+    /* The following assumes that r/g/b are in the 0..255 range each */
+    uint16_t rgb888ToRgb565(uint32_t& r, uint32_t& g, uint32_t &b) {
+        int threshold = get_value();
+        /* dither in on GGL_DITHER_BITS, and each of r, g, b is on 8 bits */
+        r += (threshold >> (GGL_DITHER_BITS-8 +5));
+        g += (threshold >> (GGL_DITHER_BITS-8 +6));
+        b += (threshold >> (GGL_DITHER_BITS-8 +5));
+        if (r > 0xff)
+            r = 0xff;
+        if (g > 0xff)
+            g = 0xff;
+        if (b > 0xff)
+            b = 0xff;
+        return uint16_t(((r & 0xf8) << 8) | ((g & 0xfc) << 3) | (b >> 3));
+    }
+protected:
+    const uint8_t* m_line;
+    int            m_index;
+};
+
+/* This structure is used to blend (SRC_OVER) 32-bit source pixels
+ * onto 16-bit destination ones. Usage is simply:
+ *
+ *   blender.blend(<32-bit-src-pixel-value>,<ptr-to-16-bit-dest-pixel>)
+ */
+struct blender_32to16 {
+    blender_32to16(context_t* c) { }
+    void write(uint32_t s, uint16_t* dst) {
+        if (s == 0)
+            return;
+        s = GGL_RGBA_TO_HOST(s);
+        int sA = (s>>24);
+        if (sA == 0xff) {
+            *dst = convertAbgr8888ToRgb565(s);
+        } else {
+            int f = 0x100 - (sA + (sA>>7));
+            int sR = (s >> (   3))&0x1F;
+            int sG = (s >> ( 8+2))&0x3F;
+            int sB = (s >> (16+3))&0x1F;
+            uint16_t d = *dst;
+            int dR = (d>>11)&0x1f;
+            int dG = (d>>5)&0x3f;
+            int dB = (d)&0x1f;
+            sR += (f*dR)>>8;
+            sG += (f*dG)>>8;
+            sB += (f*dB)>>8;
+            *dst = uint16_t((sR<<11)|(sG<<5)|sB);
+        }
+    }
+    void write(uint32_t s, uint16_t* dst, ditherer& di) {
+        if (s == 0) {
+            di.step();
+            return;
+        }
+        s = GGL_RGBA_TO_HOST(s);
+        int sA = (s>>24);
+        if (sA == 0xff) {
+            *dst = di.abgr8888ToRgb565(s);
+        } else {
+            int threshold = di.get_value() << (8 - GGL_DITHER_BITS);
+            int f = 0x100 - (sA + (sA>>7));
+            int sR = (s >> (   3))&0x1F;
+            int sG = (s >> ( 8+2))&0x3F;
+            int sB = (s >> (16+3))&0x1F;
+            uint16_t d = *dst;
+            int dR = (d>>11)&0x1f;
+            int dG = (d>>5)&0x3f;
+            int dB = (d)&0x1f;
+            sR = ((sR << 8) + f*dR + threshold)>>8;
+            sG = ((sG << 8) + f*dG + threshold)>>8;
+            sB = ((sB << 8) + f*dB + threshold)>>8;
+            if (sR > 0x1f) sR = 0x1f;
+            if (sG > 0x3f) sG = 0x3f;
+            if (sB > 0x1f) sB = 0x1f;
+            *dst = uint16_t((sR<<11)|(sG<<5)|sB);
+        }
+    }
+};
+
+/* This blender does the same for the 'blend_srca' operation.
+ * where dstFactor=srcA*(1-srcA) srcFactor=srcA
+ */
+struct blender_32to16_srcA {
+    blender_32to16_srcA(const context_t* c) { }
+    void write(uint32_t s, uint16_t* dst) {
+        if (!s) {
+            return;
+        }
+        uint16_t d = *dst;
+        s = GGL_RGBA_TO_HOST(s);
+        int sR = (s >> (   3))&0x1F;
+        int sG = (s >> ( 8+2))&0x3F;
+        int sB = (s >> (16+3))&0x1F;
+        int sA = (s>>24);
+        int f1 = (sA + (sA>>7));
+        int f2 = 0x100-f1;
+        int dR = (d>>11)&0x1f;
+        int dG = (d>>5)&0x3f;
+        int dB = (d)&0x1f;
+        sR = (f1*sR + f2*dR)>>8;
+        sG = (f1*sG + f2*dG)>>8;
+        sB = (f1*sB + f2*dB)>>8;
+        *dst = uint16_t((sR<<11)|(sG<<5)|sB);
+    }
+};
+
+/* Common init code the modulating blenders */
+struct blender_modulate {
+    void init(const context_t* c) {
+        const int r = c->iterators.ydrdy >> (GGL_COLOR_BITS-8);
+        const int g = c->iterators.ydgdy >> (GGL_COLOR_BITS-8);
+        const int b = c->iterators.ydbdy >> (GGL_COLOR_BITS-8);
+        const int a = c->iterators.ydady >> (GGL_COLOR_BITS-8);
+        m_r = r + (r >> 7);
+        m_g = g + (g >> 7);
+        m_b = b + (b >> 7);
+        m_a = a + (a >> 7);
+    }
+protected:
+    int m_r, m_g, m_b, m_a;
+};
+
+/* This blender does a normal blend after modulation.
+ */
+struct blender_32to16_modulate : blender_modulate {
+    blender_32to16_modulate(const context_t* c) {
+        init(c);
+    }
+    void write(uint32_t s, uint16_t* dst) {
+        // blend source and destination
+        if (!s) {
+            return;
+        }
+        s = GGL_RGBA_TO_HOST(s);
+
+        /* We need to modulate s */
+        uint32_t  sA = (s >> 24);
+        uint32_t  sB = (s >> 16) & 0xff;
+        uint32_t  sG = (s >> 8) & 0xff;
+        uint32_t  sR = s & 0xff;
+
+        sA = (sA*m_a) >> 8;
+        /* Keep R/G/B scaled to 5.8 or 6.8 fixed float format */
+        sR = (sR*m_r) >> (8 - 5);
+        sG = (sG*m_g) >> (8 - 6);
+        sB = (sB*m_b) >> (8 - 5);
+
+        /* Now do a normal blend */
+        int f = 0x100 - (sA + (sA>>7));
+        uint16_t d = *dst;
+        int dR = (d>>11)&0x1f;
+        int dG = (d>>5)&0x3f;
+        int dB = (d)&0x1f;
+        sR = (sR + f*dR)>>8;
+        sG = (sG + f*dG)>>8;
+        sB = (sB + f*dB)>>8;
+        *dst = uint16_t((sR<<11)|(sG<<5)|sB);
+    }
+    void write(uint32_t s, uint16_t* dst, ditherer& di) {
+        // blend source and destination
+        if (!s) {
+            di.step();
+            return;
+        }
+        s = GGL_RGBA_TO_HOST(s);
+
+        /* We need to modulate s */
+        uint32_t  sA = (s >> 24);
+        uint32_t  sB = (s >> 16) & 0xff;
+        uint32_t  sG = (s >> 8) & 0xff;
+        uint32_t  sR = s & 0xff;
+
+        sA = (sA*m_a) >> 8;
+        /* keep R/G/B scaled to 5.8 or 6.8 fixed float format */
+        sR = (sR*m_r) >> (8 - 5);
+        sG = (sG*m_g) >> (8 - 6);
+        sB = (sB*m_b) >> (8 - 5);
+
+        /* Scale threshold to 0.8 fixed float format */
+        int threshold = di.get_value() << (8 - GGL_DITHER_BITS);
+        int f = 0x100 - (sA + (sA>>7));
+        uint16_t d = *dst;
+        int dR = (d>>11)&0x1f;
+        int dG = (d>>5)&0x3f;
+        int dB = (d)&0x1f;
+        sR = (sR + f*dR + threshold)>>8;
+        sG = (sG + f*dG + threshold)>>8;
+        sB = (sB + f*dB + threshold)>>8;
+        if (sR > 0x1f) sR = 0x1f;
+        if (sG > 0x3f) sG = 0x3f;
+        if (sB > 0x1f) sB = 0x1f;
+        *dst = uint16_t((sR<<11)|(sG<<5)|sB);
+    }
+};
+
+/* same as 32to16_modulate, except that the input is xRGB, instead of ARGB */
+struct blender_x32to16_modulate : blender_modulate {
+    blender_x32to16_modulate(const context_t* c) {
+        init(c);
+    }
+    void write(uint32_t s, uint16_t* dst) {
+        s = GGL_RGBA_TO_HOST(s);
+
+        uint32_t  sB = (s >> 16) & 0xff;
+        uint32_t  sG = (s >> 8) & 0xff;
+        uint32_t  sR = s & 0xff;
+
+        /* Keep R/G/B in 5.8 or 6.8 format */
+        sR = (sR*m_r) >> (8 - 5);
+        sG = (sG*m_g) >> (8 - 6);
+        sB = (sB*m_b) >> (8 - 5);
+
+        int f = 0x100 - m_a;
+        uint16_t d = *dst;
+        int dR = (d>>11)&0x1f;
+        int dG = (d>>5)&0x3f;
+        int dB = (d)&0x1f;
+        sR = (sR + f*dR)>>8;
+        sG = (sG + f*dG)>>8;
+        sB = (sB + f*dB)>>8;
+        *dst = uint16_t((sR<<11)|(sG<<5)|sB);
+    }
+    void write(uint32_t s, uint16_t* dst, ditherer& di) {
+        s = GGL_RGBA_TO_HOST(s);
+
+        uint32_t  sB = (s >> 16) & 0xff;
+        uint32_t  sG = (s >> 8) & 0xff;
+        uint32_t  sR = s & 0xff;
+
+        sR = (sR*m_r) >> (8 - 5);
+        sG = (sG*m_g) >> (8 - 6);
+        sB = (sB*m_b) >> (8 - 5);
+
+        /* Now do a normal blend */
+        int threshold = di.get_value() << (8 - GGL_DITHER_BITS);
+        int f = 0x100 - m_a;
+        uint16_t d = *dst;
+        int dR = (d>>11)&0x1f;
+        int dG = (d>>5)&0x3f;
+        int dB = (d)&0x1f;
+        sR = (sR + f*dR + threshold)>>8;
+        sG = (sG + f*dG + threshold)>>8;
+        sB = (sB + f*dB + threshold)>>8;
+        if (sR > 0x1f) sR = 0x1f;
+        if (sG > 0x3f) sG = 0x3f;
+        if (sB > 0x1f) sB = 0x1f;
+        *dst = uint16_t((sR<<11)|(sG<<5)|sB);
+    }
+};
+
+/* Same as above, but source is 16bit rgb565 */
+struct blender_16to16_modulate : blender_modulate {
+    blender_16to16_modulate(const context_t* c) {
+        init(c);
+    }
+    void write(uint16_t s16, uint16_t* dst) {
+        uint32_t  s = s16;
+
+        uint32_t  sR = s >> 11;
+        uint32_t  sG = (s >> 5) & 0x3f;
+        uint32_t  sB = s & 0x1f;
+
+        sR = (sR*m_r);
+        sG = (sG*m_g);
+        sB = (sB*m_b);
+
+        int f = 0x100 - m_a;
+        uint16_t d = *dst;
+        int dR = (d>>11)&0x1f;
+        int dG = (d>>5)&0x3f;
+        int dB = (d)&0x1f;
+        sR = (sR + f*dR)>>8;
+        sG = (sG + f*dG)>>8;
+        sB = (sB + f*dB)>>8;
+        *dst = uint16_t((sR<<11)|(sG<<5)|sB);
+    }
+};
+
+/* This is used to iterate over a 16-bit destination color buffer.
+ * Usage is:
+ *
+ *   dst_iterator16  di(context);
+ *   while (di.count--) {
+ *       <do stuff with dest pixel at di.dst>
+ *       di.dst++;
+ *   }
+ */
+struct dst_iterator16 {
+    dst_iterator16(const context_t* c) {
+        const int x = c->iterators.xl;
+        const int width = c->iterators.xr - x;
+        const int32_t y = c->iterators.y;
+        const surface_t* cb = &(c->state.buffers.color);
+        count = width;
+        dst = reinterpret_cast<uint16_t*>(cb->data) + (x+(cb->stride*y));
+    }
+    int        count;
+    uint16_t*  dst;
+};
+
+
+static void scanline_t32cb16_clamp(context_t* c)
+{
+    dst_iterator16  di(c);
+
+    if (is_context_horizontal(c)) {
+        /* Special case for simple horizontal scaling */
+        horz_clamp_iterator32 ci(c);
+        while (di.count--) {
+            uint32_t s = ci.get_pixel32();
+            *di.dst++ = convertAbgr8888ToRgb565(s);
+        }
+    } else {
+        /* General case */
+        clamp_iterator ci(c);
+        while (di.count--) {
+            uint32_t s = ci.get_pixel32();
+            *di.dst++ = convertAbgr8888ToRgb565(s);
+        }
+    }
+}
+
+static void scanline_t32cb16_dither(context_t* c)
+{
+    horz_iterator32 si(c);
+    dst_iterator16  di(c);
+    ditherer        dither(c);
+
+    while (di.count--) {
+        uint32_t s = si.get_pixel32();
+        *di.dst++ = dither.abgr8888ToRgb565(s);
+    }
+}
+
+static void scanline_t32cb16_clamp_dither(context_t* c)
+{
+    dst_iterator16  di(c);
+    ditherer        dither(c);
+
+    if (is_context_horizontal(c)) {
+        /* Special case for simple horizontal scaling */
+        horz_clamp_iterator32 ci(c);
+        while (di.count--) {
+            uint32_t s = ci.get_pixel32();
+            *di.dst++ = dither.abgr8888ToRgb565(s);
+        }
+    } else {
+        /* General case */
+        clamp_iterator ci(c);
+        while (di.count--) {
+            uint32_t s = ci.get_pixel32();
+            *di.dst++ = dither.abgr8888ToRgb565(s);
+        }
+    }
+}
+
+static void scanline_t32cb16blend_dither(context_t* c)
+{
+    dst_iterator16 di(c);
+    ditherer       dither(c);
+    blender_32to16 bl(c);
+    horz_iterator32  hi(c);
+    while (di.count--) {
+        uint32_t s = hi.get_pixel32();
+        bl.write(s, di.dst, dither);
+        di.dst++;
+    }
+}
+
+static void scanline_t32cb16blend_clamp(context_t* c)
+{
+    dst_iterator16  di(c);
+    blender_32to16  bl(c);
+
+    if (is_context_horizontal(c)) {
+        horz_clamp_iterator32 ci(c);
+        while (di.count--) {
+            uint32_t s = ci.get_pixel32();
+            bl.write(s, di.dst);
+            di.dst++;
+        }
+    } else {
+        clamp_iterator ci(c);
+        while (di.count--) {
+            uint32_t s = ci.get_pixel32();
+            bl.write(s, di.dst);
+            di.dst++;
+        }
+    }
+}
+
+static void scanline_t32cb16blend_clamp_dither(context_t* c)
+{
+    dst_iterator16 di(c);
+    ditherer       dither(c);
+    blender_32to16 bl(c);
+
+    clamp_iterator ci(c);
+    while (di.count--) {
+        uint32_t s = ci.get_pixel32();
+        bl.write(s, di.dst, dither);
+        di.dst++;
+    }
+}
+
+void scanline_t32cb16blend_clamp_mod(context_t* c)
+{
+    dst_iterator16 di(c);
+    blender_32to16_modulate bl(c);
+
+    clamp_iterator ci(c);
+    while (di.count--) {
+        uint32_t s = ci.get_pixel32();
+        bl.write(s, di.dst);
+        di.dst++;
+    }
+}
+
+void scanline_t32cb16blend_clamp_mod_dither(context_t* c)
+{
+    dst_iterator16 di(c);
+    blender_32to16_modulate bl(c);
+    ditherer dither(c);
+
+    clamp_iterator ci(c);
+    while (di.count--) {
+        uint32_t s = ci.get_pixel32();
+        bl.write(s, di.dst, dither);
+        di.dst++;
+    }
+}
+
+/* Variant of scanline_t32cb16blend_clamp_mod with a xRGB texture */
+void scanline_x32cb16blend_clamp_mod(context_t* c)
+{
+    dst_iterator16 di(c);
+    blender_x32to16_modulate  bl(c);
+
+    clamp_iterator ci(c);
+    while (di.count--) {
+        uint32_t s = ci.get_pixel32();
+        bl.write(s, di.dst);
+        di.dst++;
+    }
+}
+
+void scanline_x32cb16blend_clamp_mod_dither(context_t* c)
+{
+    dst_iterator16 di(c);
+    blender_x32to16_modulate  bl(c);
+    ditherer dither(c);
+
+    clamp_iterator ci(c);
+    while (di.count--) {
+        uint32_t s = ci.get_pixel32();
+        bl.write(s, di.dst, dither);
+        di.dst++;
+    }
+}
+
+void scanline_t16cb16_clamp(context_t* c)
+{
+    dst_iterator16  di(c);
+
+    /* Special case for simple horizontal scaling */
+    if (is_context_horizontal(c)) {
+        horz_clamp_iterator16 ci(c);
+        while (di.count--) {
+            *di.dst++ = ci.get_pixel16();
+        }
+    } else {
+        clamp_iterator ci(c);
+        while (di.count--) {
+            *di.dst++ = ci.get_pixel16();
+        }
+    }
+}
+
+
+
 template <typename T, typename U>
 static inline __attribute__((const))
 T interpolate(int y, T v0, U dvdx, U dvdy) {
@@ -1322,30 +2107,24 @@
     if (ct==1 || uint32_t(dst)&2) {
 last_one:
         s = GGL_RGBA_TO_HOST( *src++ );
-        sR = (s >> (   3))&0x1F;
-        sG = (s >> ( 8+2))&0x3F;
-        sB = (s >> (16+3))&0x1F;
-        *dst++ = uint16_t((sR<<11)|(sG<<5)|sB);
+        *dst++ = convertAbgr8888ToRgb565(s);
         ct--;
     }
 
     while (ct >= 2) {
-        s = GGL_RGBA_TO_HOST( *src++ );
-        sR = (s >> (   3))&0x1F;
-        sG = (s >> ( 8+2))&0x3F;
-        sB = (s >> (16+3))&0x1F;
-        d = (sR<<11)|(sG<<5)|sB;
-        
-        s = GGL_RGBA_TO_HOST( *src++ );
-        sR = (s >> (   3))&0x1F;
-        sG = (s >> ( 8+2))&0x3F;
-        sB = (s >> (16+3))&0x1F;        
-        d |= ((sR<<11)|(sG<<5)|sB)<<16;
-
 #if BYTE_ORDER == BIG_ENDIAN
-        d = (d>>16) | (d<<16);
-#endif
+        s = GGL_RGBA_TO_HOST( *src++ );
+        d = convertAbgr8888ToRgb565_hi16(s);
 
+        s = GGL_RGBA_TO_HOST( *src++ );
+        d |= convertAbgr8888ToRgb565(s);
+#else
+        s = GGL_RGBA_TO_HOST( *src++ );
+        d = convertAbgr8888ToRgb565(s);
+
+        s = GGL_RGBA_TO_HOST( *src++ );
+        d |= convertAbgr8888ToRgb565(s) << 16;
+#endif
         *dst32++ = d;
         ct -= 2;
     }
@@ -1357,6 +2136,7 @@
 
 void scanline_t32cb16blend(context_t* c)
 {
+#if ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && defined(__arm__))
     int32_t x = c->iterators.xl;
     size_t ct = c->iterators.xr - x;
     int32_t y = c->iterators.y;
@@ -1368,33 +2148,55 @@
     const int32_t v = (c->state.texture[0].shade.it0>>16) + y;
     uint32_t *src = reinterpret_cast<uint32_t*>(tex->data)+(u+(tex->stride*v));
 
-#if ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && defined(__arm__))
     scanline_t32cb16blend_arm(dst, src, ct);
 #else
-    while (ct--) {
-        uint32_t s = *src++;
-        if (!s) {
-            dst++;
-            continue;
-        }
-        uint16_t d = *dst;
-        s = GGL_RGBA_TO_HOST(s);
-        int sR = (s >> (   3))&0x1F;
-        int sG = (s >> ( 8+2))&0x3F;
-        int sB = (s >> (16+3))&0x1F;
-        int sA = (s>>24);
-        int f = 0x100 - (sA + (sA>>7));
-        int dR = (d>>11)&0x1f;
-        int dG = (d>>5)&0x3f;
-        int dB = (d)&0x1f;
-        sR += (f*dR)>>8;
-        sG += (f*dG)>>8;
-        sB += (f*dB)>>8;
-        *dst++ = uint16_t((sR<<11)|(sG<<5)|sB);
+    dst_iterator16  di(c);
+    horz_iterator32  hi(c);
+    blender_32to16  bl(c);
+    while (di.count--) {
+        uint32_t s = hi.get_pixel32();
+        bl.write(s, di.dst);
+        di.dst++;
     }
 #endif
 }
 
+void scanline_t32cb16blend_srca(context_t* c)
+{
+    dst_iterator16  di(c);
+    horz_iterator32  hi(c);
+    blender_32to16_srcA  blender(c);
+
+    while (di.count--) {
+        uint32_t s = hi.get_pixel32();
+        blender.write(s,di.dst);
+        di.dst++;
+    }
+}
+
+void scanline_t16cb16blend_clamp_mod(context_t* c)
+{
+    const int a = c->iterators.ydady >> (GGL_COLOR_BITS-8);
+    if (a == 0) {
+        return;
+    }
+
+    if (a == 255) {
+        scanline_t16cb16_clamp(c);
+        return;
+    }
+
+    dst_iterator16  di(c);
+    blender_16to16_modulate  blender(c);
+    clamp_iterator  ci(c);
+
+    while (di.count--) {
+        uint16_t s = ci.get_pixel16();
+        blender.write(s, di.dst);
+        di.dst++;
+    }
+}
+
 void scanline_memcpy(context_t* c)
 {
     int32_t x = c->iterators.xl;
diff --git a/libsysutils/Android.mk b/libsysutils/Android.mk
index dd2b32d..3b1f618 100644
--- a/libsysutils/Android.mk
+++ b/libsysutils/Android.mk
@@ -1,3 +1,4 @@
+ifneq ($(BUILD_TINY_ANDROID),true)
 BUILD_LIBSYSUTILS := false
 ifneq ($(TARGET_SIMULATOR),true)
     BUILD_LIBSYSUTILS := true
@@ -33,3 +34,4 @@
 include $(BUILD_SHARED_LIBRARY)
 
 endif
+endif
diff --git a/libsysutils/src/NetlinkListener.cpp b/libsysutils/src/NetlinkListener.cpp
index a4f62c6..b24a45e 100644
--- a/libsysutils/src/NetlinkListener.cpp
+++ b/libsysutils/src/NetlinkListener.cpp
@@ -17,10 +17,12 @@
 
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <linux/netlink.h>
 #include <string.h>
 
 #define LOG_TAG "NetlinkListener"
 #include <cutils/log.h>
+#include <cutils/uevent.h>
 
 #include <sysutils/NetlinkListener.h>
 #include <sysutils/NetlinkEvent.h>
@@ -32,11 +34,11 @@
 bool NetlinkListener::onDataAvailable(SocketClient *cli)
 {
     int socket = cli->getSocket();
-    int count;
+    ssize_t count;
 
-    count = TEMP_FAILURE_RETRY(recv(socket, mBuffer, sizeof(mBuffer), 0));
+    count = TEMP_FAILURE_RETRY(uevent_checked_recv(socket, mBuffer, sizeof(mBuffer)));
     if (count < 0) {
-        SLOGE("recv failed (%s)", strerror(errno));
+        SLOGE("recvmsg failed (%s)", strerror(errno));
         return false;
     }
 
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index a6aed26..90ca52e 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -15,8 +15,10 @@
         , mPid(-1)
         , mUid(-1)
         , mGid(-1)
+        , mRefCount(1)
 {
     pthread_mutex_init(&mWriteMutex, NULL);
+    pthread_mutex_init(&mRefCountMutex, NULL);
 
     struct ucred creds;
     socklen_t szCreds = sizeof(creds);
@@ -100,3 +102,25 @@
     pthread_mutex_unlock(&mWriteMutex);
     return 0;
 }
+
+void SocketClient::incRef() {
+    pthread_mutex_lock(&mRefCountMutex);
+    mRefCount++;
+    pthread_mutex_unlock(&mRefCountMutex);
+}
+
+bool SocketClient::decRef() {
+    bool deleteSelf = false;
+    pthread_mutex_lock(&mRefCountMutex);
+    mRefCount--;
+    if (mRefCount == 0) {
+        deleteSelf = true;
+    } else if (mRefCount < 0) {
+        SLOGE("SocketClient refcount went negative!");
+    }
+    pthread_mutex_unlock(&mRefCountMutex);
+    if (deleteSelf) {
+        delete this;
+    }
+    return deleteSelf;
+}
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 611d5fe..fcad624 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -55,7 +55,7 @@
     }
     SocketClientCollection::iterator it;
     for (it = mClients->begin(); it != mClients->end();) {
-        delete (*it);
+        (*it)->decRef();
         it = mClients->erase(it);
     }
     delete mClients;
@@ -213,8 +213,9 @@
             it = pendingList->begin();
             SocketClient* c = *it;
             pendingList->erase(it);
-            /* Process it, if false is returned, remove and destroy it */
-            if (!onDataAvailable(c)) {
+            /* Process it, if false is returned and our sockets are
+             * connection-based, remove and destroy it */
+            if (!onDataAvailable(c) && mListen) {
                 /* Remove the client from our array */
                 pthread_mutex_lock(&mClientsLock);
                 for (it = mClients->begin(); it != mClients->end(); ++it) {
@@ -225,8 +226,11 @@
                 }
                 pthread_mutex_unlock(&mClientsLock);
                 /* Destroy the client */
-                close(c->getSocket());
-                delete c;
+                int socket = c->getSocket();
+                if (c->decRef()) {
+                    // Note: 'c' is deleted memory at this point.
+                    close(socket);
+                }
             }
         }
     }
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index d6736d3..b1c967d 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -53,6 +53,9 @@
 #define USB_FS_ID_SCANNER   "/dev/bus/usb/%d/%d"
 #define USB_FS_ID_FORMAT    "/dev/bus/usb/%03d/%03d"
 
+// From drivers/usb/core/devio.c
+// I don't know why this isn't in a kernel header
+#define MAX_USBFS_BUFFER_SIZE   16384
 
 struct usb_host_context {
     int fd;
@@ -60,7 +63,7 @@
 
 struct usb_device {
     char dev_name[64];
-    unsigned char desc[256];
+    unsigned char desc[4096];
     int desc_length;
     int fd;
     int writeable;
@@ -204,6 +207,8 @@
 {
     int fd, did_retry = 0, writeable = 1;
 
+    D("usb_device_open %s\n", dev_name);
+
 retry:
     fd = open(dev_name, O_RDWR);
     if (fd < 0) {
@@ -240,10 +245,12 @@
     struct usb_device *device = calloc(1, sizeof(struct usb_device));
     int length;
 
+    D("usb_device_new %s fd: %d\n", dev_name, fd);
+
     if (lseek(fd, 0, SEEK_SET) != 0)
         goto failed;
     length = read(fd, device->desc, sizeof(device->desc));
-    D("usb_device_new read returned %d errno %d\n", fd, errno);
+    D("usb_device_new read returned %d errno %d\n", length, errno);
     if (length < 0)
         goto failed;
 
@@ -328,30 +335,6 @@
     return (struct usb_device_descriptor*)device->desc;
 }
 
-int usb_device_send_control(struct usb_device *device,
-                            int requestType,
-                            int request,
-                            int value,
-                            int index,
-                            int length,
-                            void* buffer)
-{
-    struct usbdevfs_ctrltransfer  ctrl;
-
-    // this usually requires read/write permission
-    if (!usb_device_reopen_writeable(device))
-        return -1;
-
-    memset(&ctrl, 0, sizeof(ctrl));
-    ctrl.bRequestType = requestType;
-    ctrl.bRequest = request;
-    ctrl.wValue = value;
-    ctrl.wIndex = index;
-    ctrl.wLength = length;
-    ctrl.data = buffer;
-    return ioctl(device->fd, USBDEVFS_CONTROL, &ctrl);
-}
-
 char* usb_device_get_string(struct usb_device *device, int id)
 {
     char string[256];
@@ -364,18 +347,18 @@
     memset(languages, 0, sizeof(languages));
 
     // read list of supported languages
-    result = usb_device_send_control(device,
+    result = usb_device_control_transfer(device,
             USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR,
-            (USB_DT_STRING << 8) | 0, 0, sizeof(languages), languages);
+            (USB_DT_STRING << 8) | 0, 0, languages, sizeof(languages), 0);
     if (result > 0)
         languageCount = (result - 2) / 2;
 
     for (i = 1; i <= languageCount; i++) {
         memset(buffer, 0, sizeof(buffer));
 
-        result = usb_device_send_control(device,
+        result = usb_device_control_transfer(device,
                 USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR,
-                (USB_DT_STRING << 8) | id, languages[i], sizeof(buffer), buffer);
+                (USB_DT_STRING << 8) | id, languages[i], buffer, sizeof(buffer), 0);
         if (result > 0) {
             int i;
             // skip first word, and copy the rest to the string, changing shorts to bytes.
@@ -452,6 +435,63 @@
     return ioctl(device->fd, USBDEVFS_RELEASEINTERFACE, &interface);
 }
 
+int usb_device_connect_kernel_driver(struct usb_device *device,
+        unsigned int interface, int connect)
+{
+    struct usbdevfs_ioctl ctl;
+
+    ctl.ifno = interface;
+    ctl.ioctl_code = (connect ? USBDEVFS_CONNECT : USBDEVFS_DISCONNECT);
+    ctl.data = NULL;
+    return ioctl(device->fd, USBDEVFS_IOCTL, &ctl);
+}
+
+int usb_device_control_transfer(struct usb_device *device,
+                            int requestType,
+                            int request,
+                            int value,
+                            int index,
+                            void* buffer,
+                            int length,
+                            unsigned int timeout)
+{
+    struct usbdevfs_ctrltransfer  ctrl;
+
+    // this usually requires read/write permission
+    if (!usb_device_reopen_writeable(device))
+        return -1;
+
+    memset(&ctrl, 0, sizeof(ctrl));
+    ctrl.bRequestType = requestType;
+    ctrl.bRequest = request;
+    ctrl.wValue = value;
+    ctrl.wIndex = index;
+    ctrl.wLength = length;
+    ctrl.data = buffer;
+    ctrl.timeout = timeout;
+    return ioctl(device->fd, USBDEVFS_CONTROL, &ctrl);
+}
+
+int usb_device_bulk_transfer(struct usb_device *device,
+                            int endpoint,
+                            void* buffer,
+                            int length,
+                            unsigned int timeout)
+{
+    struct usbdevfs_bulktransfer  ctrl;
+
+    // need to limit request size to avoid EINVAL
+    if (length > MAX_USBFS_BUFFER_SIZE)
+        length = MAX_USBFS_BUFFER_SIZE;
+
+    memset(&ctrl, 0, sizeof(ctrl));
+    ctrl.ep = endpoint;
+    ctrl.len = length;
+    ctrl.data = buffer;
+    ctrl.timeout = timeout;
+    return ioctl(device->fd, USBDEVFS_BULK, &ctrl);
+}
+
 struct usb_request *usb_request_new(struct usb_device *dev,
         const struct usb_endpoint_descriptor *ep_desc)
 {
@@ -479,6 +519,7 @@
     req->dev = dev;
     req->max_packet_size = __le16_to_cpu(ep_desc->wMaxPacketSize);
     req->private_data = urb;
+    req->endpoint = urb->endpoint;
     urb->usercontext = req;
 
     return req;
@@ -497,7 +538,11 @@
 
     urb->status = -1;
     urb->buffer = req->buffer;
-    urb->buffer_length = req->buffer_length;
+    // need to limit request size to avoid EINVAL
+    if (req->buffer_length > MAX_USBFS_BUFFER_SIZE)
+        urb->buffer_length = MAX_USBFS_BUFFER_SIZE;
+    else
+        urb->buffer_length = req->buffer_length;
 
     do {
         res = ioctl(req->dev->fd, USBDEVFS_SUBMITURB, urb);
diff --git a/netcfg/netcfg.c b/netcfg/netcfg.c
index 9cd883a..c520075 100644
--- a/netcfg/netcfg.c
+++ b/netcfg/netcfg.c
@@ -20,6 +20,7 @@
 #include <errno.h>
 #include <dirent.h>
 #include <netinet/ether.h>
+#include <netinet/if_ether.h>
 
 #include <netutils/ifc.h>
 #include <netutils/dhcp.h>
@@ -44,21 +45,30 @@
 void usage(void)
 {
     fprintf(stderr,"usage: netcfg [<interface> {dhcp|up|down}]\n");
-    exit(1);    
+    exit(1);
 }
 
 int dump_interface(const char *name)
 {
-    unsigned addr, mask, flags;
-    
-    if(ifc_get_info(name, &addr, &mask, &flags)) {
+    unsigned addr, prefixLength, flags;
+    unsigned char hwbuf[ETH_ALEN];
+
+    if(ifc_get_info(name, &addr, &prefixLength, &flags)) {
         return 0;
     }
 
     printf("%-8s %s  ", name, flags & 1 ? "UP  " : "DOWN");
-    printf("%-16s", ipaddr(addr));
-    printf("%-16s", ipaddr(mask));
-    printf("0x%08x\n", flags);
+    printf("%40s", ipaddr(addr));
+    printf("/%-4d", prefixLength);
+    printf("0x%08x ", flags);
+    if (!ifc_get_hwaddr(name, hwbuf)) {
+        int i;
+        for(i=0; i < (ETH_ALEN-1); i++)
+            printf("%02x:", hwbuf[i]);
+        printf("%02x\n", hwbuf[i]);
+    } else {
+        printf("\n");
+    }
     return 0;
 }
 
@@ -66,10 +76,10 @@
 {
     DIR *d;
     struct dirent *de;
-    
+
     d = opendir("/sys/class/net");
     if(d == 0) return -1;
-    
+
     while((de = readdir(d))) {
         if(de->d_name[0] == '.') continue;
         dump_interface(de->d_name);
diff --git a/patch.txt b/patch.txt
deleted file mode 100644
index 258965d..0000000
--- a/patch.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-diff --git a/init/util.c b/init/util.c
-index 4d98cc2..0667593 100755
---- a/init/util.c
-+++ b/init/util.c
-@@ -657,8 +657,9 @@ static void get_hardware_name(void)
-         if (x) {
-             x += 2;
-             n = 0;
--            while (*x && !isspace(*x)) {
--                hardware[n++] = tolower(*x);
-+            while (*x && *x != '\n') {
-+                if (!isspace(*x))
-+                    hardware[n++] = tolower(*x);
-                 x++;
-                 if (n == 31) break;
-             }
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 380bb60..1a9e06f 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -11,6 +11,10 @@
 copy_from += etc/vold.fstab
 endif
 
+ifeq ($(TARGET_PRODUCT),full_x86)
+copy_from += etc/vold.fstab
+endif
+
 # the /system/etc/init.goldfish.sh is needed to enable emulator support
 # in the system image. In theory, we don't need these for -user builds
 # which are device-specific. However, these builds require at the moment
diff --git a/rootdir/etc/init.goldfish.rc b/rootdir/etc/init.goldfish.rc
index 7cc028f..1ac09ca 100644
--- a/rootdir/etc/init.goldfish.rc
+++ b/rootdir/etc/init.goldfish.rc
@@ -28,12 +28,6 @@
     start goldfish-logcat
     start goldfish-setup
 
-    # This is a workaround for another bug in init and init.rc
-    # where the late_start class of services is never started
-    # properly when running an unencrypted /data partition.
-    #
-    start ril-daemon
-
     setprop ro.setupwizard.mode EMULATOR
 
 # enable Google-specific location features,
diff --git a/rootdir/etc/ueventd.goldfish.rc b/rootdir/etc/ueventd.goldfish.rc
index b5828e7..8de7049 100644
--- a/rootdir/etc/ueventd.goldfish.rc
+++ b/rootdir/etc/ueventd.goldfish.rc
@@ -1,4 +1,5 @@
 # These settings are specific to running under the Android emulator
 /dev/qemu_trace           0666   system     system
+/dev/qemu_pipe            0666   system     system
 /dev/ttyS*                0666   system     system
 /proc                     0666   system     system
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 12db34d..54873e0 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -19,7 +19,7 @@
     export ANDROID_DATA /data
     export ASEC_MOUNTPOINT /mnt/asec
     export LOOP_MOUNTPOINT /mnt/obb
-    export BOOTCLASSPATH /system/framework/core.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/core-junit.jar
+    export BOOTCLASSPATH /system/framework/core.jar:/system/framework/apache-xml.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/core-junit.jar
 
 # Backward compatibility
     symlink /system/etc /etc
@@ -150,6 +150,7 @@
     mkdir /data/misc/bluetoothd 0770 bluetooth bluetooth
     mkdir /data/misc/bluetooth 0770 system system
     mkdir /data/misc/keystore 0700 keystore keystore
+    mkdir /data/misc/keychain 0771 keychain keychain
     mkdir /data/misc/vpn 0770 system system
     mkdir /data/misc/systemkeys 0700 system system
     mkdir /data/misc/vpn/profiles 0770 system system
@@ -176,11 +177,8 @@
     chown root root /data/lost+found
     chmod 0770 /data/lost+found
 
-    # temporarily disable the drm server
     # create directory for DRM plug-ins
-    #mkdir /data/drm 0774 drm drm
-    #mkdir /data/drm/plugins 0774 drm drm
-    #mkdir /data/drm/plugins/native 0774 drm drm
+    mkdir /data/drm 0774 drm drm
 
     # If there is no fs-post-data action in the init.<device>.rc file, you
     # must uncomment this line, otherwise encrypted filesystems
@@ -298,6 +296,9 @@
     setprop net.tcp.buffersize.edge    4093,26280,35040,4096,16384,35040
     setprop net.tcp.buffersize.gprs    4092,8760,11680,4096,8760,11680
 
+# Set this property so surfaceflinger is not started by system_init
+    setprop system_init.startsurfaceflinger 0
+
     class_start core
     class_start main
 
@@ -307,6 +308,9 @@
 on property:vold.decrypt=trigger_reset_main
     class_reset main
 
+on property:vold.decrypt=trigger_load_persist_props
+    load_persist_props
+
 on property:vold.decrypt=trigger_post_fs_data
     trigger post-fs-data
 
@@ -380,29 +384,30 @@
     user root
     group radio cache inet misc audio sdcard_rw
 
+service surfaceflinger /system/bin/surfaceflinger
+    class main
+    user system
+    group graphics
+    onrestart restart zygote
+
 service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
     class main
     socket zygote stream 666
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
+    onrestart restart surfaceflinger
     onrestart restart media
     onrestart restart netd
 
-# temporarily disable the drm server
-#service drm /system/bin/drmserver
-    #class main
-    #user drm
-    #group system root inet
-
-#service drmio /system/bin/drmioserver
-    #class main
-    #user drmio
-    #group drmio
+service drm /system/bin/drmserver
+    class main
+    user drm
+    group system inet
 
 service media /system/bin/mediaserver
     class main
     user media
-    group system audio camera graphics inet net_bt net_bt_admin net_raw
+    group audio camera inet net_bt net_bt_admin
     ioprio rt 4
 
 service bootanim /system/bin/bootanimation
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index d343bd4..438cf0a 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -69,13 +69,14 @@
 /dev/qmi2                 0640   radio      radio
 /dev/bus/usb/*            0660   root       usb
 /dev/mtp_usb              0660   root       mtp
+/dev/usb_accessory        0660   root       usb
+/dev/tun                  0660   system     vpn
 
 # CDMA radio interface MUX
 /dev/ts0710mux*           0640   radio      radio
 /dev/ppp                  0660   radio      vpn
-/dev/tun                  0640   vpn        vpn
 
 # sysfs properties
 /sys/devices/virtual/input/input*   enable      0660  root   input
 /sys/devices/virtual/input/input*   poll_delay  0660  root   input
-
+/sys/devices/virtual/usb_composite/*   enable      0664  root   system
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 0b8f656..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);
 }
 
@@ -581,17 +575,50 @@
         struct fuse_attr_out out;
         char *path, buffer[PATH_BUFFER_SIZE];
         int res = 0;
+        struct timespec times[2];
 
         TRACE("SETATTR fh=%llx id=%llx valid=%x\n",
               req->fh, hdr->nodeid, req->valid);
 
-        /* XXX: incomplete implementation -- truncate only.  chmod/chown
-         * should NEVER be implemented. */
+        /* XXX: incomplete implementation on purpose.   chmod/chown
+         * should NEVER be implemented.*/
 
         path = node_get_path(node, buffer, 0);
         if (req->valid & FATTR_SIZE)
             res = truncate(path, req->size);
+        if (res)
+            goto getout;
 
+        /* Handle changing atime and mtime.  If FATTR_ATIME_and FATTR_ATIME_NOW
+         * are both set, then set it to the current time.  Else, set it to the
+         * time specified in the request.  Same goes for mtime.  Use utimensat(2)
+         * as it allows ATIME and MTIME to be changed independently, and has
+         * nanosecond resolution which fuse also has.
+         */
+        if (req->valid & (FATTR_ATIME | FATTR_MTIME)) {
+            times[0].tv_nsec = UTIME_OMIT;
+            times[1].tv_nsec = UTIME_OMIT;
+            if (req->valid & FATTR_ATIME) {
+                if (req->valid & FATTR_ATIME_NOW) {
+                  times[0].tv_nsec = UTIME_NOW;
+                } else {
+                  times[0].tv_sec = req->atime;
+                  times[0].tv_nsec = req->atimensec;
+                }
+            }
+            if (req->valid & FATTR_MTIME) {
+                if (req->valid & FATTR_MTIME_NOW) {
+                  times[1].tv_nsec = UTIME_NOW;
+                } else {
+                  times[1].tv_sec = req->mtime;
+                  times[1].tv_nsec = req->mtimensec;
+                }
+            }
+            TRACE("Calling utimensat on %s with atime %ld, mtime=%ld\n", path, times[0].tv_sec, times[1].tv_sec);
+            res = utimensat(-1, path, times, 0);
+        }
+
+        getout:
         memset(&out, 0, sizeof(out));
         node_get_attr(node, &out.attr);
         out.attr_valid = 10;
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index bc8c02f..d7a675a 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -54,9 +54,15 @@
 	vmstat \
 	nandread \
 	ionice \
+	touch \
 	lsof
 
+ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
+TOOLS += r
+endif
+
 LOCAL_SRC_FILES:= \
+	dynarray.c \
 	toolbox.c \
 	$(patsubst %,%.c,$(TOOLS))
 
diff --git a/toolbox/dynarray.c b/toolbox/dynarray.c
new file mode 100644
index 0000000..e9b7b03
--- /dev/null
+++ b/toolbox/dynarray.c
@@ -0,0 +1,103 @@
+#include "dynarray.h"
+#include <stdlib.h>
+#include <limits.h>
+
+void
+dynarray_init( dynarray_t *a )
+{
+    a->count = a->capacity = 0;
+    a->items = NULL;
+}
+
+
+static void
+dynarray_reserve_more( dynarray_t *a, int count )
+{
+    int old_cap = a->capacity;
+    int new_cap = old_cap;
+    const int max_cap = INT_MAX/sizeof(void*);
+    void** new_items;
+    int new_count = a->count + count;
+
+    if (count <= 0)
+        return;
+
+    if (count > max_cap - a->count)
+        abort();
+
+    new_count = a->count + count;
+
+    while (new_cap < new_count) {
+        old_cap = new_cap;
+        new_cap += (new_cap >> 2) + 4;
+        if (new_cap < old_cap || new_cap > max_cap) {
+            new_cap = max_cap;
+        }
+    }
+    new_items = realloc(a->items, new_cap*sizeof(void*));
+    if (new_items == NULL)
+        abort();
+
+    a->items = new_items;
+    a->capacity = new_cap;
+}
+
+void
+dynarray_append( dynarray_t *a, void* item )
+{
+    if (a->count >= a->capacity)
+        dynarray_reserve_more(a, 1);
+
+    a->items[a->count++] = item;
+}
+
+void
+dynarray_done( dynarray_t *a )
+{
+    free(a->items);
+    a->items = NULL;
+    a->count = a->capacity = 0;
+}
+
+// string arrays
+
+void strlist_init( strlist_t *list )
+{
+    dynarray_init(list);
+}
+
+void strlist_append_b( strlist_t *list, const void* str, size_t  slen )
+{
+    char *copy = malloc(slen+1);
+    memcpy(copy, str, slen);
+    copy[slen] = '\0';
+    dynarray_append(list, copy);
+}
+
+void strlist_append_dup( strlist_t *list, const char *str)
+{
+    strlist_append_b(list, str, strlen(str));
+}
+
+void strlist_done( strlist_t *list )
+{
+    STRLIST_FOREACH(list, string, free(string));
+    dynarray_done(list);
+}
+
+static int strlist_compare_strings(const void* a, const void* b)
+{
+    const char *sa = *(const char **)a;
+    const char *sb = *(const char **)b;
+    return strcmp(sa, sb);
+}
+
+void strlist_sort( strlist_t *list )
+{
+    if (list->count > 0) {
+        qsort(list->items,
+              (size_t)list->count,
+              sizeof(void*),
+              strlist_compare_strings);
+    }
+}
diff --git a/toolbox/dynarray.h b/toolbox/dynarray.h
new file mode 100644
index 0000000..f73fb3b
--- /dev/null
+++ b/toolbox/dynarray.h
@@ -0,0 +1,80 @@
+#ifndef DYNARRAY_H
+#define DYNARRAY_H
+
+#include <stddef.h>
+
+/* simple dynamic array of pointers */
+typedef struct {
+    int count;
+    int capacity;
+    void** items;
+} dynarray_t;
+
+#define DYNARRAY_INITIALIZER  { 0, 0, NULL }
+
+void dynarray_init( dynarray_t *a );
+void dynarray_done( dynarray_t *a );
+
+void dynarray_append( dynarray_t *a, void* item );
+
+/* Used to iterate over a dynarray_t
+ * _array :: pointer to the array
+ * _item_type :: type of objects pointed to by the array
+ * _item      :: name of a local variable defined within the loop
+ *               with type '_item_type'
+ * _stmnt     :: C statement that will be executed in each iteration.
+ *
+ * You case use 'break' and 'continue' within _stmnt
+ *
+ * This macro is only intended for simple uses. I.e. do not add or
+ * remove items from the array during iteration.
+ */
+#define DYNARRAY_FOREACH_TYPE(_array,_item_type,_item,_stmnt) \
+    do { \
+        int _nn_##__LINE__ = 0; \
+        for (;_nn_##__LINE__ < (_array)->count; ++ _nn_##__LINE__) { \
+            _item_type _item = (_item_type)(_array)->items[_nn_##__LINE__]; \
+            _stmnt; \
+        } \
+    } while (0)
+
+#define DYNARRAY_FOREACH(_array,_item,_stmnt) \
+    DYNARRAY_FOREACH_TYPE(_array,void *,_item,_stmnt)
+
+/* Simple dynamic string arrays
+ *
+ * NOTE: A strlist_t owns the strings it references.
+ */
+typedef dynarray_t  strlist_t;
+
+#define  STRLIST_INITIALIZER  DYNARRAY_INITIALIZER
+
+/* Used to iterate over a strlist_t
+ * _list   :: pointer to strlist_t object
+ * _string :: name of local variable name defined within the loop with
+ *            type 'char*'
+ * _stmnt  :: C statement executed in each iteration
+ *
+ * This macro is only intended for simple uses. Do not add or remove items
+ * to/from the list during iteration.
+ */
+#define  STRLIST_FOREACH(_list,_string,_stmnt) \
+    DYNARRAY_FOREACH_TYPE(_list,char *,_string,_stmnt)
+
+void strlist_init( strlist_t *list );
+
+/* note: strlist_done will free all the strings owned by the list */
+void strlist_done( strlist_t *list );
+
+/* append a new string made of the first 'slen' characters from 'str'
+ * followed by a trailing zero.
+ */
+void strlist_append_b( strlist_t *list, const void* str, size_t  slen );
+
+/* append the copy of a given input string to a strlist_t */
+void strlist_append_dup( strlist_t *list, const char *str);
+
+/* sort the strings in a given list (using strcmp) */
+void strlist_sort( strlist_t *list );
+
+#endif /* DYNARRAY_H */
\ No newline at end of file
diff --git a/toolbox/getprop.c b/toolbox/getprop.c
index fc80a4d..c001fda 100644
--- a/toolbox/getprop.c
+++ b/toolbox/getprop.c
@@ -1,13 +1,34 @@
 #include <stdio.h>
+#include <stdlib.h>
 
 #include <cutils/properties.h>
 
 #include <sys/system_properties.h>
+#include "dynarray.h"
 
-static void proplist(const char *key, const char *name, 
-                     void *user __attribute__((unused)))
+static void record_prop(const char* key, const char* name, void* opaque)
 {
-    printf("[%s]: [%s]\n", key, name);
+    strlist_t* list = opaque;
+    char temp[PROP_VALUE_MAX + PROP_NAME_MAX + 16];
+    snprintf(temp, sizeof temp, "[%s]: [%s]", key, name);
+    strlist_append_dup(list, temp);
+}
+
+static void list_properties(void)
+{
+    strlist_t  list[1] = { STRLIST_INITIALIZER };
+
+    /* Record properties in the string list */
+    (void)property_list(record_prop, list);
+
+    /* Sort everything */
+    strlist_sort(list);
+
+    /* print everything */
+    STRLIST_FOREACH(list, str, printf("%s\n", str));
+
+    /* voila */
+    strlist_done(list);
 }
 
 int __system_property_wait(prop_info *pi);
@@ -17,7 +38,7 @@
     int n = 0;
 
     if (argc == 1) {
-        (void)property_list(proplist, NULL);
+        list_properties();
     } else {
         char value[PROPERTY_VALUE_MAX];
         char *default_value;
diff --git a/toolbox/ls.c b/toolbox/ls.c
index daa8095..b08e378 100644
--- a/toolbox/ls.c
+++ b/toolbox/ls.c
@@ -15,128 +15,7 @@
 #include <linux/kdev_t.h>
 #include <limits.h>
 
-// dynamic arrays
-typedef struct {
-    int count;
-    int capacity;
-    void** items;
-} dynarray_t;
-
-#define DYNARRAY_INITIALIZER  { 0, 0, NULL }
-
-static void dynarray_init( dynarray_t *a )
-{
-    a->count = a->capacity = 0;
-    a->items = NULL;
-}
-
-static void dynarray_reserve_more( dynarray_t *a, int count )
-{
-    int old_cap = a->capacity;
-    int new_cap = old_cap;
-    const int max_cap = INT_MAX/sizeof(void*);
-    void** new_items;
-    int new_count = a->count + count;
-
-    if (count <= 0)
-        return;
-
-    if (count > max_cap - a->count)
-        abort();
-
-    new_count = a->count + count;
-
-    while (new_cap < new_count) {
-        old_cap = new_cap;
-        new_cap += (new_cap >> 2) + 4;
-        if (new_cap < old_cap || new_cap > max_cap) {
-            new_cap = max_cap;
-        }
-    }
-    new_items = realloc(a->items, new_cap*sizeof(void*));
-    if (new_items == NULL)
-        abort();
-
-    a->items = new_items;
-    a->capacity = new_cap;
-}
-
-static void dynarray_append( dynarray_t *a, void* item )
-{
-    if (a->count >= a->capacity)
-        dynarray_reserve_more(a, 1);
-
-    a->items[a->count++] = item;
-}
-
-static void dynarray_done( dynarray_t *a )
-{
-    free(a->items);
-    a->items = NULL;
-    a->count = a->capacity = 0;
-}
-
-#define DYNARRAY_FOREACH_TYPE(_array,_item_type,_item,_stmnt) \
-    do { \
-        int _nn_##__LINE__ = 0; \
-        for (;_nn_##__LINE__ < (_array)->count; ++ _nn_##__LINE__) { \
-            _item_type _item = (_item_type)(_array)->items[_nn_##__LINE__]; \
-            _stmnt; \
-        } \
-    } while (0)
-
-#define DYNARRAY_FOREACH(_array,_item,_stmnt) \
-    DYNARRAY_FOREACH_TYPE(_array,void *,_item,_stmnt)
-
-// string arrays
-
-typedef dynarray_t  strlist_t;
-
-#define  STRLIST_INITIALIZER  DYNARRAY_INITIALIZER
-
-#define  STRLIST_FOREACH(_list,_string,_stmnt) \
-    DYNARRAY_FOREACH_TYPE(_list,char *,_string,_stmnt)
-
-static void strlist_init( strlist_t *list )
-{
-    dynarray_init(list);
-}
-
-static void strlist_append_b( strlist_t *list, const void* str, size_t  slen )
-{
-    char *copy = malloc(slen+1);
-    memcpy(copy, str, slen);
-    copy[slen] = '\0';
-    dynarray_append(list, copy);
-}
-
-static void strlist_append_dup( strlist_t *list, const char *str)
-{
-    strlist_append_b(list, str, strlen(str));
-}
-
-static void strlist_done( strlist_t *list )
-{
-    STRLIST_FOREACH(list, string, free(string));
-    dynarray_done(list);
-}
-
-static int strlist_compare_strings(const void* a, const void* b)
-{
-    const char *sa = *(const char **)a;
-    const char *sb = *(const char **)b;
-    return strcmp(sa, sb);
-}
-
-static void strlist_sort( strlist_t *list )
-{
-    if (list->count > 0) {
-        qsort(list->items, 
-              (size_t)list->count,
-              sizeof(void*),
-              strlist_compare_strings);
-    }
-}
+#include "dynarray.h"
 
 // bits for flags argument
 #define LIST_LONG           (1 << 0)
@@ -166,7 +45,7 @@
 static void mode2str(unsigned mode, char *out)
 {
     *out++ = mode2kind(mode);
-    
+
     *out++ = (mode & 0400) ? 'r' : '-';
     *out++ = (mode & 0200) ? 'w' : '-';
     if(mode & 04000) {
@@ -290,7 +169,7 @@
 
     strftime(date, 32, "%Y-%m-%d %H:%M", localtime((const time_t*)&s.st_mtime));
     date[31] = 0;
-    
+
 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890
 // MMMMMMMM UUUUUUUU GGGGGGGGG XXXXXXXX YYYY-MM-DD HH:MM NAME (->LINK)
 
@@ -298,7 +177,7 @@
     case S_IFBLK:
     case S_IFCHR:
         printf("%s %-8s %-8s %3d, %3d %s %s\n",
-               mode, user, group, 
+               mode, user, group,
                (int) MAJOR(s.st_rdev), (int) MINOR(s.st_rdev),
                date, name);
         break;
@@ -312,7 +191,7 @@
 
         len = readlink(path, linkto, 256);
         if(len < 0) return -1;
-        
+
         if(len > 255) {
             linkto[252] = '.';
             linkto[253] = '.';
@@ -321,7 +200,7 @@
         } else {
             linkto[len] = 0;
         }
-        
+
         printf("%s %-8s %-8s          %s %s -> %s\n",
                mode, user, group, date, name, linkto);
         break;
@@ -364,7 +243,7 @@
     DIR *d;
     struct dirent *de;
     strlist_t  files = STRLIST_INITIALIZER;
-    
+
     d = opendir(name);
     if(d == 0) {
         fprintf(stderr, "opendir failed, %s\n", strerror(errno));
@@ -469,7 +348,7 @@
 {
     int flags = 0;
     int listed = 0;
-    
+
     if(argc > 1) {
         int i;
         int err = 0;
@@ -509,7 +388,7 @@
             return err;
         }
     }
-    
-    // list working directory if no files or directories were specified    
+
+    // list working directory if no files or directories were specified
     return listpath(".", flags);
 }
diff --git a/toolbox/lsof.c b/toolbox/lsof.c
index 99891db..c55384b 100644
--- a/toolbox/lsof.c
+++ b/toolbox/lsof.c
@@ -196,28 +196,37 @@
 
 int lsof_main(int argc, char *argv[])
 {
-    DIR *dir = opendir("/proc");
-    if (dir == NULL) {
-        fprintf(stderr, "Couldn't open /proc\n");
-        return -1;
+    long int pid = 0;
+    char* endptr;
+    if (argc == 2) {
+        pid = strtol(argv[1], &endptr, 10);
     }
 
     print_header();
 
-    struct dirent* de;
-    while ((de = readdir(dir))) {
-        if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
-            continue;
-
-        // Only inspect directories that are PID numbers
-        char* endptr;
-        long int pid = strtol(de->d_name, &endptr, 10);
-        if (*endptr != '\0')
-            continue;
-
+    if (pid) {
         lsof_dumpinfo(pid);
+    } else {
+        DIR *dir = opendir("/proc");
+        if (dir == NULL) {
+            fprintf(stderr, "Couldn't open /proc\n");
+            return -1;
+        }
+
+        struct dirent* de;
+        while ((de = readdir(dir))) {
+            if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+                continue;
+
+            // Only inspect directories that are PID numbers
+                pid = strtol(de->d_name, &endptr, 10);
+            if (*endptr != '\0')
+                continue;
+
+            lsof_dumpinfo(pid);
+        }
+        closedir(dir);
     }
-    closedir(dir);
 
     return 0;
 }
diff --git a/toolbox/reboot.c b/toolbox/reboot.c
index aebe185..f8546de 100644
--- a/toolbox/reboot.c
+++ b/toolbox/reboot.c
@@ -1,7 +1,7 @@
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <sys/reboot.h>
+#include <cutils/android_reboot.h>
 #include <unistd.h>
 
 int reboot_main(int argc, char *argv[])
@@ -9,6 +9,7 @@
     int ret;
     int nosync = 0;
     int poweroff = 0;
+    int flags = 0;
 
     opterr = 0;
     do {
@@ -38,15 +39,16 @@
         exit(EXIT_FAILURE);
     }
 
-    if(!nosync)
-        sync();
+    if(nosync)
+        /* also set NO_REMOUNT_RO as remount ro includes an implicit sync */
+        flags = ANDROID_RB_FLAG_NO_SYNC | ANDROID_RB_FLAG_NO_REMOUNT_RO;
 
     if(poweroff)
-        ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_POWER_OFF, NULL);
+        ret = android_reboot(ANDROID_RB_POWEROFF, flags, 0);
     else if(argc > optind)
-        ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, argv[optind]);
+        ret = android_reboot(ANDROID_RB_RESTART2, flags, argv[optind]);
     else
-        ret = reboot(RB_AUTOBOOT);
+        ret = android_reboot(ANDROID_RB_RESTART, flags, 0);
     if(ret < 0) {
         perror("reboot");
         exit(EXIT_FAILURE);
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);
+}
+
diff --git a/toolbox/wipe.c b/toolbox/wipe.c
index 7e263fd..650a0d6 100644
--- a/toolbox/wipe.c
+++ b/toolbox/wipe.c
@@ -5,7 +5,7 @@
 #include <string.h>
 #include <errno.h>
 #include <sys/types.h>
-#include <sys/reboot.h>
+#include <cutils/android_reboot.h>
 #include <sys/stat.h>
 
 #ifndef PATH_MAX
@@ -63,7 +63,7 @@
 		wipe ("/system");
         wipe ("/data");
 		fprintf(stdout, "Device nuked! Rebooting...\n");
-		ret = reboot(RB_AUTOBOOT);
+		ret = android_reboot(ANDROID_RB_RESTART, 0, 0);
 	    if (ret < 0) {
 	        fprintf(stderr, "Reboot failed, %s\n", strerror(errno));
 	        return 1;