Merge "init: Fix get_hardware_name() to cope with long /proc/cpuinfo output"
diff --git a/adb/Android.mk b/adb/Android.mk
index bc8315e..a803978 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -16,7 +16,8 @@
 ifeq ($(HOST_OS),linux)
   USB_SRCS := usb_linux.c
   EXTRA_SRCS := get_my_path_linux.c
-  LOCAL_LDLIBS += -lrt -lncurses -lpthread
+  LOCAL_LDLIBS += -lrt -ldl -lpthread
+  LOCAL_CFLAGS += -DWORKAROUND_BUG6558362
 endif
 
 ifeq ($(HOST_OS),darwin)
@@ -77,6 +78,7 @@
 LOCAL_CFLAGS += -O2 -g -DADB_HOST=1  -Wall -Wno-unused-parameter
 LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
 LOCAL_MODULE := adb
+LOCAL_MODULE_TAGS := debug
 
 LOCAL_STATIC_LIBRARIES := libzipfile libunz libcrypto_static $(EXTRA_STATIC_LIBS)
 ifeq ($(USE_SYSDEPS_WIN32),)
@@ -139,7 +141,7 @@
 ifneq ($(SDK_ONLY),true)
 include $(CLEAR_VARS)
 
-LOCAL_LDLIBS := -lrt -lncurses -lpthread
+LOCAL_LDLIBS := -lrt -ldl -lpthread
 
 LOCAL_SRC_FILES := \
 	adb.c \
diff --git a/adb/SERVICES.TXT b/adb/SERVICES.TXT
index d9aa09c..b53bc44 100644
--- a/adb/SERVICES.TXT
+++ b/adb/SERVICES.TXT
@@ -117,7 +117,34 @@
 
     or even any one of the local services described below.
 
+<host-prefix>:forward:norebind:<local>;<remote>
+    Same as <host-prefix>:forward:<local>;<remote> except that it will
+    fail it there is already a forward connection from <local>.
 
+    Used to implement 'adb forward --no-rebind <local> <remote>'
+
+<host-prefix>:killforward:<local>
+    Remove any existing forward local connection from <local>.
+    This is used to implement 'adb forward --remove <local>'
+
+<host-prefix>:killforward-all
+    Remove all forward network connections.
+    This is used to implement 'adb forward --remove-all'.
+
+<host-prefix>:list-forward
+    List all existing forward connections from this server.
+    This returns something that looks like the following:
+
+       <hex4>: The length of the payload, as 4 hexadecimal chars.
+       <payload>: A series of lines of the following format:
+
+         <serial> " " <local> " " <remote> "\n"
+
+    Where <serial> is a device serial number.
+          <local>  is the host-specific endpoint (e.g. tcp:9000).
+          <remote> is the device-specific endpoint.
+
+    Used to implement 'adb forward --list'.
 
 LOCAL SERVICES:
 
diff --git a/adb/adb.c b/adb/adb.c
index 07bfbe5..ec74b49 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -25,6 +25,7 @@
 #include <string.h>
 #include <time.h>
 #include <sys/time.h>
+#include <stdint.h>
 
 #include "sysdeps.h"
 #include "adb.h"
@@ -34,7 +35,7 @@
 
 #if !ADB_HOST
 #include <private/android_filesystem_config.h>
-#include <linux/capability.h>
+#include <sys/capability.h>
 #include <linux/prctl.h>
 #include <sys/mount.h>
 #else
@@ -46,6 +47,7 @@
 #endif
 
 int HOST = 0;
+int gListenAll = 0;
 
 static int auth_enabled = 0;
 
@@ -324,7 +326,7 @@
     send_packet(cp, t);
 }
 
-static void send_auth_request(atransport *t)
+void send_auth_request(atransport *t)
 {
     D("Calling send_auth_request\n");
     apacket *p;
@@ -399,8 +401,14 @@
         return "bootloader";
     case CS_DEVICE:
         return "device";
+    case CS_RECOVERY:
+        return "recovery";
+    case CS_SIDELOAD:
+        return "sideload";
     case CS_OFFLINE:
         return "offline";
+    case CS_UNAUTHORIZED:
+        return "unauthorized";
     default:
         return "unknown";
     }
@@ -530,6 +538,7 @@
 
     case A_AUTH:
         if (p->msg.arg0 == ADB_AUTH_TOKEN) {
+            t->connection_state = CS_UNAUTHORIZED;
             t->key = adb_auth_nextkey(t->key);
             if (t->key) {
                 send_auth_response(p->data, p->msg.data_length, t);
@@ -701,7 +710,13 @@
     if(!strncmp("tcp:", name, 4)){
         int  ret;
         port = atoi(name + 4);
-        ret = socket_loopback_server(port, SOCK_STREAM);
+
+        if (gListenAll > 0) {
+            ret = socket_inaddr_any_server(port, SOCK_STREAM);
+        } else {
+            ret = socket_loopback_server(port, SOCK_STREAM);
+        }
+
         return ret;
     }
 #ifndef HAVE_WIN32_IPC  /* no Unix-domain sockets on Win32 */
@@ -722,24 +737,90 @@
     return -1;
 }
 
-static int remove_listener(const char *local_name, const char *connect_to, atransport* transport)
+// Write a single line describing a listener to a user-provided buffer.
+// Appends a trailing zero, even in case of truncation, but the function
+// returns the full line length.
+// If |buffer| is NULL, does not write but returns required size.
+static int format_listener(alistener* l, char* buffer, size_t buffer_len) {
+    // Format is simply:
+    //
+    //  <device-serial> " " <local-name> " " <remote-name> "\n"
+    //
+    int local_len = strlen(l->local_name);
+    int connect_len = strlen(l->connect_to);
+    int serial_len = strlen(l->transport->serial);
+
+    if (buffer != NULL) {
+        snprintf(buffer, buffer_len, "%s %s %s\n",
+                l->transport->serial, l->local_name, l->connect_to);
+    }
+    // NOTE: snprintf() on Windows returns -1 in case of truncation, so
+    // return the computed line length instead.
+    return local_len + connect_len + serial_len + 3;
+}
+
+// Write the list of current listeners (network redirections) into a
+// user-provided buffer. Appends a trailing zero, even in case of
+// trunctaion, but return the full size in bytes.
+// If |buffer| is NULL, does not write but returns required size.
+static int format_listeners(char* buf, size_t buflen)
+{
+    alistener* l;
+    int result = 0;
+    for (l = listener_list.next; l != &listener_list; l = l->next) {
+        // Ignore special listeners like those for *smartsocket*
+        if (l->connect_to[0] == '*')
+          continue;
+        int len = format_listener(l, buf, buflen);
+        // Ensure there is space for the trailing zero.
+        result += len;
+        if (buf != NULL) {
+          buf += len;
+          buflen -= len;
+          if (buflen <= 0)
+              break;
+        }
+    }
+    return result;
+}
+
+static int remove_listener(const char *local_name, atransport* transport)
 {
     alistener *l;
 
     for (l = listener_list.next; l != &listener_list; l = l->next) {
-        if (!strcmp(local_name, l->local_name) &&
-            !strcmp(connect_to, l->connect_to) &&
-            l->transport && l->transport == transport) {
-
-            listener_disconnect(l, transport);
+        if (!strcmp(local_name, l->local_name)) {
+            listener_disconnect(l, l->transport);
             return 0;
         }
     }
-
     return -1;
 }
 
-static int install_listener(const char *local_name, const char *connect_to, atransport* transport)
+static void remove_all_listeners(void)
+{
+    alistener *l, *l_next;
+    for (l = listener_list.next; l != &listener_list; l = l_next) {
+        l_next = l->next;
+        // Never remove smart sockets.
+        if (l->connect_to[0] == '*')
+            continue;
+        listener_disconnect(l, l->transport);
+    }
+}
+
+// error/status codes for install_listener.
+typedef enum {
+  INSTALL_STATUS_OK = 0,
+  INSTALL_STATUS_INTERNAL_ERROR = -1,
+  INSTALL_STATUS_CANNOT_BIND = -2,
+  INSTALL_STATUS_CANNOT_REBIND = -3,
+} install_status_t;
+
+static install_status_t install_listener(const char *local_name,
+                                         const char *connect_to,
+                                         atransport* transport,
+                                         int no_rebind)
 {
     alistener *l;
 
@@ -751,12 +832,17 @@
 
                 /* can't repurpose a smartsocket */
             if(l->connect_to[0] == '*') {
-                return -1;
+                return INSTALL_STATUS_INTERNAL_ERROR;
+            }
+
+                /* can't repurpose a listener if 'no_rebind' is true */
+            if (no_rebind) {
+                return INSTALL_STATUS_CANNOT_REBIND;
             }
 
             cto = strdup(connect_to);
             if(cto == 0) {
-                return -1;
+                return INSTALL_STATUS_INTERNAL_ERROR;
             }
 
             //printf("rebinding '%s' to '%s'\n", local_name, connect_to);
@@ -767,7 +853,7 @@
                 l->transport = transport;
                 add_transport_disconnect(l->transport, &l->disconnect);
             }
-            return 0;
+            return INSTALL_STATUS_OK;
         }
     }
 
@@ -804,11 +890,11 @@
         l->disconnect.func   = listener_disconnect;
         add_transport_disconnect(transport, &l->disconnect);
     }
-    return 0;
+    return INSTALL_STATUS_OK;
 
 nomem:
     fatal("cannot allocate listener");
-    return 0;
+    return INSTALL_STATUS_INTERNAL_ERROR;
 }
 
 #ifdef HAVE_WIN32_PROC
@@ -905,6 +991,33 @@
 #endif
 
 #if ADB_HOST
+
+#ifdef WORKAROUND_BUG6558362
+#include <sched.h>
+#define AFFINITY_ENVVAR "ADB_CPU_AFFINITY_BUG6558362"
+void adb_set_affinity(void)
+{
+   cpu_set_t cpu_set;
+   const char* cpunum_str = getenv(AFFINITY_ENVVAR);
+   char* strtol_res;
+   int cpu_num;
+
+   if (!cpunum_str || !*cpunum_str)
+       return;
+   cpu_num = strtol(cpunum_str, &strtol_res, 0);
+   if (*strtol_res != '\0')
+     fatal("bad number (%s) in env var %s. Expecting 0..n.\n", cpunum_str, AFFINITY_ENVVAR);
+
+   sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
+   D("orig cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
+   CPU_ZERO(&cpu_set);
+   CPU_SET(cpu_num, &cpu_set);
+   sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
+   sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
+   D("new cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
+}
+#endif
+
 int launch_server(int server_port)
 {
 #ifdef HAVE_WIN32_PROC
@@ -913,6 +1026,7 @@
     /* message since the pipe handles must be inheritable, we use a     */
     /* security attribute                                               */
     HANDLE                pipe_read, pipe_write;
+    HANDLE                stdout_handle, stderr_handle;
     SECURITY_ATTRIBUTES   sa;
     STARTUPINFO           startup;
     PROCESS_INFORMATION   pinfo;
@@ -932,6 +1046,26 @@
 
     SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );
 
+    /* Some programs want to launch an adb command and collect its output by
+     * calling CreateProcess with inheritable stdout/stderr handles, then
+     * using read() to get its output. When this happens, the stdout/stderr
+     * handles passed to the adb client process will also be inheritable.
+     * When starting the adb server here, care must be taken to reset them
+     * to non-inheritable.
+     * Otherwise, something bad happens: even if the adb command completes,
+     * the calling process is stuck while read()-ing from the stdout/stderr
+     * descriptors, because they're connected to corresponding handles in the
+     * adb server process (even if the latter never uses/writes to them).
+     */
+    stdout_handle = GetStdHandle( STD_OUTPUT_HANDLE );
+    stderr_handle = GetStdHandle( STD_ERROR_HANDLE );
+    if (stdout_handle != INVALID_HANDLE_VALUE) {
+        SetHandleInformation( stdout_handle, HANDLE_FLAG_INHERIT, 0 );
+    }
+    if (stderr_handle != INVALID_HANDLE_VALUE) {
+        SetHandleInformation( stderr_handle, HANDLE_FLAG_INHERIT, 0 );
+    }
+
     ZeroMemory( &startup, sizeof(startup) );
     startup.cb = sizeof(startup);
     startup.hStdInput  = GetStdHandle( STD_INPUT_HANDLE );
@@ -1008,8 +1142,10 @@
         dup2(fd[1], STDERR_FILENO);
         adb_close(fd[1]);
 
+        char str_port[30];
+        snprintf(str_port, sizeof(str_port), "%d",  server_port);
         // child process
-        int result = execl(path, "adb", "fork-server", "server", NULL);
+        int result = execl(path, "adb", "-P", str_port, "fork-server", "server", NULL);
         // this should not return
         fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
     } else  {
@@ -1052,6 +1188,32 @@
 }
 
 #if !ADB_HOST
+
+static void drop_capabilities_bounding_set_if_needed() {
+#ifdef ALLOW_ADBD_ROOT
+    char value[PROPERTY_VALUE_MAX];
+    property_get("ro.debuggable", value, "");
+    if (strcmp(value, "1") == 0) {
+        return;
+    }
+#endif
+    int i;
+    for (i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
+        if ((i == CAP_SETUID) || (i == CAP_SETGID)) {
+            // CAP_SETUID CAP_SETGID needed by /system/bin/run-as
+            continue;
+        }
+        int err = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
+
+        // Some kernels don't have file capabilities compiled in, and
+        // prctl(PR_CAPBSET_DROP) returns EINVAL. Don't automatically
+        // die when we see such misconfigured kernels.
+        if ((err < 0) && (errno != EINVAL)) {
+            exit(1);
+        }
+    }
+}
+
 static int should_drop_privileges() {
 #ifndef ALLOW_ADBD_ROOT
     return 1;
@@ -1106,6 +1268,10 @@
 
 #if ADB_HOST
     HOST = 1;
+
+#ifdef WORKAROUND_BUG6558362
+    if(is_daemon) adb_set_affinity();
+#endif
     usb_vendors_init();
     usb_init();
     local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
@@ -1113,7 +1279,7 @@
 
     char local_name[30];
     build_local_name(local_name, sizeof(local_name), server_port);
-    if(install_listener(local_name, "*smartsocket*", NULL)) {
+    if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
         exit(1);
     }
 #else
@@ -1136,12 +1302,14 @@
     /* don't run as root if we are running in secure mode */
     if (should_drop_privileges()) {
         struct __user_cap_header_struct header;
-        struct __user_cap_data_struct cap;
+        struct __user_cap_data_struct cap[2];
 
         if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
             exit(1);
         }
 
+        drop_capabilities_bounding_set_if_needed();
+
         /* add extra groups:
         ** AID_ADB to access the USB driver
         ** AID_LOG to read system logs (adb logcat)
@@ -1169,18 +1337,21 @@
             exit(1);
         }
 
+        memset(&header, 0, sizeof(header));
+        memset(cap, 0, sizeof(cap));
+
         /* set CAP_SYS_BOOT capability, so "adb reboot" will succeed */
-        header.version = _LINUX_CAPABILITY_VERSION;
+        header.version = _LINUX_CAPABILITY_VERSION_3;
         header.pid = 0;
-        cap.effective = cap.permitted = (1 << CAP_SYS_BOOT);
-        cap.inheritable = 0;
-        capset(&header, &cap);
+        cap[CAP_TO_INDEX(CAP_SYS_BOOT)].effective |= CAP_TO_MASK(CAP_SYS_BOOT);
+        cap[CAP_TO_INDEX(CAP_SYS_BOOT)].permitted |= CAP_TO_MASK(CAP_SYS_BOOT);
+        capset(&header, cap);
 
         D("Local port disabled\n");
     } else {
         char local_name[30];
         build_local_name(local_name, sizeof(local_name), server_port);
-        if(install_listener(local_name, "*smartsocket*", NULL)) {
+        if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
             exit(1);
         }
     }
@@ -1474,24 +1645,63 @@
     }
 #endif // ADB_HOST
 
-    if(!strncmp(service,"forward:",8) || !strncmp(service,"killforward:",12)) {
+    if(!strcmp(service,"list-forward")) {
+        // Create the list of forward redirections.
+        char header[9];
+        int buffer_size = format_listeners(NULL, 0);
+        // Add one byte for the trailing zero.
+        char* buffer = malloc(buffer_size+1);
+        (void) format_listeners(buffer, buffer_size+1);
+        snprintf(header, sizeof header, "OKAY%04x", buffer_size);
+        writex(reply_fd, header, 8);
+        writex(reply_fd, buffer, buffer_size);
+        free(buffer);
+        return 0;
+    }
+
+    if (!strcmp(service,"killforward-all")) {
+        remove_all_listeners();
+        adb_write(reply_fd, "OKAYOKAY", 8);
+        return 0;
+    }
+
+    if(!strncmp(service,"forward:",8) ||
+       !strncmp(service,"killforward:",12)) {
         char *local, *remote, *err;
         int r;
         atransport *transport;
 
         int createForward = strncmp(service,"kill",4);
+        int no_rebind = 0;
 
-        local = service + (createForward ? 8 : 12);
-        remote = strchr(local,';');
-        if(remote == 0) {
-            sendfailmsg(reply_fd, "malformed forward spec");
-            return 0;
+        local = strchr(service, ':') + 1;
+
+        // Handle forward:norebind:<local>... here
+        if (createForward && !strncmp(local, "norebind:", 9)) {
+            no_rebind = 1;
+            local = strchr(local, ':') + 1;
         }
 
-        *remote++ = 0;
-        if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){
-            sendfailmsg(reply_fd, "malformed forward spec");
-            return 0;
+        remote = strchr(local,';');
+
+        if (createForward) {
+            // Check forward: parameter format: '<local>;<remote>'
+            if(remote == 0) {
+                sendfailmsg(reply_fd, "malformed forward spec");
+                return 0;
+            }
+
+            *remote++ = 0;
+            if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){
+                sendfailmsg(reply_fd, "malformed forward spec");
+                return 0;
+            }
+        } else {
+            // Check killforward: parameter format: '<local>'
+            if (local[0] == 0) {
+                sendfailmsg(reply_fd, "malformed forward spec");
+                return 0;
+            }
         }
 
         transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
@@ -1501,9 +1711,9 @@
         }
 
         if (createForward) {
-            r = install_listener(local, remote, transport);
+            r = install_listener(local, remote, transport, no_rebind);
         } else {
-            r = remove_listener(local, remote, transport);
+            r = remove_listener(local, transport);
         }
         if(r == 0) {
                 /* 1st OKAY is connect, 2nd OKAY is status */
@@ -1512,7 +1722,18 @@
         }
 
         if (createForward) {
-            sendfailmsg(reply_fd, (r == -1) ? "cannot rebind smartsocket" : "cannot bind socket");
+            const char* message;
+            switch (r) {
+              case INSTALL_STATUS_CANNOT_BIND:
+                message = "cannot bind to socket";
+                break;
+              case INSTALL_STATUS_CANNOT_REBIND:
+                message = "cannot rebind existing socket";
+                break;
+              default:
+                message = "internal error";
+            }
+            sendfailmsg(reply_fd, message);
         } else {
             sendfailmsg(reply_fd, "cannot remove listener");
         }
diff --git a/adb/adb.h b/adb/adb.h
index 9da8af8..a01d460 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -468,6 +468,7 @@
 #define CS_RECOVERY   4
 #define CS_NOPERM     5 /* Insufficient permissions to communicate with the device */
 #define CS_SIDELOAD   6
+#define CS_UNAUTHORIZED 7
 
 extern int HOST;
 extern int SHELL_EXIT_NOTIFY_FD;
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index 1fffa49..b24c674 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -20,6 +20,8 @@
 void adb_auth_init(void);
 void adb_auth_verified(atransport *t);
 
+void send_auth_request(atransport *t);
+
 /* AUTH packets first argument */
 /* Request */
 #define ADB_AUTH_TOKEN         1
@@ -36,7 +38,6 @@
 static inline int adb_auth_generate_token(void *token, size_t token_size) { return 0; }
 static inline int adb_auth_verify(void *token, void *sig, int siglen) { return 0; }
 static inline void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t) { }
-static inline void adb_auth_reload_keys(void) { }
 
 #else // !ADB_HOST
 
@@ -47,7 +48,6 @@
 int adb_auth_generate_token(void *token, size_t token_size);
 int adb_auth_verify(void *token, void *sig, int siglen);
 void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t);
-void adb_auth_reload_keys(void);
 
 #endif // ADB_HOST
 
diff --git a/adb/adb_auth_client.c b/adb/adb_auth_client.c
index 0b4913e..763b448 100644
--- a/adb/adb_auth_client.c
+++ b/adb/adb_auth_client.c
@@ -34,8 +34,6 @@
     RSAPublicKey key;
 };
 
-static struct listnode key_list;
-
 static char *key_paths[] = {
     "/adb_keys",
     "/data/misc/adb/adb_keys",
@@ -45,6 +43,10 @@
 static fdevent listener_fde;
 static int framework_fd = -1;
 
+static void usb_disconnected(void* unused, atransport* t);
+static struct adisconnect usb_disconnect = { usb_disconnected, 0, 0, 0 };
+static atransport* usb_transport;
+static bool needs_retry = false;
 
 static void read_keys(const char *file, struct listnode *list)
 {
@@ -102,18 +104,18 @@
     }
 }
 
-void adb_auth_reload_keys(void)
+static void load_keys(struct listnode *list)
 {
     char *path;
     char **paths = key_paths;
     struct stat buf;
 
-    free_keys(&key_list);
+    list_init(list);
 
     while ((path = *paths++)) {
         if (!stat(path, &buf)) {
             D("Loading keys from '%s'\n", path);
-            read_keys(path, &key_list);
+            read_keys(path, list);
         }
     }
 }
@@ -137,37 +139,50 @@
 {
     struct listnode *item;
     struct adb_public_key *key;
-    int ret;
+    struct listnode key_list;
+    int ret = 0;
 
     if (siglen != RSANUMBYTES)
         return 0;
 
+    load_keys(&key_list);
+
     list_for_each(item, &key_list) {
         key = node_to_item(item, struct adb_public_key, node);
         ret = RSA_verify(&key->key, sig, siglen, token);
         if (ret)
-            return 1;
+            break;
     }
 
-    return 0;
+    free_keys(&key_list);
+
+    return ret;
+}
+
+static void usb_disconnected(void* unused, atransport* t)
+{
+    D("USB disconnect\n");
+    remove_transport_disconnect(usb_transport, &usb_disconnect);
+    usb_transport = NULL;
+    needs_retry = false;
 }
 
 static void adb_auth_event(int fd, unsigned events, void *data)
 {
-    atransport *t = data;
     char response[2];
     int ret;
 
     if (events & FDE_READ) {
         ret = unix_read(fd, response, sizeof(response));
         if (ret < 0) {
-            D("Disconnect");
-            fdevent_remove(&t->auth_fde);
+            D("Framework disconnect\n");
+            if (usb_transport)
+                fdevent_remove(&usb_transport->auth_fde);
             framework_fd = -1;
         }
         else if (ret == 2 && response[0] == 'O' && response[1] == 'K') {
-            adb_auth_reload_keys();
-            adb_auth_verified(t);
+            if (usb_transport)
+                adb_auth_verified(usb_transport);
         }
     }
 }
@@ -177,8 +192,14 @@
     char msg[MAX_PAYLOAD];
     int ret;
 
+    if (!usb_transport) {
+        usb_transport = t;
+        add_transport_disconnect(t, &usb_disconnect);
+    }
+
     if (framework_fd < 0) {
         D("Client not connected\n");
+        needs_retry = true;
         return;
     }
 
@@ -219,15 +240,17 @@
     }
 
     framework_fd = s;
+
+    if (needs_retry) {
+        needs_retry = false;
+        send_auth_request(usb_transport);
+    }
 }
 
 void adb_auth_init(void)
 {
     int fd, ret;
 
-    list_init(&key_list);
-    adb_auth_reload_keys();
-
     fd = android_get_control_socket("adbd");
     if (fd < 0) {
         D("Failed to get adbd socket\n");
diff --git a/adb/adb_client.c b/adb/adb_client.c
index 9a812f0..8340738 100644
--- a/adb/adb_client.c
+++ b/adb/adb_client.c
@@ -17,6 +17,7 @@
 static const char* __adb_serial = NULL;
 
 static int __adb_server_port = DEFAULT_ADB_PORT;
+static const char* __adb_server_name = NULL;
 
 void adb_set_transport(transport_type type, const char* serial)
 {
@@ -29,6 +30,11 @@
     __adb_server_port = server_port;
 }
 
+void adb_set_tcp_name(const char* hostname)
+{
+    __adb_server_name = hostname;
+}
+
 int  adb_get_emulator_console_port(void)
 {
     const char*   serial = __adb_serial;
@@ -181,7 +187,11 @@
     }
     snprintf(tmp, sizeof tmp, "%04x", len);
 
-    fd = socket_loopback_client(__adb_server_port, SOCK_STREAM);
+    if (__adb_server_name)
+        fd = socket_network_client(__adb_server_name, __adb_server_port, SOCK_STREAM);
+    else
+        fd = socket_loopback_client(__adb_server_port, SOCK_STREAM);
+
     if(fd < 0) {
         strcpy(__adb_error, "cannot connect to daemon");
         return -2;
@@ -212,7 +222,10 @@
     int fd = _adb_connect("host:version");
 
     D("adb_connect: service %s\n", service);
-    if(fd == -2) {
+    if(fd == -2 && __adb_server_name) {
+        fprintf(stderr,"** Cannot start server on remote host\n");
+        return fd;
+    } else if(fd == -2) {
         fprintf(stdout,"* daemon not running. starting it now on port %d *\n",
                 __adb_server_port);
     start_server:
@@ -266,7 +279,7 @@
 
     fd = _adb_connect(service);
     if(fd == -2) {
-        fprintf(stderr,"** daemon still not running");
+        fprintf(stderr,"** daemon still not running\n");
     }
     D("adb_connect: return fd %d\n", fd);
 
diff --git a/adb/adb_client.h b/adb/adb_client.h
index 40ab189..0ec47ca 100644
--- a/adb/adb_client.h
+++ b/adb/adb_client.h
@@ -29,6 +29,10 @@
 */
 void adb_set_tcp_specifics(int server_port);
 
+/* Set TCP Hostname of the transport to use
+*/
+void adb_set_tcp_name(const char* hostname);
+
 /* Return the console port of the currently connected emulator (if any)
  * of -1 if there is no emulator, and -2 if there is more than one.
  * assumes adb_set_transport() was alled previously...
diff --git a/adb/commandline.c b/adb/commandline.c
index 24cbb5a..27a1754 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -46,6 +46,7 @@
 int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
 
 static const char *gProductOutPath = NULL;
+extern int gListenAll;
 
 static char *product_file(const char *extra)
 {
@@ -80,6 +81,7 @@
 
     fprintf(stderr,
         "\n"
+        " -a                            - directs adb to listen on all interfaces for a connection\n"
         " -d                            - directs command to the only connected USB device\n"
         "                                 returns an error if more than one USB device is present.\n"
         " -e                            - directs command to the only running emulator.\n"
@@ -93,6 +95,8 @@
         "                                 If -p is not specified, the ANDROID_PRODUCT_OUT\n"
         "                                 environment variable is used, which must\n"
         "                                 be an absolute path.\n"
+        " -H                            - Name of adb server host (default: localhost)\n"
+        " -P                            - Port of adb server (default: 5037)\n"
         " devices [-l]                  - list all connected devices\n"
         "                                 ('-l' will also list device qualifiers)\n"
         " connect <host>[:<port>]       - connect to a device via TCP/IP\n"
@@ -112,6 +116,9 @@
         "  adb shell <command>          - run remote shell command\n"
         "  adb emu <command>            - run emulator console command\n"
         "  adb logcat [ <filter-spec> ] - View device log\n"
+        "  adb forward --list           - list all forward socket connections.\n"
+        "                                 the format is a list of lines with the following format:\n"
+        "                                    <serial> \" \" <local> \" \" <remote> \"\\n\"\n"
         "  adb forward <local> <remote> - forward socket connections\n"
         "                                 forward specs are one of: \n"
         "                                   tcp:<port>\n"
@@ -120,6 +127,11 @@
         "                                   localfilesystem:<unix domain socket name>\n"
         "                                   dev:<character device name>\n"
         "                                   jdwp:<process pid> (remote only)\n"
+        "  adb forward --no-rebind <local> <remote>\n"
+        "                               - same as 'adb forward <local> <remote>' but fails\n"
+        "                                 if <local> is already forwarded\n"
+        "  adb forward --remove <local> - remove a specific forward socket connection\n"
+        "  adb forward --remove-all     - remove all forward socket connections\n"
         "  adb jdwp                     - list PIDs of processes hosting a JDWP transport\n"
         "  adb install [-l] [-r] [-s] [--algo <algorithm name> --key <hex-encoded key> --iv <hex-encoded iv>] <file>\n"
         "                               - push this package file to the device and install it\n"
@@ -132,12 +144,15 @@
         "  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] [-system|-nosystem] [<packages...>]\n"
+        "  adb backup [-f <file>] [-apk|-noapk] [-obb|-noobb] [-shared|-noshared] [-all] [-system|-nosystem] [<packages...>]\n"
         "                               - write an archive of the device's data to <file>.\n"
         "                                 If no -f option is supplied then the data is written\n"
         "                                 to \"backup.ab\" in the current directory.\n"
         "                                 (-apk|-noapk enable/disable backup of the .apks themselves\n"
         "                                    in the archive; the default is noapk.)\n"
+        "                                 (-obb|-noobb enable/disable backup of any installed apk expansion\n"
+        "                                    (aka .obb) files associated with each application; the default\n"
+        "                                    is noobb.)\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"
@@ -371,7 +386,7 @@
     }
 }
 
-int adb_download_buffer(const char *service, const void* data, int sz,
+int adb_download_buffer(const char *service, const char *fn, const void* data, int sz,
                         unsigned progress)
 {
     char buf[4096];
@@ -407,7 +422,7 @@
         sz -= xfer;
         ptr += xfer;
         if(progress) {
-            printf("sending: '%s' %4d%%    \r", service, (int)(100LL - ((100LL * sz) / (total))));
+            printf("sending: '%s' %4d%%    \r", fn, (int)(100LL - ((100LL * sz) / (total))));
             fflush(stdout);
         }
     }
@@ -439,11 +454,11 @@
 
     data = load_file(fn, &sz);
     if(data == 0) {
-        fprintf(stderr,"* cannot read '%s' *\n", service);
+        fprintf(stderr,"* cannot read '%s' *\n", fn);
         return -1;
     }
 
-    int status = adb_download_buffer(service, data, sz, progress);
+    int status = adb_download_buffer(service, fn, data, sz, progress);
     free(data);
     return status;
 }
@@ -938,9 +953,9 @@
     int server_port = DEFAULT_ADB_PORT;
     if (server_port_str && strlen(server_port_str) > 0) {
         server_port = (int) strtol(server_port_str, NULL, 0);
-        if (server_port <= 0) {
+        if (server_port <= 0 || server_port > 65535) {
             fprintf(stderr,
-                    "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number. Got \"%s\"\n",
+                    "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number less than 65535. Got \"%s\"\n",
                     server_port_str);
             return usage();
         }
@@ -986,6 +1001,42 @@
             ttype = kTransportUsb;
         } else if (!strcmp(argv[0],"-e")) {
             ttype = kTransportLocal;
+        } else if (!strcmp(argv[0],"-a")) {
+            gListenAll = 1;
+        } else if(!strncmp(argv[0], "-H", 2)) {
+            const char *hostname = NULL;
+            if (argv[0][2] == '\0') {
+                if (argc < 2) return usage();
+                hostname = argv[1];
+                argc--;
+                argv++;
+            } else {
+                hostname = argv[0] + 2;
+            }
+            adb_set_tcp_name(hostname);
+
+        } else if(!strncmp(argv[0], "-P", 2)) {
+            if (argv[0][2] == '\0') {
+                if (argc < 2) return usage();
+                server_port_str = argv[1];
+                argc--;
+                argv++;
+            } else {
+                server_port_str = argv[0] + 2;
+            }
+            if (strlen(server_port_str) > 0) {
+                server_port = (int) strtol(server_port_str, NULL, 0);
+                if (server_port <= 0 || server_port > 65535) {
+                    fprintf(stderr,
+                            "adb: port number must be a positive number less than 65536. Got \"%s\"\n",
+                            server_port_str);
+                    return usage();
+                }
+            } else {
+                fprintf(stderr,
+                "adb: port number must be a positive number less than 65536. Got empty string.\n");
+                return usage();
+            }
         } else {
                 /* out of recognized modifiers and flags */
             break;
@@ -1223,16 +1274,85 @@
     }
 
     if(!strcmp(argv[0], "forward")) {
-        if(argc != 3) return usage();
-        if (serial) {
-            snprintf(buf, sizeof buf, "host-serial:%s:forward:%s;%s",serial, argv[1], argv[2]);
-        } else if (ttype == kTransportUsb) {
-            snprintf(buf, sizeof buf, "host-usb:forward:%s;%s", argv[1], argv[2]);
-        } else if (ttype == kTransportLocal) {
-            snprintf(buf, sizeof buf, "host-local:forward:%s;%s", argv[1], argv[2]);
-        } else {
-            snprintf(buf, sizeof buf, "host:forward:%s;%s", argv[1], argv[2]);
+        char host_prefix[64];
+        char remove = 0;
+        char remove_all = 0;
+        char list = 0;
+        char no_rebind = 0;
+
+        // Parse options here.
+        while (argc > 1 && argv[1][0] == '-') {
+            if (!strcmp(argv[1], "--list"))
+                list = 1;
+            else if (!strcmp(argv[1], "--remove"))
+                remove = 1;
+            else if (!strcmp(argv[1], "--remove-all"))
+                remove_all = 1;
+            else if (!strcmp(argv[1], "--no-rebind"))
+                no_rebind = 1;
+            else {
+                return usage();
+            }
+            argc--;
+            argv++;
         }
+
+        // Ensure we can only use one option at a time.
+        if (list + remove + remove_all + no_rebind > 1) {
+            return usage();
+        }
+
+        // Determine the <host-prefix> for this command.
+        if (serial) {
+            snprintf(host_prefix, sizeof host_prefix, "host-serial:%s",
+                    serial);
+        } else if (ttype == kTransportUsb) {
+            snprintf(host_prefix, sizeof host_prefix, "host-usb");
+        } else if (ttype == kTransportLocal) {
+            snprintf(host_prefix, sizeof host_prefix, "host-local");
+        } else {
+            snprintf(host_prefix, sizeof host_prefix, "host");
+        }
+
+        // Implement forward --list
+        if (list) {
+            if (argc != 1)
+                return usage();
+            snprintf(buf, sizeof buf, "%s:list-forward", host_prefix);
+            char* forwards = adb_query(buf);
+            if (forwards == NULL) {
+                fprintf(stderr, "error: %s\n", adb_error());
+                return 1;
+            }
+            printf("%s", forwards);
+            free(forwards);
+            return 0;
+        }
+
+        // Implement forward --remove-all
+        else if (remove_all) {
+            if (argc != 1)
+                return usage();
+            snprintf(buf, sizeof buf, "%s:killforward-all", host_prefix);
+        }
+
+        // Implement forward --remove <local>
+        else if (remove) {
+            if (argc != 2)
+                return usage();
+            snprintf(buf, sizeof buf, "%s:killforward:%s", host_prefix, argv[1]);
+        }
+        // Or implement one of:
+        //    forward <local> <remote>
+        //    forward --no-rebind <local> <remote>
+        else
+        {
+          if (argc != 3)
+            return usage();
+          const char* command = no_rebind ? "forward:norebind:" : "forward";
+          snprintf(buf, sizeof buf, "%s:%s:%s;%s", host_prefix, command, argv[1], argv[2]);
+        }
+
         if(adb_command(buf)) {
             fprintf(stderr,"error: %s\n", adb_error());
             return 1;
diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c
index 64e393c..354d0fb 100644
--- a/adb/file_sync_client.c
+++ b/adb/file_sync_client.c
@@ -32,7 +32,7 @@
 #include "file_sync_service.h"
 
 
-static unsigned total_bytes;
+static unsigned long long total_bytes;
 static long long start_time;
 
 static long long NOW()
@@ -58,8 +58,8 @@
         t = 1000000;
 
     fprintf(stderr,"%lld KB/s (%lld bytes in %lld.%03llds)\n",
-            ((((long long) total_bytes) * 1000000LL) / t) / 1024LL,
-            (long long) total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
+            ((total_bytes * 1000000LL) / t) / 1024LL,
+            total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
 }
 
 void sync_quit(int fd)
diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c
index d41c42c..2105b16 100644
--- a/adb/sysdeps_win32.c
+++ b/adb/sysdeps_win32.c
@@ -781,7 +781,7 @@
 void  disable_tcp_nagle(int fd)
 {
     FH   fh = _fh_from_int(fd);
-    int  on;
+    int  on = 1;
 
     if ( !fh || fh->clazz != &_fh_socket_class )
         return;
diff --git a/adb/transport.c b/adb/transport.c
index 9fd6cc2..b4abb66 100644
--- a/adb/transport.c
+++ b/adb/transport.c
@@ -851,6 +851,12 @@
     adb_mutex_unlock(&transport_lock);
 
     if (result) {
+        if (result->connection_state == CS_UNAUTHORIZED) {
+            if (error_out)
+                *error_out = "device unauthorized. Please check the confirmation dialog on your device.";
+            result = NULL;
+        }
+
          /* offline devices are ignored -- they are either being born or dying */
         if (result && result->connection_state == CS_OFFLINE) {
             if (error_out)
@@ -888,6 +894,7 @@
     case CS_RECOVERY: return "recovery";
     case CS_SIDELOAD: return "sideload";
     case CS_NOPERM: return "no permissions";
+    case CS_UNAUTHORIZED: return "unauthorized";
     default: return "unknown";
     }
 }
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index 1c09b84..19b3022 100644
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -131,7 +131,34 @@
 #define VENDOR_ID_KOBO          0x2237
 // Teleepoch's USB Vendor ID
 #define VENDOR_ID_TELEEPOCH     0x2340
-
+// AnyDATA's USB Vendor ID
+#define VENDOR_ID_ANYDATA       0x16D5
+// Harris's USB Vendor ID
+#define VENDOR_ID_HARRIS        0x19A5
+// OPPO's USB Vendor ID
+#define VENDOR_ID_OPPO          0x22D9
+// Xiaomi's USB Vendor ID
+#define VENDOR_ID_XIAOMI        0x2717
+// BYD's USB Vendor ID
+#define VENDOR_ID_BYD           0x19D1
+// OUYA's USB Vendor ID
+#define VENDOR_ID_OUYA          0x2836
+// Haier's USB Vendor ID
+#define VENDOR_ID_HAIER         0x201E
+// Hisense's USB Vendor ID
+#define VENDOR_ID_HISENSE       0x109b
+// MTK's USB Vendor ID
+#define VENDOR_ID_MTK           0x0e8d
+// B&N Nook's USB Vendor ID
+#define VENDOR_ID_NOOK          0x2080
+// Qisda's USB Vendor ID
+#define VENDOR_ID_QISDA         0x1D45
+// ECS's USB Vendor ID
+#define VENDOR_ID_ECS           0x03fc
+// MSI's USB Vendor ID
+#define VENDOR_ID_MSI           0x0DB0
+// Wacom's USB Vendor ID
+#define VENDOR_ID_WACOM         0x0531
 
 /** built-in vendor list */
 int builtInVendorIds[] = {
@@ -183,6 +210,20 @@
     VENDOR_ID_YULONG_COOLPAD,
     VENDOR_ID_KOBO,
     VENDOR_ID_TELEEPOCH,
+    VENDOR_ID_ANYDATA,
+    VENDOR_ID_HARRIS,
+    VENDOR_ID_OPPO,
+    VENDOR_ID_XIAOMI,
+    VENDOR_ID_BYD,
+    VENDOR_ID_OUYA,
+    VENDOR_ID_HAIER,
+    VENDOR_ID_HISENSE,
+    VENDOR_ID_MTK,
+    VENDOR_ID_NOOK,
+    VENDOR_ID_QISDA,
+    VENDOR_ID_ECS,
+    VENDOR_ID_MSI,
+    VENDOR_ID_WACOM,
 };
 
 #define BUILT_IN_VENDOR_COUNT    (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0]))
@@ -235,6 +276,7 @@
                     break;
                 }
             }
+            fclose(f);
         }
     }
 }
diff --git a/charger/Android.mk b/charger/Android.mk
index fe0c91d..b9d3473 100644
--- a/charger/Android.mk
+++ b/charger/Android.mk
@@ -12,6 +12,10 @@
 LOCAL_CFLAGS := -DCHARGER_DISABLE_INIT_BLANK
 endif
 
+ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
+LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND
+endif
+
 LOCAL_MODULE := charger
 LOCAL_MODULE_TAGS := optional
 LOCAL_FORCE_STATIC_EXECUTABLE := true
@@ -21,7 +25,10 @@
 LOCAL_C_INCLUDES := bootable/recovery
 
 LOCAL_STATIC_LIBRARIES := libminui libpixelflinger_static libpng
-LOCAL_STATIC_LIBRARIES += libz libstdc++ libcutils libm libc
+ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
+LOCAL_STATIC_LIBRARIES += libsuspend
+endif
+LOCAL_STATIC_LIBRARIES += libz libstdc++ libcutils liblog libm libc
 
 include $(BUILD_EXECUTABLE)
 
diff --git a/charger/charger.c b/charger/charger.c
index c5e4ec2..66ddeaf 100644
--- a/charger/charger.c
+++ b/charger/charger.c
@@ -41,6 +41,10 @@
 #include <cutils/misc.h>
 #include <cutils/uevent.h>
 
+#ifdef CHARGER_ENABLE_SUSPEND
+#include <suspend/autosuspend.h>
+#endif
+
 #include "minui/minui.h"
 
 #ifndef max
@@ -352,6 +356,21 @@
     free(supply);
 }
 
+#ifdef CHARGER_ENABLE_SUSPEND
+static int request_suspend(bool enable)
+{
+    if (enable)
+        return autosuspend_enable();
+    else
+        return autosuspend_disable();
+}
+#else
+static int request_suspend(bool enable)
+{
+    return 0;
+}
+#endif
+
 static void parse_uevent(const char *msg, struct uevent *uevent)
 {
     uevent->action = "";
@@ -591,7 +610,7 @@
         x = (gr_fb_width() - str_len_px) / 2;
     if (y < 0)
         y = (gr_fb_height() - char_height) / 2;
-    gr_text(x, y, str);
+    gr_text(x, y, str, 0);
 
     return y + char_height;
 }
@@ -685,6 +704,8 @@
         charger->next_screen_transition = -1;
         gr_fb_blank(true);
         LOGV("[%lld] animation done\n", now);
+        if (charger->num_supplies_online > 0)
+            request_suspend(true);
         return;
     }
 
@@ -824,8 +845,10 @@
             }
         } else {
             /* if the power key got released, force screen state cycle */
-            if (key->pending)
+            if (key->pending) {
+                request_suspend(false);
                 kick_animation(charger->batt_anim);
+            }
         }
     }
 
@@ -843,6 +866,7 @@
 static void handle_power_supply_state(struct charger *charger, int64_t now)
 {
     if (charger->num_supplies_online == 0) {
+        request_suspend(false);
         if (charger->next_pwr_check == -1) {
             charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
             LOGI("[%lld] device unplugged: shutting down in %lld (@ %lld)\n",
diff --git a/cpio/mkbootfs.c b/cpio/mkbootfs.c
index 323a09d..3569e27 100644
--- a/cpio/mkbootfs.c
+++ b/cpio/mkbootfs.c
@@ -55,6 +55,7 @@
 
 static void fix_stat(const char *path, struct stat *s)
 {
+    uint64_t capabilities;
     if (canned_config) {
         // Use the list of file uid/gid/modes loaded from the file
         // given with -f.
@@ -78,7 +79,7 @@
     } else {
         // Use the compiled-in fs_config() function.
 
-        fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &s->st_mode);
+        fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &s->st_mode, &capabilities);
     }
 }
 
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index e48b9af..8621e9c 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -25,6 +25,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
+	liblog \
 	libc \
 	libcorkscrew \
 	libselinux
@@ -37,8 +38,9 @@
 LOCAL_MODULE := crasher
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS += -fstack-protector-all
 #LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_SHARED_LIBRARIES := libcutils libc
+LOCAL_SHARED_LIBRARIES := libcutils liblog libc
 include $(BUILD_EXECUTABLE)
 
 ifeq ($(ARCH_ARM_HAVE_VFP),true)
@@ -53,7 +55,7 @@
 LOCAL_MODULE := vfp-crasher
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := optional
-LOCAL_SHARED_LIBRARIES := libcutils libc
+LOCAL_SHARED_LIBRARIES := libcutils liblog libc
 include $(BUILD_EXECUTABLE)
 endif # ARCH_ARM_HAVE_VFP == true
 
diff --git a/debuggerd/arm/machine.c b/debuggerd/arm/machine.c
index 160db7b..67e3028 100644
--- a/debuggerd/arm/machine.c
+++ b/debuggerd/arm/machine.c
@@ -42,7 +42,7 @@
 #endif
 #endif
 
-static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, bool at_fault) {
+static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scopeFlags) {
     char code_buffer[64];       /* actual 8+1+((8+1)*4) + 1 == 45 */
     char ascii_buffer[32];      /* actual 16 + 1 == 17 */
     uintptr_t p, end;
@@ -102,7 +102,7 @@
             p += 4;
         }
         *asc_out = '\0';
-        _LOG(log, !at_fault, "    %s %s\n", code_buffer, ascii_buffer);
+        _LOG(log, scopeFlags, "    %s %s\n", code_buffer, ascii_buffer);
     }
 }
 
@@ -117,6 +117,8 @@
         return;
     }
 
+    int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
+
     if (at_fault && DUMP_MEMORY_FOR_ALL_REGISTERS) {
         static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
 
@@ -132,17 +134,18 @@
                 continue;
             }
 
-            _LOG(log, false, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
-            dump_memory(log, tid, addr, at_fault);
+            _LOG(log, scopeFlags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
+            dump_memory(log, tid, addr, scopeFlags | SCOPE_SENSITIVE);
         }
     }
 
-    _LOG(log, !at_fault, "\ncode around pc:\n");
-    dump_memory(log, tid, (uintptr_t)regs.ARM_pc, at_fault);
+    /* explicitly allow upload of code dump logging */
+    _LOG(log, scopeFlags, "\ncode around pc:\n");
+    dump_memory(log, tid, (uintptr_t)regs.ARM_pc, scopeFlags);
 
     if (regs.ARM_pc != regs.ARM_lr) {
-        _LOG(log, !at_fault, "\ncode around lr:\n");
-        dump_memory(log, tid, (uintptr_t)regs.ARM_lr, at_fault);
+        _LOG(log, scopeFlags, "\ncode around lr:\n");
+        dump_memory(log, tid, (uintptr_t)regs.ARM_lr, scopeFlags);
     }
 }
 
@@ -150,20 +153,20 @@
         log_t* log, pid_t tid, bool at_fault)
 {
     struct pt_regs r;
-    bool only_in_tombstone = !at_fault;
+    int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
 
     if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
-        _LOG(log, only_in_tombstone, "cannot get registers: %s\n", strerror(errno));
+        _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno));
         return;
     }
 
-    _LOG(log, only_in_tombstone, "    r0 %08x  r1 %08x  r2 %08x  r3 %08x\n",
+    _LOG(log, scopeFlags, "    r0 %08x  r1 %08x  r2 %08x  r3 %08x\n",
             (uint32_t)r.ARM_r0, (uint32_t)r.ARM_r1, (uint32_t)r.ARM_r2, (uint32_t)r.ARM_r3);
-    _LOG(log, only_in_tombstone, "    r4 %08x  r5 %08x  r6 %08x  r7 %08x\n",
+    _LOG(log, scopeFlags, "    r4 %08x  r5 %08x  r6 %08x  r7 %08x\n",
             (uint32_t)r.ARM_r4, (uint32_t)r.ARM_r5, (uint32_t)r.ARM_r6, (uint32_t)r.ARM_r7);
-    _LOG(log, only_in_tombstone, "    r8 %08x  r9 %08x  sl %08x  fp %08x\n",
+    _LOG(log, scopeFlags, "    r8 %08x  r9 %08x  sl %08x  fp %08x\n",
             (uint32_t)r.ARM_r8, (uint32_t)r.ARM_r9, (uint32_t)r.ARM_r10, (uint32_t)r.ARM_fp);
-    _LOG(log, only_in_tombstone, "    ip %08x  sp %08x  lr %08x  pc %08x  cpsr %08x\n",
+    _LOG(log, scopeFlags, "    ip %08x  sp %08x  lr %08x  pc %08x  cpsr %08x\n",
             (uint32_t)r.ARM_ip, (uint32_t)r.ARM_sp, (uint32_t)r.ARM_lr,
             (uint32_t)r.ARM_pc, (uint32_t)r.ARM_cpsr);
 
@@ -172,14 +175,14 @@
     int i;
 
     if(ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
-        _LOG(log, only_in_tombstone, "cannot get registers: %s\n", strerror(errno));
+        _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno));
         return;
     }
 
     for (i = 0; i < NUM_VFP_REGS; i += 2) {
-        _LOG(log, only_in_tombstone, "    d%-2d %016llx  d%-2d %016llx\n",
+        _LOG(log, scopeFlags, "    d%-2d %016llx  d%-2d %016llx\n",
                 i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]);
     }
-    _LOG(log, only_in_tombstone, "    scr %08lx\n", vfp_regs.fpscr);
+    _LOG(log, scopeFlags, "    scr %08lx\n", vfp_regs.fpscr);
 #endif
 }
diff --git a/debuggerd/backtrace.c b/debuggerd/backtrace.c
index ba76e7d..f42f24c 100644
--- a/debuggerd/backtrace.c
+++ b/debuggerd/backtrace.c
@@ -51,15 +51,15 @@
     localtime_r(&t, &tm);
     char timestr[64];
     strftime(timestr, sizeof(timestr), "%F %T", &tm);
-    _LOG(log, false, "\n\n----- pid %d at %s -----\n", pid, timestr);
+    _LOG(log, SCOPE_AT_FAULT, "\n\n----- pid %d at %s -----\n", pid, timestr);
 
     if (procname) {
-        _LOG(log, false, "Cmd line: %s\n", procname);
+        _LOG(log, SCOPE_AT_FAULT, "Cmd line: %s\n", procname);
     }
 }
 
 static void dump_process_footer(log_t* log, pid_t pid) {
-    _LOG(log, false, "\n----- end %d -----\n", pid);
+    _LOG(log, SCOPE_AT_FAULT, "\n----- end %d -----\n", pid);
 }
 
 static void dump_thread(log_t* log, pid_t tid, ptrace_context_t* context, bool attached,
@@ -81,10 +81,11 @@
         }
     }
 
-    _LOG(log, false, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid);
+    _LOG(log, SCOPE_AT_FAULT, "\n\"%s\" sysTid=%d\n",
+            threadname ? threadname : "<unknown>", tid);
 
     if (!attached && ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) {
-        _LOG(log, false, "Could not attach to thread: %s\n", strerror(errno));
+        _LOG(log, SCOPE_AT_FAULT, "Could not attach to thread: %s\n", strerror(errno));
         return;
     }
 
@@ -93,7 +94,7 @@
     backtrace_frame_t backtrace[STACK_DEPTH];
     ssize_t frames = unwind_backtrace_ptrace(tid, context, backtrace, 0, STACK_DEPTH);
     if (frames <= 0) {
-        _LOG(log, false, "Could not obtain stack trace for thread.\n");
+        _LOG(log, SCOPE_AT_FAULT, "Could not obtain stack trace for thread.\n");
     } else {
         backtrace_symbol_t backtrace_symbols[STACK_DEPTH];
         get_backtrace_symbols_ptrace(context, backtrace, frames, backtrace_symbols);
@@ -101,7 +102,7 @@
             char line[MAX_BACKTRACE_LINE_LENGTH];
             format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i],
                     line, MAX_BACKTRACE_LINE_LENGTH);
-            _LOG(log, false, "  %s\n", line);
+            _LOG(log, SCOPE_AT_FAULT, "  %s\n", line);
         }
         free_backtrace_symbols(backtrace_symbols, frames);
     }
@@ -112,10 +113,11 @@
     }
 }
 
-void dump_backtrace(int fd, pid_t pid, pid_t tid, bool* detach_failed,
+void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed,
         int* total_sleep_time_usec) {
     log_t log;
     log.tfd = fd;
+    log.amfd = amfd;
     log.quiet = true;
 
     ptrace_context_t* context = load_ptrace_context(tid);
diff --git a/debuggerd/backtrace.h b/debuggerd/backtrace.h
index ec7d20f..c5c786a 100644
--- a/debuggerd/backtrace.h
+++ b/debuggerd/backtrace.h
@@ -25,7 +25,7 @@
 
 /* Dumps a backtrace using a format similar to what Dalvik uses so that the result
  * can be intermixed in a bug report. */
-void dump_backtrace(int fd, pid_t pid, pid_t tid, bool* detach_failed,
+void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed,
         int* total_sleep_time_usec);
 
 #endif // _DEBUGGERD_BACKTRACE_H
diff --git a/debuggerd/crasher.c b/debuggerd/crasher.c
index 00652e9..5ecb1a5 100644
--- a/debuggerd/crasher.c
+++ b/debuggerd/crasher.c
@@ -17,9 +17,11 @@
 
 #include <cutils/sockets.h>
 
+extern const char* __progname;
+
 void crash1(void);
 void crashnostack(void);
-void maybeabort(void);
+static int do_action(const char* arg);
 
 static void debuggerd_connect()
 {
@@ -27,30 +29,46 @@
     int s;
     sprintf(tmp, "%d", gettid());
     s = socket_local_client("android:debuggerd",
-            ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);    
+            ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
     if(s >= 0) {
         read(s, tmp, 1);
         close(s);
     }
 }
 
-void test_call1()
+static void maybeabort() {
+    if(time(0) != 42) {
+        abort();
+    }
+}
+
+static int smash_stack(int i) {
+    printf("crasher: deliberately corrupting stack...\n");
+    // Unless there's a "big enough" buffer on the stack, gcc
+    // doesn't bother inserting checks.
+    char buf[8];
+    // If we don't write something relatively unpredictable
+    // into the buffer and then do something with it, gcc
+    // optimizes everything away and just returns a constant.
+    *(int*)(&buf[7]) = (uintptr_t) &buf[0];
+    return *(int*)(&buf[0]);
+}
+
+static void* global = 0; // So GCC doesn't optimize the tail recursion out of overflow_stack.
+
+__attribute__((noinline)) static void overflow_stack(void* p) {
+    void* buf[1];
+    buf[0] = p;
+    global = buf;
+    overflow_stack(&buf);
+}
+
+static void test_call1()
 {
     *((int*) 32) = 1;
 }
 
-void *test_thread(void *x)
-{
-    printf("crasher: thread pid=%d tid=%d\n", getpid(), gettid());
-
-    sleep(1);
-    test_call1();
-    printf("goodbye\n");
-
-    return 0;
-}
-
-void *noisy(void *x)
+static void *noisy(void *x)
 {
     char c = (unsigned) x;
     for(;;) {
@@ -61,7 +79,7 @@
     return 0;
 }
 
-int ctest()
+static int ctest()
 {
     pthread_t thr;
     pthread_attr_t attr;
@@ -74,33 +92,89 @@
     return 0;
 }
 
-int main(int argc, char **argv)
+static void* thread_callback(void* raw_arg)
 {
-    pthread_t thr;
-    pthread_attr_t attr;
-
-    fprintf(stderr,"crasher: " __TIME__ "!@\n");
-    fprintf(stderr,"crasher: init pid=%d tid=%d\n", getpid(), gettid());
-
-    if(argc > 1) {
-        if(!strcmp(argv[1],"nostack")) crashnostack();
-        if(!strcmp(argv[1],"ctest")) return ctest();
-        if(!strcmp(argv[1],"exit")) exit(1);
-        if(!strcmp(argv[1],"abort")) maybeabort();
-        
-        pthread_attr_init(&attr);
-        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-        pthread_create(&thr, &attr, test_thread, 0);
-        while(1) sleep(1);
-    } else {
-        crash1();
-//        *((int*) 0) = 42;
-    }
-    
-    return 0;
+    return (void*) do_action((const char*) raw_arg);
 }
 
-void maybeabort()
+static int do_action_on_thread(const char* arg)
 {
-    if(time(0) != 42) abort();
+    pthread_t t;
+    pthread_create(&t, NULL, thread_callback, (void*) arg);
+    void* result = NULL;
+    pthread_join(t, &result);
+    return (int) result;
+}
+
+__attribute__((noinline)) static int crash3(int a) {
+    *((int*) 0xdead) = a;
+    return a*4;
+}
+
+__attribute__((noinline)) static int crash2(int a) {
+    a = crash3(a) + 2;
+    return a*3;
+}
+
+__attribute__((noinline)) static int crash(int a) {
+    a = crash2(a) + 1;
+    return a*2;
+}
+
+static void abuse_heap() {
+    char buf[16];
+    free((void*) buf); // GCC is smart enough to warn about this, but we're doing it deliberately.
+}
+
+static int do_action(const char* arg)
+{
+    fprintf(stderr,"crasher: init pid=%d tid=%d\n", getpid(), gettid());
+
+    if (!strncmp(arg, "thread-", strlen("thread-"))) {
+        return do_action_on_thread(arg + strlen("thread-"));
+    } else if (!strcmp(arg,"smash-stack")) {
+        return smash_stack(42);
+    } else if (!strcmp(arg,"stack-overflow")) {
+        overflow_stack(NULL);
+    } else if (!strcmp(arg,"nostack")) {
+        crashnostack();
+    } else if (!strcmp(arg,"ctest")) {
+        return ctest();
+    } else if (!strcmp(arg,"exit")) {
+        exit(1);
+    } else if (!strcmp(arg,"crash")) {
+        return crash(42);
+    } else if (!strcmp(arg,"abort")) {
+        maybeabort();
+    } else if (!strcmp(arg, "heap-usage")) {
+        abuse_heap();
+    }
+
+    fprintf(stderr, "%s OP\n", __progname);
+    fprintf(stderr, "where OP is:\n");
+    fprintf(stderr, "  smash-stack     overwrite a stack-guard canary\n");
+    fprintf(stderr, "  stack-overflow  recurse until the stack overflows\n");
+    fprintf(stderr, "  heap-corruption cause a libc abort by corrupting the heap\n");
+    fprintf(stderr, "  heap-usage      cause a libc abort by abusing a heap function\n");
+    fprintf(stderr, "  nostack         crash with a NULL stack pointer\n");
+    fprintf(stderr, "  ctest           (obsoleted by thread-crash?)\n");
+    fprintf(stderr, "  exit            call exit(1)\n");
+    fprintf(stderr, "  crash           cause a SIGSEGV\n");
+    fprintf(stderr, "  abort           call abort()\n");
+    fprintf(stderr, "prefix any of the above with 'thread-' to not run\n");
+    fprintf(stderr, "on the process' main thread.\n");
+    return EXIT_SUCCESS;
+}
+
+int main(int argc, char **argv)
+{
+    fprintf(stderr,"crasher: built at " __TIME__ "!@\n");
+
+    if(argc > 1) {
+        return do_action(argv[1]);
+    } else {
+        crash1();
+    }
+
+    return 0;
 }
diff --git a/debuggerd/debuggerd.c b/debuggerd/debuggerd.c
index 55222c5..da2e9b0 100644
--- a/debuggerd/debuggerd.c
+++ b/debuggerd/debuggerd.c
@@ -52,6 +52,7 @@
     debugger_action_t action;
     pid_t pid, tid;
     uid_t uid, gid;
+    uintptr_t abort_msg_address;
 } debugger_request_t;
 
 static int
@@ -202,18 +203,23 @@
     pollfds[0].revents = 0;
     status = TEMP_FAILURE_RETRY(poll(pollfds, 1, 3000));
     if (status != 1) {
-        LOG("timed out reading tid\n");
+        LOG("timed out reading tid (from pid=%d uid=%d)\n", cr.pid, cr.uid);
         return -1;
     }
 
     debugger_msg_t msg;
+    memset(&msg, 0, sizeof(msg));
     status = TEMP_FAILURE_RETRY(read(fd, &msg, sizeof(msg)));
     if (status < 0) {
-        LOG("read failure? %s\n", strerror(errno));
+        LOG("read failure? %s (pid=%d uid=%d)\n",
+            strerror(errno), cr.pid, cr.uid);
         return -1;
     }
-    if (status != sizeof(msg)) {
-        LOG("invalid crash request of size %d\n", status);
+    if (status == sizeof(debugger_msg_t)) {
+        XLOG("crash request of size %d abort_msg_address=%#08x\n", status, msg.abort_msg_address);
+    } else {
+        LOG("invalid crash request of size %d (from pid=%d uid=%d)\n",
+            status, cr.pid, cr.uid);
         return -1;
     }
 
@@ -222,6 +228,7 @@
     out_request->pid = cr.pid;
     out_request->uid = cr.uid;
     out_request->gid = cr.gid;
+    out_request->abort_msg_address = msg.abort_msg_address;
 
     if (msg.action == DEBUGGER_ACTION_CRASH) {
         /* Ensure that the tid reported by the crashing process is valid. */
@@ -245,7 +252,7 @@
             return -1;
         }
     } else {
-        /* No one else is not allowed to dump arbitrary processes. */
+        /* No one else is allowed to dump arbitrary processes. */
         return -1;
     }
     return 0;
@@ -265,6 +272,7 @@
     XLOG("handle_request(%d)\n", fd);
 
     debugger_request_t request;
+    memset(&request, 0, sizeof(request));
     int status = read_request(fd, &request);
     if (!status) {
         XLOG("BOOM: pid=%d uid=%d gid=%d tid=%d\n",
@@ -308,11 +316,12 @@
                         if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
                             XLOG("stopped -- dumping to tombstone\n");
                             tombstone_path = engrave_tombstone(request.pid, request.tid,
-                                    signal, true, true, &detach_failed,
+                                    signal, request.abort_msg_address, true, true, &detach_failed,
                                     &total_sleep_time_usec);
                         } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
                             XLOG("stopped -- dumping to fd\n");
-                            dump_backtrace(fd, request.pid, request.tid, &detach_failed,
+                            dump_backtrace(fd, -1,
+                                    request.pid, request.tid, &detach_failed,
                                     &total_sleep_time_usec);
                         } else {
                             XLOG("stopped -- continuing\n");
@@ -345,8 +354,8 @@
                         /* don't dump sibling threads when attaching to GDB because it
                          * makes the process less reliable, apparently... */
                         tombstone_path = engrave_tombstone(request.pid, request.tid,
-                                signal, !attach_gdb, false, &detach_failed,
-                                &total_sleep_time_usec);
+                                signal, request.abort_msg_address, !attach_gdb, false,
+                                &detach_failed, &total_sleep_time_usec);
                         break;
                     }
 
diff --git a/debuggerd/mips/machine.c b/debuggerd/mips/machine.c
index dba1711..65fdf02 100644
--- a/debuggerd/mips/machine.c
+++ b/debuggerd/mips/machine.c
@@ -36,7 +36,7 @@
 
 #define R(x) ((unsigned int)(x))
 
-static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, bool at_fault) {
+static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scopeFlags) {
     char code_buffer[64];       /* actual 8+1+((8+1)*4) + 1 == 45 */
     char ascii_buffer[32];      /* actual 16 + 1 == 17 */
     uintptr_t p, end;
@@ -92,7 +92,7 @@
             p += 4;
         }
         *asc_out = '\0';
-        _LOG(log, !at_fault, "    %s %s\n", code_buffer, ascii_buffer);
+        _LOG(log, scopeFlags, "    %s %s\n", code_buffer, ascii_buffer);
     }
 }
 
@@ -107,6 +107,7 @@
         return;
     }
 
+    int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
     if (at_fault && DUMP_MEMORY_FOR_ALL_REGISTERS) {
         static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
 
@@ -129,20 +130,20 @@
                 continue;
             }
 
-            _LOG(log, false, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
-            dump_memory(log, tid, addr, at_fault);
+            _LOG(log, scopeFlags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
+            dump_memory(log, tid, addr, scopeFlags | SCOPE_SENSITIVE);
         }
     }
 
     unsigned int pc = R(r.cp0_epc);
     unsigned int ra = R(r.regs[31]);
 
-    _LOG(log, !at_fault, "\ncode around pc:\n");
-    dump_memory(log, tid, (uintptr_t)pc, at_fault);
+    _LOG(log, scopeFlags, "\ncode around pc:\n");
+    dump_memory(log, tid, (uintptr_t)pc, scopeFlags);
 
     if (pc != ra) {
-        _LOG(log, !at_fault, "\ncode around ra:\n");
-        dump_memory(log, tid, (uintptr_t)ra, at_fault);
+        _LOG(log, scopeFlags, "\ncode around ra:\n");
+        dump_memory(log, tid, (uintptr_t)ra, scopeFlags);
     }
 }
 
@@ -150,29 +151,29 @@
         log_t* log, pid_t tid, bool at_fault)
 {
     pt_regs_mips_t r;
-    bool only_in_tombstone = !at_fault;
+    int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
 
     if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
-        _LOG(log, only_in_tombstone, "cannot get registers: %s\n", strerror(errno));
+        _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno));
         return;
     }
 
-    _LOG(log, only_in_tombstone, " zr %08x  at %08x  v0 %08x  v1 %08x\n",
+    _LOG(log, scopeFlags, " zr %08x  at %08x  v0 %08x  v1 %08x\n",
      R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3]));
-    _LOG(log, only_in_tombstone, " a0 %08x  a1 %08x  a2 %08x  a3 %08x\n",
+    _LOG(log, scopeFlags, " a0 %08x  a1 %08x  a2 %08x  a3 %08x\n",
      R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7]));
-    _LOG(log, only_in_tombstone, " t0 %08x  t1 %08x  t2 %08x  t3 %08x\n",
+    _LOG(log, scopeFlags, " t0 %08x  t1 %08x  t2 %08x  t3 %08x\n",
      R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11]));
-    _LOG(log, only_in_tombstone, " t4 %08x  t5 %08x  t6 %08x  t7 %08x\n",
+    _LOG(log, scopeFlags, " t4 %08x  t5 %08x  t6 %08x  t7 %08x\n",
      R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15]));
-    _LOG(log, only_in_tombstone, " s0 %08x  s1 %08x  s2 %08x  s3 %08x\n",
+    _LOG(log, scopeFlags, " s0 %08x  s1 %08x  s2 %08x  s3 %08x\n",
      R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19]));
-    _LOG(log, only_in_tombstone, " s4 %08x  s5 %08x  s6 %08x  s7 %08x\n",
+    _LOG(log, scopeFlags, " s4 %08x  s5 %08x  s6 %08x  s7 %08x\n",
      R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23]));
-    _LOG(log, only_in_tombstone, " t8 %08x  t9 %08x  k0 %08x  k1 %08x\n",
+    _LOG(log, scopeFlags, " t8 %08x  t9 %08x  k0 %08x  k1 %08x\n",
      R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27]));
-    _LOG(log, only_in_tombstone, " gp %08x  sp %08x  s8 %08x  ra %08x\n",
+    _LOG(log, scopeFlags, " gp %08x  sp %08x  s8 %08x  ra %08x\n",
      R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31]));
-    _LOG(log, only_in_tombstone, " hi %08x  lo %08x bva %08x epc %08x\n",
+    _LOG(log, scopeFlags, " hi %08x  lo %08x bva %08x epc %08x\n",
      R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
 }
diff --git a/debuggerd/tombstone.c b/debuggerd/tombstone.c
index 5f2db43..77f6ef1 100644
--- a/debuggerd/tombstone.c
+++ b/debuggerd/tombstone.c
@@ -35,6 +35,9 @@
 #include <corkscrew/demangle.h>
 #include <corkscrew/backtrace.h>
 
+#include <sys/socket.h>
+#include <linux/un.h>
+
 #include <selinux/android.h>
 
 #include "machine.h"
@@ -47,6 +50,9 @@
 #define MAX_TOMBSTONES  10
 #define TOMBSTONE_DIR   "/data/tombstones"
 
+/* Must match the path defined in NativeCrashListener.java */
+#define NCRASH_SOCKET_PATH "/data/system/ndebugsocket"
+
 #define typecheck(x,y) {    \
     typeof(x) __dummy1;     \
     typeof(y) __dummy2;     \
@@ -84,6 +90,7 @@
 
 static const char *get_sigcode(int signo, int code)
 {
+    // Try the signal-specific codes...
     switch (signo) {
     case SIGILL:
         switch (code) {
@@ -122,7 +129,31 @@
         case SEGV_ACCERR: return "SEGV_ACCERR";
         }
         break;
+    case SIGTRAP:
+        switch (code) {
+        case TRAP_BRKPT: return "TRAP_BRKPT";
+        case TRAP_TRACE: return "TRAP_TRACE";
+        }
+        break;
     }
+    // Then the other codes...
+    switch (code) {
+    case SI_USER:    return "SI_USER";
+#if defined(SI_KERNEL)
+    case SI_KERNEL:  return "SI_KERNEL";
+#endif
+    case SI_QUEUE:   return "SI_QUEUE";
+    case SI_TIMER:   return "SI_TIMER";
+    case SI_MESGQ:   return "SI_MESGQ";
+    case SI_ASYNCIO: return "SI_ASYNCIO";
+#if defined(SI_SIGIO)
+    case SI_SIGIO:   return "SI_SIGIO";
+#endif
+#if defined(SI_TKILL)
+    case SI_TKILL:   return "SI_TKILL";
+#endif
+    }
+    // Then give up...
     return "?";
 }
 
@@ -132,7 +163,7 @@
 
     property_get("ro.revision", revision, "unknown");
 
-    _LOG(log, false, "Revision: '%s'\n", revision);
+    _LOG(log, SCOPE_AT_FAULT, "Revision: '%s'\n", revision);
 }
 
 static void dump_build_info(log_t* log)
@@ -141,7 +172,7 @@
 
     property_get("ro.build.fingerprint", fingerprint, "unknown");
 
-    _LOG(log, false, "Build fingerprint: '%s'\n", fingerprint);
+    _LOG(log, SCOPE_AT_FAULT, "Build fingerprint: '%s'\n", fingerprint);
 }
 
 static void dump_fault_addr(log_t* log, pid_t tid, int sig)
@@ -150,14 +181,14 @@
 
     memset(&si, 0, sizeof(si));
     if(ptrace(PTRACE_GETSIGINFO, tid, 0, &si)){
-        _LOG(log, false, "cannot get siginfo: %s\n", strerror(errno));
+        _LOG(log, SCOPE_AT_FAULT, "cannot get siginfo: %s\n", strerror(errno));
     } else if (signal_has_address(sig)) {
-        _LOG(log, false, "signal %d (%s), code %d (%s), fault addr %08x\n",
+        _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr %08x\n",
              sig, get_signame(sig),
              si.si_code, get_sigcode(sig, si.si_code),
              (uintptr_t) si.si_addr);
     } else {
-        _LOG(log, false, "signal %d (%s), code %d (%s), fault addr --------\n",
+        _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr --------\n",
              sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code));
     }
 }
@@ -190,19 +221,20 @@
             fclose(fp);
         }
 
-        _LOG(log, false, "pid: %d, tid: %d, name: %s  >>> %s <<<\n", pid, tid,
+        _LOG(log, SCOPE_AT_FAULT, "pid: %d, tid: %d, name: %s  >>> %s <<<\n", pid, tid,
                 threadname ? threadname : "UNKNOWN",
                 procname ? procname : "UNKNOWN");
     } else {
-        _LOG(log, true, "pid: %d, tid: %d, name: %s\n", pid, tid,
-                threadname ? threadname : "UNKNOWN");
+        _LOG(log, 0, "pid: %d, tid: %d, name: %s\n",
+                pid, tid, threadname ? threadname : "UNKNOWN");
     }
 }
 
 static void dump_backtrace(const ptrace_context_t* context __attribute((unused)),
         log_t* log, pid_t tid __attribute((unused)), bool at_fault,
         const backtrace_frame_t* backtrace, size_t frames) {
-    _LOG(log, !at_fault, "\nbacktrace:\n");
+    int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
+    _LOG(log, scopeFlags, "\nbacktrace:\n");
 
     backtrace_symbol_t backtrace_symbols[STACK_DEPTH];
     get_backtrace_symbols_ptrace(context, backtrace, frames, backtrace_symbols);
@@ -210,13 +242,13 @@
         char line[MAX_BACKTRACE_LINE_LENGTH];
         format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i],
                 line, MAX_BACKTRACE_LINE_LENGTH);
-        _LOG(log, !at_fault, "    %s\n", line);
+        _LOG(log, scopeFlags, "    %s\n", line);
     }
     free_backtrace_symbols(backtrace_symbols, frames);
 }
 
 static void dump_stack_segment(const ptrace_context_t* context, log_t* log, pid_t tid,
-        bool only_in_tombstone, uintptr_t* sp, size_t words, int label) {
+        int scopeFlags, uintptr_t* sp, size_t words, int label) {
     for (size_t i = 0; i < words; i++) {
         uint32_t stack_content;
         if (!try_get_word_ptrace(tid, *sp, &stack_content)) {
@@ -233,28 +265,28 @@
             uint32_t offset = stack_content - (mi->start + symbol->start);
             if (!i && label >= 0) {
                 if (offset) {
-                    _LOG(log, only_in_tombstone, "    #%02d  %08x  %08x  %s (%s+%u)\n",
+                    _LOG(log, scopeFlags, "    #%02d  %08x  %08x  %s (%s+%u)\n",
                             label, *sp, stack_content, mi ? mi->name : "", symbol_name, offset);
                 } else {
-                    _LOG(log, only_in_tombstone, "    #%02d  %08x  %08x  %s (%s)\n",
+                    _LOG(log, scopeFlags, "    #%02d  %08x  %08x  %s (%s)\n",
                             label, *sp, stack_content, mi ? mi->name : "", symbol_name);
                 }
             } else {
                 if (offset) {
-                    _LOG(log, only_in_tombstone, "         %08x  %08x  %s (%s+%u)\n",
+                    _LOG(log, scopeFlags, "         %08x  %08x  %s (%s+%u)\n",
                             *sp, stack_content, mi ? mi->name : "", symbol_name, offset);
                 } else {
-                    _LOG(log, only_in_tombstone, "         %08x  %08x  %s (%s)\n",
+                    _LOG(log, scopeFlags, "         %08x  %08x  %s (%s)\n",
                             *sp, stack_content, mi ? mi->name : "", symbol_name);
                 }
             }
             free(demangled_name);
         } else {
             if (!i && label >= 0) {
-                _LOG(log, only_in_tombstone, "    #%02d  %08x  %08x  %s\n",
+                _LOG(log, scopeFlags, "    #%02d  %08x  %08x  %s\n",
                         label, *sp, stack_content, mi ? mi->name : "");
             } else {
-                _LOG(log, only_in_tombstone, "         %08x  %08x  %s\n",
+                _LOG(log, scopeFlags, "         %08x  %08x  %s\n",
                         *sp, stack_content, mi ? mi->name : "");
             }
         }
@@ -280,28 +312,28 @@
         return;
     }
 
-    _LOG(log, !at_fault, "\nstack:\n");
+    int scopeFlags = SCOPE_SENSITIVE | (at_fault ? SCOPE_AT_FAULT : 0);
+    _LOG(log, scopeFlags, "\nstack:\n");
 
     // Dump a few words before the first frame.
-    bool only_in_tombstone = !at_fault;
     uintptr_t sp = backtrace[first].stack_top - STACK_WORDS * sizeof(uint32_t);
-    dump_stack_segment(context, log, tid, only_in_tombstone, &sp, STACK_WORDS, -1);
+    dump_stack_segment(context, log, tid, scopeFlags, &sp, STACK_WORDS, -1);
 
     // Dump a few words from all successive frames.
     // Only log the first 3 frames, put the rest in the tombstone.
     for (size_t i = first; i <= last; i++) {
         const backtrace_frame_t* frame = &backtrace[i];
         if (sp != frame->stack_top) {
-            _LOG(log, only_in_tombstone, "         ........  ........\n");
+            _LOG(log, scopeFlags, "         ........  ........\n");
             sp = frame->stack_top;
         }
         if (i - first == 3) {
-            only_in_tombstone = true;
+            scopeFlags &= (~SCOPE_AT_FAULT);
         }
         if (i == last) {
-            dump_stack_segment(context, log, tid, only_in_tombstone, &sp, STACK_WORDS, i);
+            dump_stack_segment(context, log, tid, scopeFlags, &sp, STACK_WORDS, i);
             if (sp < frame->stack_top + frame->stack_size) {
-                _LOG(log, only_in_tombstone, "         ........  ........\n");
+                _LOG(log, scopeFlags, "         ........  ........\n");
             }
         } else {
             size_t words = frame->stack_size / sizeof(uint32_t);
@@ -310,7 +342,7 @@
             } else if (words > STACK_WORDS) {
                 words = STACK_WORDS;
             }
-            dump_stack_segment(context, log, tid, only_in_tombstone, &sp, words, i);
+            dump_stack_segment(context, log, tid, scopeFlags, &sp, words, i);
         }
     }
 }
@@ -325,11 +357,24 @@
     }
 }
 
-static void dump_nearby_maps(const ptrace_context_t* context, log_t* log, pid_t tid) {
+static void dump_map(log_t* log, map_info_t* m, const char* what, int scopeFlags) {
+    if (m != NULL) {
+        _LOG(log, scopeFlags, "    %08x-%08x %c%c%c %s\n", m->start, m->end,
+             m->is_readable ? 'r' : '-',
+             m->is_writable ? 'w' : '-',
+             m->is_executable ? 'x' : '-',
+             m->name);
+    } else {
+        _LOG(log, scopeFlags, "    (no %s)\n", what);
+    }
+}
+
+static void dump_nearby_maps(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault) {
+    int scopeFlags = SCOPE_SENSITIVE | (at_fault ? SCOPE_AT_FAULT : 0);
     siginfo_t si;
     memset(&si, 0, sizeof(si));
     if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) {
-        _LOG(log, false, "cannot get siginfo for %d: %s\n",
+        _LOG(log, scopeFlags, "cannot get siginfo for %d: %s\n",
                 tid, strerror(errno));
         return;
     }
@@ -343,7 +388,7 @@
         return;
     }
 
-    _LOG(log, false, "\nmemory map around fault addr %08x:\n", (int)si.si_addr);
+    _LOG(log, scopeFlags, "\nmemory map around fault addr %08x:\n", (int)si.si_addr);
 
     /*
      * Search for a match, or for a hole where the match would be.  The list
@@ -371,21 +416,9 @@
      * Show "next" then "match" then "prev" so that the addresses appear in
      * ascending order (like /proc/pid/maps).
      */
-    if (next != NULL) {
-        _LOG(log, false, "    %08x-%08x %s\n", next->start, next->end, next->name);
-    } else {
-        _LOG(log, false, "    (no map below)\n");
-    }
-    if (map != NULL) {
-        _LOG(log, false, "    %08x-%08x %s\n", map->start, map->end, map->name);
-    } else {
-        _LOG(log, false, "    (no map for address)\n");
-    }
-    if (prev != NULL) {
-        _LOG(log, false, "    %08x-%08x %s\n", prev->start, prev->end, prev->name);
-    } else {
-        _LOG(log, false, "    (no map above)\n");
-    }
+    dump_map(log, next, "map below", scopeFlags);
+    dump_map(log, map, "map for address", scopeFlags);
+    dump_map(log, prev, "map above", scopeFlags);
 }
 
 static void dump_thread(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault,
@@ -396,7 +429,7 @@
     dump_backtrace_and_stack(context, log, tid, at_fault);
     if (at_fault) {
         dump_memory_and_code(context, log, tid, at_fault);
-        dump_nearby_maps(context, log, tid);
+        dump_nearby_maps(context, log, tid, at_fault);
     }
 }
 
@@ -433,7 +466,7 @@
             continue;
         }
 
-        _LOG(log, true, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
+        _LOG(log, 0, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
         dump_thread_info(log, pid, new_tid, false);
         dump_thread(context, log, new_tid, false, total_sleep_time_usec);
 
@@ -486,12 +519,12 @@
                 /* non-blocking EOF; we're done */
                 break;
             } else {
-                _LOG(log, true, "Error while reading log: %s\n",
+                _LOG(log, 0, "Error while reading log: %s\n",
                     strerror(errno));
                 break;
             }
         } else if (actual == 0) {
-            _LOG(log, true, "Got zero bytes while reading log: %s\n",
+            _LOG(log, 0, "Got zero bytes while reading log: %s\n",
                 strerror(errno));
             break;
         }
@@ -511,7 +544,7 @@
         }
 
         if (first) {
-            _LOG(log, true, "--------- %slog %s\n",
+            _LOG(log, 0, "--------- %slog %s\n",
                 tailOnly ? "tail end of " : "", filename);
             first = false;
         }
@@ -553,7 +586,7 @@
             shortLogNext = (shortLogNext + 1) % kShortLogMaxLines;
             shortLogCount++;
         } else {
-            _LOG(log, true, "%s.%03d %5d %5d %c %-8s: %s\n",
+            _LOG(log, 0, "%s.%03d %5d %5d %c %-8s: %s\n",
                 timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
                 prioChar, tag, msg);
         }
@@ -573,7 +606,7 @@
         }
 
         for (i = 0; i < shortLogCount; i++) {
-            _LOG(log, true, "%s\n", shortLog[shortLogNext]);
+            _LOG(log, 0, "%s\n", shortLog[shortLogNext]);
             shortLogNext = (shortLogNext + 1) % kShortLogMaxLines;
         }
     }
@@ -591,25 +624,73 @@
     dump_log_file(log, pid, "/dev/log/main", tailOnly);
 }
 
+static void dump_abort_message(log_t* log, pid_t tid, uintptr_t address) {
+  if (address == 0) {
+    return;
+  }
+
+  address += sizeof(size_t); // Skip the buffer length.
+
+  char msg[512];
+  memset(msg, 0, sizeof(msg));
+  char* p = &msg[0];
+  while (p < &msg[sizeof(msg)]) {
+    uint32_t data;
+    if (!try_get_word_ptrace(tid, address, &data)) {
+      break;
+    }
+    address += sizeof(uint32_t);
+
+    if ((*p++ = (data >>  0) & 0xff) == 0) {
+      break;
+    }
+    if ((*p++ = (data >>  8) & 0xff) == 0) {
+      break;
+    }
+    if ((*p++ = (data >> 16) & 0xff) == 0) {
+      break;
+    }
+    if ((*p++ = (data >> 24) & 0xff) == 0) {
+      break;
+    }
+  }
+  msg[sizeof(msg) - 1] = '\0';
+
+  _LOG(log, SCOPE_AT_FAULT, "Abort message: '%s'\n", msg);
+}
+
 /*
  * Dumps all information about the specified pid to the tombstone.
  */
-static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal,
-        bool dump_sibling_threads, int* total_sleep_time_usec)
+static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address,
+                       bool dump_sibling_threads, int* total_sleep_time_usec)
 {
     /* don't copy log messages to tombstone unless this is a dev device */
     char value[PROPERTY_VALUE_MAX];
     property_get("ro.debuggable", value, "0");
     bool want_logs = (value[0] == '1');
 
-    _LOG(log, false,
+    if (log->amfd >= 0) {
+        /*
+         * Activity Manager protocol: binary 32-bit network-byte-order ints for the
+         * pid and signal number, followed by the raw text of the dump, culminating
+         * in a zero byte that marks end-of-data.
+         */
+        uint32_t datum = htonl(pid);
+        TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) );
+        datum = htonl(signal);
+        TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) );
+    }
+
+    _LOG(log, SCOPE_AT_FAULT,
             "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
     dump_build_info(log);
     dump_revision_info(log);
     dump_thread_info(log, pid, tid, true);
-    if(signal) {
+    if (signal) {
         dump_fault_addr(log, tid, signal);
     }
+    dump_abort_message(log, tid, abort_msg_address);
 
     ptrace_context_t* context = load_ptrace_context(tid);
     dump_thread(context, log, tid, true, total_sleep_time_usec);
@@ -628,6 +709,16 @@
     if (want_logs) {
         dump_logs(log, pid, false);
     }
+
+    /* send EOD to the Activity Manager, then wait for its ack to avoid racing ahead
+     * and killing the target out from under it */
+    if (log->amfd >= 0) {
+        uint8_t eodMarker = 0;
+        TEMP_FAILURE_RETRY( write(log->amfd, &eodMarker, 1) );
+        /* 3 sec timeout reading the ack; we're fine if that happens */
+        TEMP_FAILURE_RETRY( read(log->amfd, &eodMarker, 1) );
+    }
+
     return detach_failed;
 }
 
@@ -687,7 +778,36 @@
     return strdup(path);
 }
 
-char* engrave_tombstone(pid_t pid, pid_t tid, int signal,
+static int activity_manager_connect() {
+    int amfd = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (amfd >= 0) {
+        struct sockaddr_un address;
+        int err;
+
+        memset(&address, 0, sizeof(address));
+        address.sun_family = AF_UNIX;
+        strncpy(address.sun_path, NCRASH_SOCKET_PATH, sizeof(address.sun_path));
+        err = TEMP_FAILURE_RETRY( connect(amfd, (struct sockaddr*) &address, sizeof(address)) );
+        if (!err) {
+            struct timeval tv;
+            memset(&tv, 0, sizeof(tv));
+            tv.tv_sec = 1;  // tight leash
+            err = setsockopt(amfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+            if (!err) {
+                tv.tv_sec = 3;  // 3 seconds on handshake read
+                err = setsockopt(amfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+            }
+        }
+        if (err) {
+            close(amfd);
+            amfd = -1;
+        }
+    }
+
+    return amfd;
+}
+
+char* engrave_tombstone(pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address,
         bool dump_sibling_threads, bool quiet, bool* detach_failed,
         int* total_sleep_time_usec) {
     mkdir(TOMBSTONE_DIR, 0755);
@@ -707,10 +827,12 @@
 
     log_t log;
     log.tfd = fd;
+    log.amfd = activity_manager_connect();
     log.quiet = quiet;
-    *detach_failed = dump_crash(&log, pid, tid, signal, dump_sibling_threads,
+    *detach_failed = dump_crash(&log, pid, tid, signal, abort_msg_address, dump_sibling_threads,
             total_sleep_time_usec);
 
+    close(log.amfd);
     close(fd);
     return path;
 }
diff --git a/debuggerd/tombstone.h b/debuggerd/tombstone.h
index edcd7b1..d4a1a96 100644
--- a/debuggerd/tombstone.h
+++ b/debuggerd/tombstone.h
@@ -25,7 +25,7 @@
 
 /* Creates a tombstone file and writes the crash dump to it.
  * Returns the path of the tombstone, which must be freed using free(). */
-char* engrave_tombstone(pid_t pid, pid_t tid, int signal,
+char* engrave_tombstone(pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address,
         bool dump_sibling_threads, bool quiet, bool* detach_failed, int* total_sleep_time_usec);
 
 #endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/debuggerd/utility.c b/debuggerd/utility.c
index aabaf74..9bf3c18 100644
--- a/debuggerd/utility.c
+++ b/debuggerd/utility.c
@@ -25,27 +25,63 @@
 #include <cutils/logd.h>
 #include <sys/ptrace.h>
 #include <sys/wait.h>
+#include <arpa/inet.h>
+#include <assert.h>
 
 #include "utility.h"
 
 const int sleep_time_usec = 50000;         /* 0.05 seconds */
 const int max_total_sleep_usec = 10000000; /* 10 seconds */
 
-void _LOG(log_t* log, bool in_tombstone_only, const char *fmt, ...) {
+static int write_to_am(int fd, const char* buf, int len) {
+    int to_write = len;
+    while (to_write > 0) {
+        int written = TEMP_FAILURE_RETRY( write(fd, buf + len - to_write, to_write) );
+        if (written < 0) {
+            /* hard failure */
+            LOG("AM write failure (%d / %s)\n", errno, strerror(errno));
+            return -1;
+        }
+        to_write -= written;
+    }
+    return len;
+}
+
+void _LOG(log_t* log, int scopeFlags, const char *fmt, ...) {
     char buf[512];
+    bool want_tfd_write;
+    bool want_log_write;
+    bool want_amfd_write;
+    int len = 0;
 
     va_list ap;
     va_start(ap, fmt);
 
-    if (log && log->tfd >= 0) {
-        int len;
+    // where is the information going to go?
+    want_tfd_write = log && log->tfd >= 0;
+    want_log_write = IS_AT_FAULT(scopeFlags) && (!log || !log->quiet);
+    want_amfd_write = IS_AT_FAULT(scopeFlags) && !IS_SENSITIVE(scopeFlags) && log && log->amfd >= 0;
+
+    // if we're going to need the literal string, generate it once here
+    if (want_tfd_write || want_amfd_write) {
         vsnprintf(buf, sizeof(buf), fmt, ap);
         len = strlen(buf);
+    }
+
+    if (want_tfd_write) {
         write(log->tfd, buf, len);
     }
 
-    if (!in_tombstone_only && (!log || !log->quiet)) {
+    if (want_log_write) {
+        // whatever goes to logcat also goes to the Activity Manager
         __android_log_vprint(ANDROID_LOG_INFO, "DEBUG", fmt, ap);
+        if (want_amfd_write && len > 0) {
+            int written = write_to_am(log->amfd, buf, len);
+            if (written <= 0) {
+                // timeout or other failure on write; stop informing the activity manager
+                log->amfd = -1;
+            }
+        }
     }
     va_end(ap);
 }
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 136f46d..1f006ed 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -24,26 +24,38 @@
 typedef struct {
     /* tombstone file descriptor */
     int tfd;
-    /* if true, does not log anything to the Android logcat */
+    /* Activity Manager socket file descriptor */
+    int amfd;
+    /* if true, does not log anything to the Android logcat or Activity Manager */
     bool quiet;
 } log_t;
 
-/* Log information onto the tombstone. */
-void _LOG(log_t* log, bool in_tombstone_only, const char *fmt, ...)
+/* Log information onto the tombstone.  scopeFlags is a bitmask of the flags defined
+ * here. */
+void _LOG(log_t* log, int scopeFlags, const char *fmt, ...)
         __attribute__ ((format(printf, 3, 4)));
 
-#define LOG(fmt...) _LOG(NULL, 0, fmt)
+/* The message pertains specifically to the faulting thread / process */
+#define SCOPE_AT_FAULT (1 << 0)
+/* The message contains sensitive information such as RAM contents */
+#define SCOPE_SENSITIVE  (1 << 1)
+
+#define IS_AT_FAULT(x)    (((x) & SCOPE_AT_FAULT) != 0)
+#define IS_SENSITIVE(x)    (((x) & SCOPE_SENSITIVE) != 0)
+
+/* Further helpful macros */
+#define LOG(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt)
 
 /* Set to 1 for normal debug traces */
 #if 0
-#define XLOG(fmt...) _LOG(NULL, 0, fmt)
+#define XLOG(fmt...) _LOG(NULL, SCOPE_AT_FAULT, 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(NULL, 0, fmt)
+#define XLOG2(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt)
 #else
 #define XLOG2(fmt...) do {} while(0)
 #endif
diff --git a/debuggerd/x86/machine.c b/debuggerd/x86/machine.c
index 01da5fe..af79092 100644
--- a/debuggerd/x86/machine.c
+++ b/debuggerd/x86/machine.c
@@ -38,21 +38,21 @@
 void dump_registers(const ptrace_context_t* context __attribute((unused)),
         log_t* log, pid_t tid, bool at_fault) {
     struct pt_regs_x86 r;
-    bool only_in_tombstone = !at_fault;
+    int scopeFlags = (at_fault ? SCOPE_AT_FAULT : 0);
 
     if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
-        _LOG(log, only_in_tombstone, "cannot get registers: %s\n", strerror(errno));
+        _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno));
         return;
     }
     //if there is no stack, no print just like arm
     if(!r.ebp)
         return;
-    _LOG(log, only_in_tombstone, "    eax %08x  ebx %08x  ecx %08x  edx %08x\n",
+    _LOG(log, scopeFlags, "    eax %08x  ebx %08x  ecx %08x  edx %08x\n",
          r.eax, r.ebx, r.ecx, r.edx);
-    _LOG(log, only_in_tombstone, "    esi %08x  edi %08x\n",
+    _LOG(log, scopeFlags, "    esi %08x  edi %08x\n",
          r.esi, r.edi);
-    _LOG(log, only_in_tombstone, "    xcs %08x  xds %08x  xes %08x  xfs %08x  xss %08x\n",
+    _LOG(log, scopeFlags, "    xcs %08x  xds %08x  xes %08x  xfs %08x  xss %08x\n",
          r.xcs, r.xds, r.xes, r.xfs, r.xss);
-    _LOG(log, only_in_tombstone, "    eip %08x  ebp %08x  esp %08x  flags %08x\n",
+    _LOG(log, scopeFlags, "    eip %08x  ebp %08x  esp %08x  flags %08x\n",
          r.eip, r.ebp, r.esp, r.eflags);
 }
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 5025dae..1189e1f 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -20,6 +20,7 @@
   $(LOCAL_PATH)/../../extras/ext4_utils
 LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c
 LOCAL_MODULE := fastboot
+LOCAL_MODULE_TAGS := debug
 
 ifeq ($(HOST_OS),linux)
   LOCAL_SRC_FILES += usb_linux.c util_linux.c
diff --git a/fastboot/bootimg.c b/fastboot/bootimg.c
index 9e0e45c7..240784f 100644
--- a/fastboot/bootimg.c
+++ b/fastboot/bootimg.c
@@ -37,10 +37,10 @@
     strcpy((char*) h->cmdline, cmdline);
 }
 
-boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size,
-                        void *ramdisk, unsigned ramdisk_size,
-                        void *second, unsigned second_size,
-                        unsigned page_size, unsigned base,
+boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offset,
+                        void *ramdisk, unsigned ramdisk_size, unsigned ramdisk_offset,
+                        void *second, unsigned second_size, unsigned second_offset,
+                        unsigned page_size, unsigned base, unsigned tags_offset,
                         unsigned *bootimg_size)
 {
     unsigned kernel_actual;
@@ -68,12 +68,15 @@
     hdr->kernel_size =  kernel_size;
     hdr->ramdisk_size = ramdisk_size;
     hdr->second_size =  second_size;
-    hdr->kernel_addr =  base + 0x00008000;
-    hdr->ramdisk_addr = base + 0x01000000;
-    hdr->second_addr =  base + 0x00F00000;
-    hdr->tags_addr =    base + 0x00000100;
+
+    hdr->kernel_addr =  base + kernel_offset;
+    hdr->ramdisk_addr = base + ramdisk_offset;
+    hdr->second_addr =  base + second_offset;
+    hdr->tags_addr =    base + tags_offset;
+
     hdr->page_size =    page_size;
 
+
     memcpy(hdr->magic + page_size,
            kernel, kernel_size);
     memcpy(hdr->magic + page_size + kernel_actual,
diff --git a/fastboot/engine.c b/fastboot/engine.c
index 7a55260..8d46991 100644
--- a/fastboot/engine.c
+++ b/fastboot/engine.c
@@ -29,6 +29,7 @@
 #include "fastboot.h"
 #include "make_ext4fs.h"
 
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
@@ -45,8 +46,6 @@
 #include <sys/mman.h>
 #endif
 
-extern struct fs_info info;
-
 #define ARRAY_SIZE(x)           (sizeof(x)/sizeof(x[0]))
 
 double now()
@@ -302,10 +301,7 @@
 #else
     fd = fileno(tmpfile());
 #endif
-    /* reset ext4fs info so we can be called multiple times */
-    reset_ext4fs_info();
-    info.len = image->partition_size;
-    make_ext4fs_internal(fd, NULL, NULL, NULL, 0, 1, 0, 0, 0, NULL);
+    make_ext4fs_sparse_fd(fd, image->partition_size, NULL, NULL);
 
     fstat(fd, &st);
     image->image_size = st.st_size;
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index 3de6d7d..447b257 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -58,10 +58,10 @@
 
 void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline);
 
-boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size,
-                        void *ramdisk, unsigned ramdisk_size,
-                        void *second, unsigned second_size,
-                        unsigned page_size, unsigned base,
+boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offset,
+                        void *ramdisk, unsigned ramdisk_size, unsigned ramdisk_offset,
+                        void *second, unsigned second_size, unsigned second_offset,
+                        unsigned page_size, unsigned base, unsigned tags_offset,
                         unsigned *bootimg_size);
 
 static usb_handle *usb = 0;
@@ -74,7 +74,13 @@
 static int64_t sparse_limit = -1;
 static int64_t target_sparse_limit = -1;
 
-static unsigned base_addr = 0x10000000;
+unsigned page_size = 2048;
+unsigned base_addr      = 0x10000000;
+unsigned kernel_offset  = 0x00008000;
+unsigned ramdisk_offset = 0x01000000;
+unsigned second_offset  = 0x00f00000;
+unsigned tags_offset    = 0x00000100;
+
 
 void die(const char *fmt, ...)
 {
@@ -186,11 +192,6 @@
 }
 #endif
 
-int match_fastboot(usb_ifc_info *info)
-{
-    return match_fastboot_with_serial(info, serial);
-}
-
 int match_fastboot_with_serial(usb_ifc_info *info, const char *local_serial)
 {
     if(!(vendor_id && (info->dev_vendor == vendor_id)) &&
@@ -217,6 +218,11 @@
     return 0;
 }
 
+int match_fastboot(usb_ifc_info *info)
+{
+    return match_fastboot_with_serial(info, serial);
+}
+
 int list_devices_callback(usb_ifc_info *info)
 {
     if (match_fastboot_with_serial(info, NULL) == 0) {
@@ -297,14 +303,14 @@
             "  -p <product>                             specify product name\n"
             "  -c <cmdline>                             override kernel commandline\n"
             "  -i <vendor id>                           specify a custom USB vendor id\n"
-            "  -b <base_addr>                           specify a custom kernel base address\n"
+            "  -b <base_addr>                           specify a custom kernel base address. default: 0x10000000\n"
             "  -n <page size>                           specify the nand page size. default: 2048\n"
             "  -S <size>[K|M|G]                         automatically sparse files greater than\n"
             "                                           size.  0 to disable\n"
         );
 }
 
-void *load_bootable_image(unsigned page_size, const char *kernel, const char *ramdisk,
+void *load_bootable_image(const char *kernel, const char *ramdisk,
                           unsigned *sz, const char *cmdline)
 {
     void *kdata = 0, *rdata = 0;
@@ -345,7 +351,10 @@
     }
 
     fprintf(stderr,"creating boot image...\n");
-    bdata = mkbootimg(kdata, ksize, rdata, rsize, 0, 0, page_size, base_addr, &bsize);
+    bdata = mkbootimg(kdata, ksize, kernel_offset,
+                      rdata, rsize, ramdisk_offset,
+                      0, 0, second_offset,
+                      page_size, base_addr, tags_offset, &bsize);
     if(bdata == 0) {
         fprintf(stderr,"failed to create boot.img\n");
         return 0;
@@ -806,53 +815,38 @@
     int erase_first = 1;
     void *data;
     unsigned sz;
-    unsigned page_size = 2048;
     int status;
     int c;
     int r;
 
-    const struct option longopts = { 0, 0, 0, 0 };
+    const struct option longopts[] = {
+        {"base", required_argument, 0, 'b'},
+        {"kernel_offset", required_argument, 0, 'k'},
+        {"page_size", required_argument, 0, 'n'},
+        {"ramdisk_offset", required_argument, 0, 'r'},
+        {"help", 0, 0, 'h'},
+        {0, 0, 0, 0}
+    };
 
     serial = getenv("ANDROID_SERIAL");
 
     while (1) {
-        c = getopt_long(argc, argv, "wub:n:s:S:lp:c:i:m:h", &longopts, NULL);
+        int option_index = 0;
+        c = getopt_long(argc, argv, "wub:k:n:r:s:S:lp:c:i:m:h", longopts, NULL);
         if (c < 0) {
             break;
         }
-
+        /* Alphabetical cases */
         switch (c) {
-        case 'w':
-            wants_wipe = 1;
-            break;
-        case 'u':
-            erase_first = 0;
-            break;
         case 'b':
             base_addr = strtoul(optarg, 0, 16);
             break;
-        case 'n':
-            page_size = (unsigned)strtoul(optarg, NULL, 0);
-            if (!page_size) die("invalid page size");
-            break;
-        case 's':
-            serial = optarg;
-            break;
-        case 'S':
-            sparse_limit = parse_num(optarg);
-            if (sparse_limit < 0) {
-                    die("invalid sparse limit");
-            }
-            break;
-        case 'l':
-            long_listing = 1;
-            break;
-        case 'p':
-            product = optarg;
-            break;
         case 'c':
             cmdline = optarg;
             break;
+        case 'h':
+            usage();
+            return 1;
         case 'i': {
                 char *endptr = NULL;
                 unsigned long val;
@@ -863,9 +857,37 @@
                 vendor_id = (unsigned short)val;
                 break;
             }
-        case 'h':
-            usage();
-            return 1;
+        case 'k':
+            kernel_offset = strtoul(optarg, 0, 16);
+            break;
+        case 'l':
+            long_listing = 1;
+            break;
+        case 'n':
+            page_size = (unsigned)strtoul(optarg, NULL, 0);
+            if (!page_size) die("invalid page size");
+            break;
+        case 'p':
+            product = optarg;
+            break;
+        case 'r':
+            ramdisk_offset = strtoul(optarg, 0, 16);
+            break;
+        case 's':
+            serial = optarg;
+            break;
+        case 'S':
+            sparse_limit = parse_num(optarg);
+            if (sparse_limit < 0) {
+                    die("invalid sparse limit");
+            }
+            break;
+        case 'u':
+            erase_first = 0;
+            break;
+        case 'w':
+            wants_wipe = 1;
+            break;
         case '?':
             return 1;
         default:
@@ -944,7 +966,7 @@
                 rname = argv[0];
                 skip(1);
             }
-            data = load_bootable_image(page_size, kname, rname, &sz, cmdline);
+            data = load_bootable_image(kname, rname, &sz, cmdline);
             if (data == 0) return 1;
             fb_queue_download("boot.img", data, sz);
             fb_queue_command("boot", "booting");
@@ -975,7 +997,7 @@
             } else {
                 skip(3);
             }
-            data = load_bootable_image(page_size, kname, rname, &sz, cmdline);
+            data = load_bootable_image(kname, rname, &sz, cmdline);
             if (data == 0) die("cannot load bootable image");
             fb_queue_flash(pname, data, sz);
         } else if(!strcmp(*argv, "flashall")) {
diff --git a/fastboot/fastboot_protocol.txt b/fastboot/fastboot_protocol.txt
new file mode 100644
index 0000000..2248992
--- /dev/null
+++ b/fastboot/fastboot_protocol.txt
@@ -0,0 +1,173 @@
+
+FastBoot  Version  0.4
+----------------------
+
+The fastboot protocol is a mechanism for communicating with bootloaders
+over USB.  It is designed to be very straightforward to implement, to
+allow it to be used across a wide range of devices and from hosts running
+Linux, Windows, or OSX.
+
+
+Basic Requirements
+------------------
+
+* Two bulk endpoints (in, out) are required
+* Max packet size must be 64 bytes for full-speed and 512 bytes for 
+  high-speed USB
+* The protocol is entirely host-driven and synchronous (unlike the
+  multi-channel, bi-directional, asynchronous ADB protocol)
+
+
+Transport and Framing
+---------------------
+
+1. Host sends a command, which is an ascii string in a single
+   packet no greater than 64 bytes.
+
+2. Client response with a single packet no greater than 64 bytes.
+   The first four bytes of the response are "OKAY", "FAIL", "DATA", 
+   or "INFO".  Additional bytes may contain an (ascii) informative
+   message.
+
+   a. INFO -> the remaining 60 bytes are an informative message
+      (providing progress or diagnostic messages).  They should 
+      be displayed and then step #2 repeats
+
+   b. FAIL -> the requested command failed.  The remaining 60 bytes 
+      of the response (if present) provide a textual failure message 
+      to present to the user.  Stop.
+
+   c. OKAY -> the requested command completed successfully.  Go to #5
+
+   d. DATA -> the requested command is ready for the data phase.
+      A DATA response packet will be 12 bytes long, in the form of
+      DATA00000000 where the 8 digit hexidecimal number represents
+      the total data size to transfer.
+
+3. Data phase.  Depending on the command, the host or client will 
+   send the indicated amount of data.  Short packets are always 
+   acceptable and zero-length packets are ignored.  This phase continues
+   until the client has sent or received the number of bytes indicated
+   in the "DATA" response above.
+
+4. Client responds with a single packet no greater than 64 bytes.  
+   The first four bytes of the response are "OKAY", "FAIL", or "INFO".  
+   Similar to #2:
+
+   a. INFO -> display the remaining 60 bytes and return to #4
+   
+   b. FAIL -> display the remaining 60 bytes (if present) as a failure
+      reason and consider the command failed.  Stop.
+
+   c. OKAY -> success.  Go to #5
+
+5. Success.  Stop.
+
+
+Example Session
+---------------
+
+Host:    "getvar:version"        request version variable
+
+Client:  "OKAY0.4"               return version "0.4"
+
+Host:    "getvar:nonexistant"    request some undefined variable
+
+Client:  "OKAY"                  return value ""
+
+Host:    "download:00001234"     request to send 0x1234 bytes of data
+
+Client:  "DATA00001234"          ready to accept data
+
+Host:    < 0x1234 bytes >        send data
+
+Client:  "OKAY"                  success
+
+Host:    "flash:bootloader"      request to flash the data to the bootloader
+
+Client:  "INFOerasing flash"     indicate status / progress
+         "INFOwriting flash"
+         "OKAY"                  indicate success
+
+Host:    "powerdown"             send a command
+
+Client:  "FAILunknown command"   indicate failure
+
+
+Command Reference
+-----------------
+
+* Command parameters are indicated by printf-style escape sequences.
+
+* Commands are ascii strings and sent without the quotes (which are
+  for illustration only here) and without a trailing 0 byte.
+
+* Commands that begin with a lowercase letter are reserved for this
+  specification.  OEM-specific commands should not begin with a 
+  lowercase letter, to prevent incompatibilities with future specs.
+
+ "getvar:%s"           Read a config/version variable from the bootloader.
+                       The variable contents will be returned after the
+                       OKAY response.
+
+ "download:%08x"       Write data to memory which will be later used
+                       by "boot", "ramdisk", "flash", etc.  The client
+                       will reply with "DATA%08x" if it has enough 
+                       space in RAM or "FAIL" if not.  The size of
+                       the download is remembered.
+
+  "verify:%08x"        Send a digital signature to verify the downloaded
+                       data.  Required if the bootloader is "secure"
+                       otherwise "flash" and "boot" will be ignored.
+
+  "flash:%s"           Write the previously downloaded image to the
+                       named partition (if possible).
+
+  "erase:%s"           Erase the indicated partition (clear to 0xFFs)
+
+  "boot"               The previously downloaded data is a boot.img
+                       and should be booted according to the normal
+                       procedure for a boot.img
+
+  "continue"           Continue booting as normal (if possible)
+
+  "reboot"             Reboot the device.
+
+  "reboot-bootloader"  Reboot back into the bootloader.
+                       Useful for upgrade processes that require upgrading
+                       the bootloader and then upgrading other partitions
+                       using the new bootloader.
+
+  "powerdown"          Power off the device.
+
+
+
+Client Variables
+----------------
+
+The "getvar:%s" command is used to read client variables which
+represent various information about the device and the software
+on it.
+
+The various currently defined names are:
+
+  version             Version of FastBoot protocol supported.
+                      It should be "0.3" for this document.
+
+  version-bootloader  Version string for the Bootloader.
+
+  version-baseband    Version string of the Baseband Software
+
+  product             Name of the product
+
+  serialno            Product serial number
+
+  secure              If the value is "yes", this is a secure
+                      bootloader requiring a signature before
+                      it will install or boot images.
+
+Names starting with a lowercase character are reserved by this
+specification.  OEM-specific names should not start with lowercase
+characters.
+
+
diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c
index b7a9ca3..9153c8d 100644
--- a/fastboot/usb_linux.c
+++ b/fastboot/usb_linux.c
@@ -75,10 +75,18 @@
     unsigned char ep_out;
 };
 
+/* True if name isn't a valid name for a USB device in /sys/bus/usb/devices.
+ * Device names are made up of numbers, dots, and dashes, e.g., '7-1.5'.
+ * We reject interfaces (e.g., '7-1.5:1.0') and host controllers (e.g. 'usb1').
+ * The name must also start with a digit, to disallow '.' and '..'
+ */
 static inline int badname(const char *name)
 {
-    while(*name) {
-        if(!isdigit(*name++)) return 1;
+    if (!isdigit(*name))
+      return 1;
+    while(*++name) {
+        if(!isdigit(*name) && *name != '.' && *name != '-')
+            return 1;
     }
     return 0;
 }
@@ -95,7 +103,8 @@
     return 0;
 }
 
-static int filter_usb_device(int fd, char *ptr, int len, int writable,
+static int filter_usb_device(int fd, char* sysfs_name,
+                             char *ptr, int len, int writable,
                              ifc_match_func callback,
                              int *ept_in_id, int *ept_out_id, int *ifc_id)
 {
@@ -131,69 +140,35 @@
     info.dev_protocol = dev->bDeviceProtocol;
     info.writable = writable;
 
-    // read device serial number (if there is one)
-    info.serial_number[0] = 0;
-    if (dev->iSerialNumber) {
-        struct usbdevfs_ctrltransfer  ctrl;
-        // Keep it short enough because some bootloaders are borked if the URB len is > 255
-        // 128 is too big by 1.
-        __u16 buffer[127];
+    snprintf(info.device_path, sizeof(info.device_path), "usb:%s", sysfs_name);
 
-        memset(buffer, 0, sizeof(buffer));
-
-        ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
-        ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
-        ctrl.wValue = (USB_DT_STRING << 8) | dev->iSerialNumber;
-        //language ID (en-us) for serial number string
-        ctrl.wIndex = 0x0409;
-        ctrl.wLength = sizeof(buffer);
-        ctrl.data = buffer;
-        ctrl.timeout = 50;
-
-        result = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
-        if (result > 0) {
-            int i;
-            // skip first word, and copy the rest to the serial string, changing shorts to bytes.
-            result /= 2;
-            for (i = 1; i < result; i++)
-                info.serial_number[i - 1] = buffer[i];
-            info.serial_number[i - 1] = 0;
-        }
-    }
-
-    /* We need to get a path that represents a particular port on a particular
-     * hub.  We are passed an fd that was obtained by opening an entry under
-     * /dev/bus/usb.  Unfortunately, the names of those entries change each
-     * time devices are plugged and unplugged.  So how to get a repeatable
-     * path?  udevadm provided the inspiration.  We can get the major and
-     * minor of the device file, read the symlink that can be found here:
-     *   /sys/dev/char/<major>:<minor>
-     * and then use the last element of that path.  As a concrete example, I
-     * have an Android device at /dev/bus/usb/001/027 so working with bash:
-     *   $ ls -l /dev/bus/usb/001/027
-     *   crw-rw-r-- 1 root plugdev 189, 26 Apr  9 11:03 /dev/bus/usb/001/027
-     *   $ ls -l /sys/dev/char/189:26
-     *   lrwxrwxrwx 1 root root 0 Apr  9 11:03 /sys/dev/char/189:26 ->
-     *           ../../devices/pci0000:00/0000:00:1a.7/usb1/1-4/1-4.2/1-4.2.3
-     * So our device_path would be 1-4.2.3 which says my device is connected
-     * to port 3 of a hub on port 2 of a hub on port 4 of bus 1 (per
-     * http://www.linux-usb.org/FAQ.html).
+    /* Read device serial number (if there is one).
+     * We read the serial number from sysfs, since it's faster and more
+     * reliable than issuing a control pipe read, and also won't
+     * cause problems for devices which don't like getting descriptor
+     * requests while they're in the middle of flashing.
      */
-    info.device_path[0] = '\0';
-    result = fstat(fd, &st);
-    if (!result && S_ISCHR(st.st_mode)) {
-        char cdev[128];
-        char link[256];
-        char *slash;
-        ssize_t link_len;
-        snprintf(cdev, sizeof(cdev), "/sys/dev/char/%d:%d",
-                 major(st.st_rdev), minor(st.st_rdev));
-        link_len = readlink(cdev, link, sizeof(link) - 1);
-        if (link_len > 0) {
-            link[link_len] = '\0';
-            slash = strrchr(link, '/');
-            if (slash)
-                snprintf(info.device_path, sizeof(info.device_path), "usb:%s", slash+1);
+    info.serial_number[0] = '\0';
+    if (dev->iSerialNumber) {
+        char path[80];
+        int fd;
+
+        snprintf(path, sizeof(path),
+                 "/sys/bus/usb/devices/%s/serial", sysfs_name);
+        path[sizeof(path) - 1] = '\0';
+
+        fd = open(path, O_RDONLY);
+        if (fd >= 0) {
+            int chars_read = read(fd, info.serial_number,
+                                  sizeof(info.serial_number) - 1);
+            close(fd);
+
+            if (chars_read <= 0)
+                info.serial_number[0] = '\0';
+            else if (info.serial_number[chars_read - 1] == '\n') {
+                // strip trailing newline
+                info.serial_number[chars_read - 1] = '\0';
+            }
         }
     }
 
@@ -241,14 +216,73 @@
     return -1;
 }
 
+static int read_sysfs_string(const char *sysfs_name, const char *sysfs_node,
+                             char* buf, int bufsize)
+{
+    char path[80];
+    int fd, n;
+
+    snprintf(path, sizeof(path),
+             "/sys/bus/usb/devices/%s/%s", sysfs_name, sysfs_node);
+    path[sizeof(path) - 1] = '\0';
+
+    fd = open(path, O_RDONLY);
+    if (fd < 0)
+        return -1;
+
+    n = read(fd, buf, bufsize - 1);
+    close(fd);
+
+    if (n < 0)
+        return -1;
+
+    buf[n] = '\0';
+
+    return n;
+}
+
+static int read_sysfs_number(const char *sysfs_name, const char *sysfs_node)
+{
+    char buf[16];
+    int value;
+
+    if (read_sysfs_string(sysfs_name, sysfs_node, buf, sizeof(buf)) < 0)
+        return -1;
+
+    if (sscanf(buf, "%d", &value) != 1)
+        return -1;
+
+    return value;
+}
+
+/* Given the name of a USB device in sysfs, get the name for the same
+ * device in devfs. Returns 0 for success, -1 for failure.
+ */
+static int convert_to_devfs_name(const char* sysfs_name,
+                                 char* devname, int devname_size)
+{
+    int busnum, devnum;
+
+    busnum = read_sysfs_number(sysfs_name, "busnum");
+    if (busnum < 0)
+        return -1;
+
+    devnum = read_sysfs_number(sysfs_name, "devnum");
+    if (devnum < 0)
+        return -1;
+
+    snprintf(devname, devname_size, "/dev/bus/usb/%03d/%03d", busnum, devnum);
+    return 0;
+}
+
 static usb_handle *find_usb_device(const char *base, ifc_match_func callback)
 {
     usb_handle *usb = 0;
-    char busname[64], devname[64];
+    char devname[64];
     char desc[1024];
     int n, in, out, ifc;
 
-    DIR *busdir, *devdir;
+    DIR *busdir;
     struct dirent *de;
     int fd;
     int writable;
@@ -259,15 +293,7 @@
     while((de = readdir(busdir)) && (usb == 0)) {
         if(badname(de->d_name)) continue;
 
-        sprintf(busname, "%s/%s", base, de->d_name);
-        devdir = opendir(busname);
-        if(devdir == 0) continue;
-
-//        DBG("[ scanning %s ]\n", busname);
-        while((de = readdir(devdir)) && (usb == 0)) {
-
-            if(badname(de->d_name)) continue;
-            sprintf(devname, "%s/%s", busname, de->d_name);
+        if(!convert_to_devfs_name(de->d_name, devname, sizeof(devname))) {
 
 //            DBG("[ scanning %s ]\n", devname);
             writable = 1;
@@ -282,7 +308,7 @@
 
             n = read(fd, desc, sizeof(desc));
 
-            if(filter_usb_device(fd, desc, n, writable, callback,
+            if(filter_usb_device(fd, de->d_name, desc, n, writable, callback,
                                  &in, &out, &ifc) == 0) {
                 usb = calloc(1, sizeof(usb_handle));
                 strcpy(usb->fname, devname);
@@ -301,7 +327,6 @@
                 close(fd);
             }
         }
-        closedir(devdir);
     }
     closedir(busdir);
 
@@ -431,5 +456,5 @@
 
 usb_handle *usb_open(ifc_match_func callback)
 {
-    return find_usb_device("/dev/bus/usb", callback);
+    return find_usb_device("/sys/bus/usb/devices", callback);
 }
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 7c66f6a..782ae99 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -8,6 +8,7 @@
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 
 LOCAL_MODULE:= libfs_mgr
+LOCAL_STATIC_LIBRARIES := liblogwrap
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 
 include $(BUILD_STATIC_LIBRARY)
@@ -27,7 +28,7 @@
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/sbin
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
 
-LOCAL_STATIC_LIBRARIES := libfs_mgr libcutils libc
+LOCAL_STATIC_LIBRARIES := libfs_mgr liblogwrap libcutils liblog libc
 
 include $(BUILD_EXECUTABLE)
 
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 2bcc9c4..fecc556 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -14,11 +14,6 @@
  * limitations under the License.
  */
 
-/* TO DO:
- *   1. Re-direct fsck output to the kernel log?
- *
- */
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -36,6 +31,7 @@
 #include <private/android_filesystem_config.h>
 #include <cutils/partition_utils.h>
 #include <cutils/properties.h>
+#include <logwrap/logwrap.h>
 
 #include "fs_mgr_priv.h"
 
@@ -44,6 +40,8 @@
 
 #define E2FSCK_BIN      "/system/bin/e2fsck"
 
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+
 struct flag_list {
     const char *name;
     unsigned flag;
@@ -72,6 +70,10 @@
     { "wait",        MF_WAIT },
     { "check",       MF_CHECK },
     { "encryptable=",MF_CRYPT },
+    { "nonremovable",MF_NONREMOVABLE },
+    { "voldmanaged=",MF_VOLDMANAGED},
+    { "length=",     MF_LENGTH },
+    { "recoveryonly",MF_RECOVERYONLY },
     { "defaults",    0 },
     { 0,             0 },
 };
@@ -106,7 +108,8 @@
     return ret;
 }
 
-static int parse_flags(char *flags, struct flag_list *fl, char **key_loc,
+static int parse_flags(char *flags, struct flag_list *fl,
+                       char **key_loc, long long *part_length, char **label, int *partnum,
                        char *fs_options, int fs_options_len)
 {
     int f = 0;
@@ -119,6 +122,18 @@
     if (key_loc) {
         *key_loc = NULL;
     }
+    /* initialize part_length to 0, if we find an MF_LENGTH flag,
+     * then we'll set part_length to the proper value */
+    if (part_length) {
+        *part_length = 0;
+    }
+    if (partnum) {
+        *partnum = -1;
+    }
+    if (label) {
+        *label = NULL;
+    }
+
     /* initialize fs_options to the null string */
     if (fs_options && (fs_options_len > 0)) {
         fs_options[0] = '\0';
@@ -137,6 +152,36 @@
                      * location of the keys.  Get it and return it.
                      */
                     *key_loc = strdup(strchr(p, '=') + 1);
+                } else if ((fl[i].flag == MF_LENGTH) && part_length) {
+                    /* The length flag is followed by an = and the
+                     * size of the partition.  Get it and return it.
+                     */
+                    *part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
+                } else if ((fl[i].flag == MF_VOLDMANAGED) && label && partnum) {
+                    /* The voldmanaged flag is followed by an = and the
+                     * label, a colon and the partition number or the
+                     * word "auto", e.g.
+                     *   voldmanaged=sdcard:3
+                     * Get and return them.
+                     */
+                    char *label_start;
+                    char *label_end;
+                    char *part_start;
+
+                    label_start = strchr(p, '=') + 1;
+                    label_end = strchr(p, ':');
+                    if (label_end) {
+                        *label = strndup(label_start,
+                                         (int) (label_end - label_start));
+                        part_start = strchr(p, ':') + 1;
+                        if (!strcmp(part_start, "auto")) {
+                            *partnum = -1;
+                        } else {
+                            *partnum = strtol(part_start, NULL, 0);
+                        }
+                    } else {
+                        ERROR("Warning: voldmanaged= flag malformed\n");
+                    }
                 }
                 break;
             }
@@ -227,7 +272,7 @@
     }
 }
 
-static struct fstab_rec *read_fstab(char *fstab_path)
+struct fstab *fs_mgr_read_fstab(const char *fstab_path)
 {
     FILE *fstab_file;
     int cnt, entries;
@@ -235,8 +280,12 @@
     char line[256];
     const char *delim = " \t";
     char *save_ptr, *p;
-    struct fstab_rec *fstab;
+    struct fstab *fstab;
+    struct fstab_rec *recs;
     char *key_loc;
+    long long part_length;
+    char *label;
+    int partnum;
 #define FS_OPTIONS_LEN 1024
     char tmp_fs_options[FS_OPTIONS_LEN];
 
@@ -269,7 +318,11 @@
         return 0;
     }
 
-    fstab = calloc(entries + 1, sizeof(struct fstab_rec));
+    /* Allocate and init the fstab structure */
+    fstab = calloc(1, sizeof(struct fstab));
+    fstab->num_entries = entries;
+    fstab->fstab_filename = strdup(fstab_path);
+    fstab->recs = calloc(fstab->num_entries, sizeof(struct fstab_rec));
 
     fseek(fstab_file, 0, SEEK_SET);
 
@@ -303,41 +356,48 @@
             ERROR("Error parsing mount source\n");
             return 0;
         }
-        fstab[cnt].blk_dev = strdup(p);
+        fstab->recs[cnt].blk_device = strdup(p);
 
         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
-            ERROR("Error parsing mnt_point\n");
+            ERROR("Error parsing mount_point\n");
             return 0;
         }
-        fstab[cnt].mnt_point = strdup(p);
+        fstab->recs[cnt].mount_point = strdup(p);
 
         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
             ERROR("Error parsing fs_type\n");
             return 0;
         }
-        fstab[cnt].type = strdup(p);
+        fstab->recs[cnt].fs_type = strdup(p);
 
         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
             ERROR("Error parsing mount_flags\n");
             return 0;
         }
         tmp_fs_options[0] = '\0';
-        fstab[cnt].flags = parse_flags(p, mount_flags, 0, tmp_fs_options, FS_OPTIONS_LEN);
+        fstab->recs[cnt].flags = parse_flags(p, mount_flags,
+                                       NULL, NULL, NULL, NULL,
+                                       tmp_fs_options, FS_OPTIONS_LEN);
 
         /* fs_options are optional */
         if (tmp_fs_options[0]) {
-            fstab[cnt].fs_options = strdup(tmp_fs_options);
+            fstab->recs[cnt].fs_options = strdup(tmp_fs_options);
         } else {
-            fstab[cnt].fs_options = NULL;
+            fstab->recs[cnt].fs_options = NULL;
         }
 
         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
             ERROR("Error parsing fs_mgr_options\n");
             return 0;
         }
-        fstab[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags, &key_loc, 0, 0);
-        fstab[cnt].key_loc = key_loc;
-
+        fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
+                                              &key_loc, &part_length,
+                                              &label, &partnum,
+                                              NULL, 0);
+        fstab->recs[cnt].key_loc = key_loc;
+        fstab->recs[cnt].length = part_length;
+        fstab->recs[cnt].label = label;
+        fstab->recs[cnt].partnum = partnum;
         cnt++;
     }
     fclose(fstab_file);
@@ -345,35 +405,45 @@
     return fstab;
 }
 
-static void free_fstab(struct fstab_rec *fstab)
+void fs_mgr_free_fstab(struct fstab *fstab)
 {
-    int i = 0;
+    int i;
 
-    while (fstab[i].blk_dev) {
+    for (i = 0; i < fstab->num_entries; i++) {
         /* Free the pointers return by strdup(3) */
-        free(fstab[i].blk_dev);
-        free(fstab[i].mnt_point);
-        free(fstab[i].type);
-        free(fstab[i].fs_options);
-        free(fstab[i].key_loc);
-
+        free(fstab->recs[i].blk_device);
+        free(fstab->recs[i].mount_point);
+        free(fstab->recs[i].fs_type);
+        free(fstab->recs[i].fs_options);
+        free(fstab->recs[i].key_loc);
+        free(fstab->recs[i].label);
         i++;
     }
 
-    /* Free the actual fstab array created by calloc(3) */
+    /* Free the fstab_recs array created by calloc(3) */
+    free(fstab->recs);
+
+    /* Free the fstab filename */
+    free(fstab->fstab_filename);
+
+    /* Free fstab */
     free(fstab);
 }
 
-static void check_fs(char *blk_dev, char *type, char *target)
+static void check_fs(char *blk_device, char *fs_type, char *target)
 {
-    pid_t pid;
     int status;
     int ret;
     long tmpmnt_flags = MS_NOATIME | MS_NOEXEC | MS_NOSUID;
     char *tmpmnt_opts = "nomblk_io_submit,errors=remount-ro";
+    char *e2fsck_argv[] = {
+        E2FSCK_BIN,
+        "-y",
+        blk_device
+    };
 
     /* Check for the types of filesystems we know how to check */
-    if (!strcmp(type, "ext2") || !strcmp(type, "ext3") || !strcmp(type, "ext4")) {
+    if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) {
         /*
          * First try to mount and unmount the filesystem.  We do this because
          * the kernel is more efficient than e2fsck in running the journal and
@@ -387,25 +457,19 @@
          * filesytsem due to an error, e2fsck is still run to do a full check
          * fix the filesystem.
          */
-        ret = mount(blk_dev, target, type, tmpmnt_flags, tmpmnt_opts);
-        if (! ret) {
+        ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts);
+        if (!ret) {
             umount(target);
         }
 
-        INFO("Running %s on %s\n", E2FSCK_BIN, blk_dev);
-        pid = fork();
-        if (pid > 0) {
-            /* Parent, wait for the child to return */
-            waitpid(pid, &status, 0);
-        } else if (pid == 0) {
-            /* child, run checker */
-            execlp(E2FSCK_BIN, E2FSCK_BIN, "-y", blk_dev, (char *)NULL);
+        INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
 
-            /* Only gets here on error */
-            ERROR("Cannot run fs_mgr binary %s\n", E2FSCK_BIN);
-        } else {
+        ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
+                                      &status, true, LOG_KLOG, true);
+
+        if (ret < 0) {
             /* No need to check for error in fork, we can't really handle it now */
-            ERROR("Fork failed trying to run %s\n", E2FSCK_BIN);
+            ERROR("Failed trying to run %s\n", E2FSCK_BIN);
         }
     }
 
@@ -443,49 +507,62 @@
     return ret;
 }
 
-int fs_mgr_mount_all(char *fstab_file)
+int fs_mgr_mount_all(struct fstab *fstab)
 {
     int i = 0;
     int encrypted = 0;
     int ret = -1;
     int mret;
-    struct fstab_rec *fstab = 0;
 
-    if (!(fstab = read_fstab(fstab_file))) {
+    if (!fstab) {
         return ret;
     }
 
-    for (i = 0; fstab[i].blk_dev; i++) {
-        if (fstab[i].fs_mgr_flags & MF_WAIT) {
-            wait_for_file(fstab[i].blk_dev, WAIT_TIMEOUT);
+    for (i = 0; i < fstab->num_entries; i++) {
+        /* Don't mount entries that are managed by vold */
+        if (fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) {
+            continue;
         }
 
-        if (fstab[i].fs_mgr_flags & MF_CHECK) {
-            check_fs(fstab[i].blk_dev, fstab[i].type, fstab[i].mnt_point);
+        /* Skip raw partition entries such as boot, recovery, etc */
+        if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
+            !strcmp(fstab->recs[i].fs_type, "mtd")) {
+            continue;
         }
 
-        mret = mount(fstab[i].blk_dev, fstab[i].mnt_point, fstab[i].type,
-                     fstab[i].flags, fstab[i].fs_options);
+        if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
+            wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
+        }
+
+        if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
+            check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
+                     fstab->recs[i].mount_point);
+        }
+
+        mret = mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point,
+                     fstab->recs[i].fs_type, fstab->recs[i].flags,
+                     fstab->recs[i].fs_options);
         if (!mret) {
             /* Success!  Go get the next one */
             continue;
         }
 
         /* mount(2) returned an error, check if it's encrypted and deal with it */
-        if ((fstab[i].fs_mgr_flags & MF_CRYPT) && !partition_wiped(fstab[i].blk_dev)) {
+        if ((fstab->recs[i].fs_mgr_flags & MF_CRYPT) &&
+            !partition_wiped(fstab->recs[i].blk_device)) {
             /* Need to mount a tmpfs at this mountpoint for now, and set
              * properties that vold will query later for decrypting
              */
-            if (mount("tmpfs", fstab[i].mnt_point, "tmpfs",
+            if (mount("tmpfs", fstab->recs[i].mount_point, "tmpfs",
                   MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS) < 0) {
                 ERROR("Cannot mount tmpfs filesystem for encrypted fs at %s\n",
-                        fstab[i].mnt_point);
+                        fstab->recs[i].mount_point);
                 goto out;
             }
             encrypted = 1;
         } else {
             ERROR("Cannot mount filesystem on %s at %s\n",
-                    fstab[i].blk_dev, fstab[i].mnt_point);
+                    fstab->recs[i].blk_device, fstab->recs[i].mount_point);
             goto out;
         }
     }
@@ -497,49 +574,57 @@
     }
 
 out:
-    free_fstab(fstab);
     return ret;
 }
 
-/* If tmp_mnt_point is non-null, mount the filesystem there.  This is for the
+/* If tmp_mount_point is non-null, mount the filesystem there.  This is for the
  * tmp mount we do to check the user password
  */
-int fs_mgr_do_mount(char *fstab_file, char *n_name, char *n_blk_dev, char *tmp_mnt_point)
+int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
+                    char *tmp_mount_point)
 {
     int i = 0;
     int ret = -1;
-    struct fstab_rec *fstab = 0;
     char *m;
 
-    if (!(fstab = read_fstab(fstab_file))) {
+    if (!fstab) {
         return ret;
     }
 
-    for (i = 0; fstab[i].blk_dev; i++) {
-        if (!fs_match(fstab[i].mnt_point, n_name)) {
+    for (i = 0; i < fstab->num_entries; i++) {
+        if (!fs_match(fstab->recs[i].mount_point, n_name)) {
             continue;
         }
 
         /* We found our match */
-        /* First check the filesystem if requested */
-        if (fstab[i].fs_mgr_flags & MF_WAIT) {
-            wait_for_file(fstab[i].blk_dev, WAIT_TIMEOUT);
+        /* If this is a raw partition, report an error */
+        if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
+            !strcmp(fstab->recs[i].fs_type, "mtd")) {
+            ERROR("Cannot mount filesystem of type %s on %s\n",
+                  fstab->recs[i].fs_type, n_blk_device);
+            goto out;
         }
 
-        if (fstab[i].fs_mgr_flags & MF_CHECK) {
-            check_fs(fstab[i].blk_dev, fstab[i].type, fstab[i].mnt_point);
+        /* First check the filesystem if requested */
+        if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
+            wait_for_file(n_blk_device, WAIT_TIMEOUT);
+        }
+
+        if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
+            check_fs(n_blk_device, fstab->recs[i].fs_type,
+                     fstab->recs[i].mount_point);
         }
 
         /* Now mount it where requested */
-        if (tmp_mnt_point) {
-            m = tmp_mnt_point;
+        if (tmp_mount_point) {
+            m = tmp_mount_point;
         } else {
-            m = fstab[i].mnt_point;
+            m = fstab->recs[i].mount_point;
         }
-        if (mount(n_blk_dev, m, fstab[i].type,
-                  fstab[i].flags, fstab[i].fs_options)) {
+        if (mount(n_blk_device, m, fstab->recs[i].fs_type,
+                  fstab->recs[i].flags, fstab->recs[i].fs_options)) {
             ERROR("Cannot mount filesystem on %s at %s\n",
-                    n_blk_dev, m);
+                    n_blk_device, m);
             goto out;
         } else {
             ret = 0;
@@ -548,10 +633,9 @@
     }
 
     /* We didn't find a match, say so and return an error */
-    ERROR("Cannot find mount point %s in fstab\n", fstab[i].mnt_point);
+    ERROR("Cannot find mount point %s in fstab\n", fstab->recs[i].mount_point);
 
 out:
-    free_fstab(fstab);
     return ret;
 }
 
@@ -574,65 +658,128 @@
     return 0;
 }
 
-int fs_mgr_unmount_all(char *fstab_file)
+int fs_mgr_unmount_all(struct fstab *fstab)
 {
     int i = 0;
     int ret = 0;
-    struct fstab_rec *fstab = 0;
 
-    if (!(fstab = read_fstab(fstab_file))) {
+    if (!fstab) {
         return -1;
     }
 
-    while (fstab[i].blk_dev) {
-        if (umount(fstab[i].mnt_point)) {
-            ERROR("Cannot unmount filesystem at %s\n", fstab[i].mnt_point);
+    while (fstab->recs[i].blk_device) {
+        if (umount(fstab->recs[i].mount_point)) {
+            ERROR("Cannot unmount filesystem at %s\n", fstab->recs[i].mount_point);
             ret = -1;
         }
         i++;
     }
 
-    free_fstab(fstab);
     return ret;
 }
 /*
  * key_loc must be at least PROPERTY_VALUE_MAX bytes long
  *
- * real_blk_dev must be at least PROPERTY_VALUE_MAX bytes long
+ * real_blk_device must be at least PROPERTY_VALUE_MAX bytes long
  */
-int fs_mgr_get_crypt_info(char *fstab_file, char *key_loc, char *real_blk_dev, int size)
+int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_device, int size)
 {
     int i = 0;
-    struct fstab_rec *fstab = 0;
 
-    if (!(fstab = read_fstab(fstab_file))) {
+    if (!fstab) {
         return -1;
     }
     /* Initialize return values to null strings */
     if (key_loc) {
         *key_loc = '\0';
     }
-    if (real_blk_dev) {
-        *real_blk_dev = '\0';
+    if (real_blk_device) {
+        *real_blk_device = '\0';
     }
 
     /* Look for the encryptable partition to find the data */
-    for (i = 0; fstab[i].blk_dev; i++) {
-        if (!(fstab[i].fs_mgr_flags & MF_CRYPT)) {
+    for (i = 0; i < fstab->num_entries; i++) {
+        /* Don't deal with vold managed enryptable partitions here */
+        if (fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) {
+            continue;
+        }
+        if (!(fstab->recs[i].fs_mgr_flags & MF_CRYPT)) {
             continue;
         }
 
         /* We found a match */
         if (key_loc) {
-            strlcpy(key_loc, fstab[i].key_loc, size);
+            strlcpy(key_loc, fstab->recs[i].key_loc, size);
         }
-        if (real_blk_dev) {
-            strlcpy(real_blk_dev, fstab[i].blk_dev, size);
+        if (real_blk_device) {
+            strlcpy(real_blk_device, fstab->recs[i].blk_device, size);
         }
         break;
     }
 
-    free_fstab(fstab);
     return 0;
 }
 
+/* Add an entry to the fstab, and return 0 on success or -1 on error */
+int fs_mgr_add_entry(struct fstab *fstab,
+                     const char *mount_point, const char *fs_type,
+                     const char *blk_device, long long length)
+{
+    struct fstab_rec *new_fstab_recs;
+    int n = fstab->num_entries;
+
+    new_fstab_recs = (struct fstab_rec *)
+                     realloc(fstab->recs, sizeof(struct fstab_rec) * (n + 1));
+
+    if (!new_fstab_recs) {
+        return -1;
+    }
+
+    /* A new entry was added, so initialize it */
+     memset(&new_fstab_recs[n], 0, sizeof(struct fstab_rec));
+     new_fstab_recs[n].mount_point = strdup(mount_point);
+     new_fstab_recs[n].fs_type = strdup(fs_type);
+     new_fstab_recs[n].blk_device = strdup(blk_device);
+     new_fstab_recs[n].length = 0;
+
+     /* Update the fstab struct */
+     fstab->recs = new_fstab_recs;
+     fstab->num_entries++;
+
+     return 0;
+}
+
+struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path)
+{
+    int i;
+
+    if (!fstab) {
+        return NULL;
+    }
+
+    for (i = 0; i < fstab->num_entries; i++) {
+        int len = strlen(fstab->recs[i].mount_point);
+        if (strncmp(path, fstab->recs[i].mount_point, len) == 0 &&
+            (path[len] == '\0' || path[len] == '/')) {
+            return &fstab->recs[i];
+        }
+    }
+
+    return NULL;
+}
+
+int fs_mgr_is_voldmanaged(struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_VOLDMANAGED;
+}
+
+int fs_mgr_is_nonremovable(struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_NONREMOVABLE;
+}
+
+int fs_mgr_is_encryptable(struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_CRYPT;
+}
+
diff --git a/fs_mgr/fs_mgr_main.c b/fs_mgr/fs_mgr_main.c
index 81febf1..4bde4a1 100644
--- a/fs_mgr/fs_mgr_main.c
+++ b/fs_mgr/fs_mgr_main.c
@@ -82,7 +82,8 @@
     int n_flag=0;
     char *n_name;
     char *n_blk_dev;
-    char *fstab;
+    char *fstab_file;
+    struct fstab *fstab;
 
     klog_init();
     klog_set_level(6);
@@ -90,7 +91,9 @@
     parse_options(argc, argv, &a_flag, &u_flag, &n_flag, &n_name, &n_blk_dev);
 
     /* The name of the fstab file is last, after the option */
-    fstab = argv[argc - 1];
+    fstab_file = argv[argc - 1];
+
+    fstab = fs_mgr_read_fstab(fstab_file);
 
     if (a_flag) {
         return fs_mgr_mount_all(fstab);
@@ -103,6 +106,8 @@
         exit(1);
     }
 
+    fs_mgr_free_fstab(fstab);
+
     /* Should not get here */
     exit(1);
 }
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 175fdab..f961b39 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -25,17 +25,7 @@
 
 #define CRYPTO_TMPFS_OPTIONS "size=128m,mode=0771,uid=1000,gid=1000"
 
-struct fstab_rec {
-    char *blk_dev;
-    char *mnt_point;
-    char *type;
-    unsigned long flags;
-    char *fs_options;
-    int fs_mgr_flags;
-    char *key_loc;
-};
-
-#define WAIT_TIMEOUT 5
+#define WAIT_TIMEOUT 20
 
 /* fstab has the following format:
  *
@@ -59,8 +49,8 @@
  *                     run an fscheck program on the <source> before mounting the filesystem.
  *                     If check is specifed on a read-only filesystem, it is ignored.
  *                     Also, "encryptable" means that filesystem can be encrypted.
- *                     The "encryptable" flag _MUST_ be followed by a : and a string which
- *                     is the location of the encryption keys.  I can either be a path
+ *                     The "encryptable" flag _MUST_ be followed by a = and a string which
+ *                     is the location of the encryption keys.  It can either be a path
  *                     to a file or partition which contains the keys, or the word "footer"
  *                     which means the keys are in the last 16 Kbytes of the partition
  *                     containing the filesystem.
@@ -72,9 +62,13 @@
  *
  */
 
-#define MF_WAIT      0x1
-#define MF_CHECK     0x2
-#define MF_CRYPT     0x4
+#define MF_WAIT         0x1
+#define MF_CHECK        0x2
+#define MF_CRYPT        0x4
+#define MF_NONREMOVABLE 0x8
+#define MF_VOLDMANAGED  0x10
+#define MF_LENGTH       0x20
+#define MF_RECOVERYONLY 0x40
 
 #endif /* __CORE_FS_MGR_PRIV_H */
 
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 76abb83..05bcc1b 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -17,11 +17,48 @@
 #ifndef __CORE_FS_MGR_H
 #define __CORE_FS_MGR_H
 
-int fs_mgr_mount_all(char *fstab_file);
-int fs_mgr_do_mount(char *fstab_file, char *n_name, char *n_blk_dev, char *tmp_mnt_point);
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct fstab {
+    int num_entries;
+    struct fstab_rec *recs;
+    char *fstab_filename;
+};
+
+struct fstab_rec {
+    char *blk_device;
+    char *mount_point;
+    char *fs_type;
+    unsigned long flags;
+    char *fs_options;
+    int fs_mgr_flags;
+    char *key_loc;
+    long long length;
+    char *label;
+    int partnum;
+};
+
+struct fstab *fs_mgr_read_fstab(const char *fstab_path);
+void fs_mgr_free_fstab(struct fstab *fstab);
+int fs_mgr_mount_all(struct fstab *fstab);
+int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
+                    char *tmp_mount_point);
 int fs_mgr_do_tmpfs_mount(char *n_name);
-int fs_mgr_unmount_all(char *fstab_file);
-int fs_mgr_get_crypt_info(char *fstab_file, char *key_loc, char *real_blk_dev, int size);
+int fs_mgr_unmount_all(struct fstab *fstab);
+int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc,
+                          char *real_blk_device, int size);
+int fs_mgr_add_entry(struct fstab *fstab,
+                     const char *mount_point, const char *fs_type,
+                     const char *blk_device, long long length);
+struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path);
+int fs_mgr_is_voldmanaged(struct fstab_rec *fstab);
+int fs_mgr_is_nonremovable(struct fstab_rec *fstab);
+int fs_mgr_is_encryptable(struct fstab_rec *fstab);
+#ifdef __cplusplus
+}
+#endif
 
 #endif /* __CORE_FS_MGR_H */
 
diff --git a/include/corkscrew/map_info.h b/include/corkscrew/map_info.h
index ea1d35f..14bfad6 100644
--- a/include/corkscrew/map_info.h
+++ b/include/corkscrew/map_info.h
@@ -32,6 +32,7 @@
     uintptr_t start;
     uintptr_t end;
     bool is_readable;
+    bool is_writable;
     bool is_executable;
     void* data; // arbitrary data associated with the map by the user, initially NULL
     char name[];
@@ -46,9 +47,10 @@
 /* Finds the memory map that contains the specified address. */
 const map_info_t* find_map_info(const map_info_t* milist, uintptr_t addr);
 
-/* Returns true if the addr is in an readable map. */
+/* Returns true if the addr is in a readable map. */
 bool is_readable_map(const map_info_t* milist, uintptr_t addr);
-
+/* Returns true if the addr is in a writable map. */
+bool is_writable_map(const map_info_t* milist, uintptr_t addr);
 /* Returns true if the addr is in an executable map. */
 bool is_executable_map(const map_info_t* milist, uintptr_t addr);
 
@@ -61,6 +63,10 @@
  * previous acquired using acquire_my_map_info_list(). */
 void release_my_map_info_list(map_info_t* milist);
 
+/* Flushes the cached memory map so the next call to
+ * acquire_my_map_info_list() gets fresh data. */
+void flush_my_map_info_list();
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/cutils/aref.h b/include/cutils/aref.h
new file mode 100644
index 0000000..460ac02
--- /dev/null
+++ b/include/cutils/aref.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2013 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_AREF_H_
+#define _CUTILS_AREF_H_
+
+#include <stddef.h>
+#include <sys/cdefs.h>
+
+#ifdef ANDROID_SMP
+#include <cutils/atomic-inline.h>
+#else
+#include <cutils/atomic.h>
+#endif
+
+__BEGIN_DECLS
+
+#define AREF_TO_ITEM(aref, container, member) \
+    (container *) (((char*) (aref)) - offsetof(container, member))
+
+struct aref
+{
+    volatile int32_t count;
+};
+
+static inline void aref_init(struct aref *r)
+{
+    r->count = 1;
+}
+
+static inline int32_t aref_count(struct aref *r)
+{
+    return r->count;
+}
+
+static inline void aref_get(struct aref *r)
+{
+    android_atomic_inc(&r->count);
+}
+
+static inline void aref_put(struct aref *r, void (*release)(struct aref *))
+{
+    if (android_atomic_dec(&r->count) == 1)
+        release(r);
+}
+
+__END_DECLS
+
+#endif // _CUTILS_AREF_H_
diff --git a/include/cutils/atomic-arm.h b/include/cutils/atomic-arm.h
index 795afd3..172a0cd 100644
--- a/include/cutils/atomic-arm.h
+++ b/include/cutils/atomic-arm.h
@@ -18,55 +18,33 @@
 #define ANDROID_CUTILS_ATOMIC_ARM_H
 
 #include <stdint.h>
-#include <machine/cpu-features.h>
 
 #ifndef ANDROID_ATOMIC_INLINE
 #define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))
 #endif
 
-extern ANDROID_ATOMIC_INLINE void android_compiler_barrier(void)
+extern ANDROID_ATOMIC_INLINE void android_compiler_barrier()
 {
     __asm__ __volatile__ ("" : : : "memory");
 }
 
+extern ANDROID_ATOMIC_INLINE void android_memory_barrier()
+{
 #if ANDROID_SMP == 0
-extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
-{
     android_compiler_barrier();
-}
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
-{
-    android_compiler_barrier();
-}
-#elif defined(__ARM_HAVE_DMB)
-extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
-{
-    __asm__ __volatile__ ("dmb" : : : "memory");
-}
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
-{
-    __asm__ __volatile__ ("dmb st" : : : "memory");
-}
-#elif defined(__ARM_HAVE_LDREX_STREX)
-extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
-{
-    __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r" (0) : "memory");
-}
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
-{
-    android_memory_barrier();
-}
 #else
-extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
-{
-    typedef void (kuser_memory_barrier)(void);
-    (*(kuser_memory_barrier *)0xffff0fa0)();
-}
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
-{
-    android_memory_barrier();
-}
+    __asm__ __volatile__ ("dmb" : : : "memory");
 #endif
+}
+
+extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier()
+{
+#if ANDROID_SMP == 0
+    android_compiler_barrier();
+#else
+    __asm__ __volatile__ ("dmb st" : : : "memory");
+#endif
+}
 
 extern ANDROID_ATOMIC_INLINE
 int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
@@ -83,32 +61,32 @@
     return *ptr;
 }
 
-extern ANDROID_ATOMIC_INLINE void
-android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
 {
     *ptr = value;
     android_memory_barrier();
 }
 
-extern ANDROID_ATOMIC_INLINE void
-android_atomic_release_store(int32_t value, volatile int32_t *ptr)
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_release_store(int32_t value, volatile int32_t *ptr)
 {
     android_memory_barrier();
     *ptr = value;
 }
 
-#if defined(__thumb__)
-extern int android_atomic_cas(int32_t old_value, int32_t new_value,
-                              volatile int32_t *ptr);
-#elif defined(__ARM_HAVE_LDREX_STREX)
-extern ANDROID_ATOMIC_INLINE int
-android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr)
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_cas(int32_t old_value, int32_t new_value,
+                       volatile int32_t *ptr)
 {
     int32_t prev, status;
     do {
         __asm__ __volatile__ ("ldrex %0, [%3]\n"
                               "mov %1, #0\n"
                               "teq %0, %4\n"
+#ifdef __thumb2__
+                              "it eq\n"
+#endif
                               "strexeq %1, %5, [%3]"
                               : "=&r" (prev), "=&r" (status), "+m"(*ptr)
                               : "r" (ptr), "Ir" (old_value), "r" (new_value)
@@ -116,49 +94,26 @@
     } while (__builtin_expect(status != 0, 0));
     return prev != old_value;
 }
-#else
-extern ANDROID_ATOMIC_INLINE int
-android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr)
-{
-    typedef int (kuser_cmpxchg)(int32_t, int32_t, volatile int32_t *);
-    int32_t prev, status;
-    prev = *ptr;
-    do {
-        status = (*(kuser_cmpxchg *)0xffff0fc0)(old_value, new_value, ptr);
-        if (__builtin_expect(status == 0, 1))
-            return 0;
-        prev = *ptr;
-    } while (prev == old_value);
-    return 1;
-}
-#endif
 
-extern ANDROID_ATOMIC_INLINE int
-android_atomic_acquire_cas(int32_t old_value,
-                           int32_t new_value,
-                           volatile int32_t *ptr)
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_acquire_cas(int32_t old_value, int32_t new_value,
+                               volatile int32_t *ptr)
 {
     int status = android_atomic_cas(old_value, new_value, ptr);
     android_memory_barrier();
     return status;
 }
 
-extern ANDROID_ATOMIC_INLINE int
-android_atomic_release_cas(int32_t old_value,
-                           int32_t new_value,
-                           volatile int32_t *ptr)
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_release_cas(int32_t old_value, int32_t new_value,
+                               volatile int32_t *ptr)
 {
     android_memory_barrier();
     return android_atomic_cas(old_value, new_value, ptr);
 }
 
-
-#if defined(__thumb__)
-extern int32_t android_atomic_add(int32_t increment,
-                                  volatile int32_t *ptr);
-#elif defined(__ARM_HAVE_LDREX_STREX)
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_add(int32_t increment, volatile int32_t *ptr)
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr)
 {
     int32_t prev, tmp, status;
     android_memory_barrier();
@@ -173,19 +128,6 @@
     } while (__builtin_expect(status != 0, 0));
     return prev;
 }
-#else
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_add(int32_t increment, volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    android_memory_barrier();
-    do {
-        prev = *ptr;
-        status = android_atomic_cas(prev, prev + increment, ptr);
-    } while (__builtin_expect(status != 0, 0));
-    return prev;
-}
-#endif
 
 extern ANDROID_ATOMIC_INLINE int32_t android_atomic_inc(volatile int32_t *addr)
 {
@@ -197,11 +139,8 @@
     return android_atomic_add(-1, addr);
 }
 
-#if defined(__thumb__)
-extern int32_t android_atomic_and(int32_t value, volatile int32_t *ptr);
-#elif defined(__ARM_HAVE_LDREX_STREX)
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_and(int32_t value, volatile int32_t *ptr)
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_and(int32_t value, volatile int32_t *ptr)
 {
     int32_t prev, tmp, status;
     android_memory_barrier();
@@ -216,25 +155,9 @@
     } while (__builtin_expect(status != 0, 0));
     return prev;
 }
-#else
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_and(int32_t value, volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    android_memory_barrier();
-    do {
-        prev = *ptr;
-        status = android_atomic_cas(prev, prev & value, ptr);
-    } while (__builtin_expect(status != 0, 0));
-    return prev;
-}
-#endif
 
-#if defined(__thumb__)
-extern int32_t android_atomic_or(int32_t value, volatile int32_t *ptr);
-#elif defined(__ARM_HAVE_LDREX_STREX)
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_or(int32_t value, volatile int32_t *ptr)
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_or(int32_t value, volatile int32_t *ptr)
 {
     int32_t prev, tmp, status;
     android_memory_barrier();
@@ -249,18 +172,5 @@
     } while (__builtin_expect(status != 0, 0));
     return prev;
 }
-#else
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_or(int32_t value, volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    android_memory_barrier();
-    do {
-        prev = *ptr;
-        status = android_atomic_cas(prev, prev | value, ptr);
-    } while (__builtin_expect(status != 0, 0));
-    return prev;
-}
-#endif
 
 #endif /* ANDROID_CUTILS_ATOMIC_ARM_H */
diff --git a/include/cutils/bitops.h b/include/cutils/bitops.h
index 1b3b762..eb44236 100644
--- a/include/cutils/bitops.h
+++ b/include/cutils/bitops.h
@@ -17,10 +17,79 @@
 #ifndef __CUTILS_BITOPS_H
 #define __CUTILS_BITOPS_H
 
+#include <stdbool.h>
+#include <string.h>
+#include <strings.h>
 #include <sys/cdefs.h>
 
 __BEGIN_DECLS
 
+/*
+ * Bitmask Operations
+ *
+ * Note this doesn't provide any locking/exclusion, and isn't atomic.
+ * Additionally no bounds checking is done on the bitmask array.
+ *
+ * Example:
+ *
+ * int num_resources;
+ * unsigned int resource_bits[BITS_TO_WORDS(num_resources)];
+ * bitmask_init(resource_bits, num_resources);
+ * ...
+ * int bit = bitmask_ffz(resource_bits, num_resources);
+ * bitmask_set(resource_bits, bit);
+ * ...
+ * if (bitmask_test(resource_bits, bit)) { ... }
+ * ...
+ * bitmask_clear(resource_bits, bit);
+ *
+ */
+
+#define BITS_PER_WORD    (sizeof(unsigned int) * 8)
+#define BITS_TO_WORDS(x) (((x) + BITS_PER_WORD - 1) / BITS_PER_WORD)
+#define BIT_IN_WORD(x)   ((x) % BITS_PER_WORD)
+#define BIT_WORD(x)      ((x) / BITS_PER_WORD)
+#define BIT_MASK(x)      (1 << BIT_IN_WORD(x))
+
+static inline void bitmask_init(unsigned int *bitmask, int num_bits)
+{
+    memset(bitmask, 0, BITS_TO_WORDS(num_bits)*sizeof(unsigned int));
+}
+
+static inline int bitmask_ffz(unsigned int *bitmask, int num_bits)
+{
+    int bit, result;
+    unsigned int i;
+
+    for (i = 0; i < BITS_TO_WORDS(num_bits); i++) {
+        bit = ffs(~bitmask[i]);
+        if (bit) {
+            // ffs is 1-indexed, return 0-indexed result
+            bit--;
+            result = BITS_PER_WORD * i + bit;
+            if (result >= num_bits)
+                return -1;
+            return result;
+        }
+    }
+    return -1;
+}
+
+static inline void bitmask_set(unsigned int *bitmask, int bit)
+{
+    bitmask[BIT_WORD(bit)] |= BIT_MASK(bit);
+}
+
+static inline void bitmask_clear(unsigned int *bitmask, int bit)
+{
+    bitmask[BIT_WORD(bit)] &= ~BIT_MASK(bit);
+}
+
+static inline bool bitmask_test(unsigned int *bitmask, int bit)
+{
+    return bitmask[BIT_WORD(bit)] & BIT_MASK(bit);
+}
+
 static inline int popcount(unsigned int x)
 {
     return __builtin_popcount(x);
diff --git a/include/cutils/debugger.h b/include/cutils/debugger.h
index 5a8e796..4eda523 100644
--- a/include/cutils/debugger.h
+++ b/include/cutils/debugger.h
@@ -34,10 +34,10 @@
     DEBUGGER_ACTION_DUMP_BACKTRACE,
 } debugger_action_t;
 
-/* message sent over the socket */
 typedef struct {
     debugger_action_t action;
     pid_t tid;
+    uintptr_t abort_msg_address;
 } debugger_msg_t;
 
 /* Dumps a process backtrace, registers, and stack to a tombstone file (requires root).
diff --git a/include/cutils/klog.h b/include/cutils/klog.h
index 1335543..ba728ac 100644
--- a/include/cutils/klog.h
+++ b/include/cutils/klog.h
@@ -17,12 +17,18 @@
 #ifndef _CUTILS_KLOG_H_
 #define _CUTILS_KLOG_H_
 
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
 void klog_init(void);
 void klog_set_level(int level);
 void klog_close(void);
 void klog_write(int level, const char *fmt, ...)
     __attribute__ ((format(printf, 2, 3)));
 
+__END_DECLS
+
 #define KLOG_ERROR(tag,x...)   klog_write(3, "<3>" tag ": " x)
 #define KLOG_WARNING(tag,x...) klog_write(4, "<4>" tag ": " x)
 #define KLOG_NOTICE(tag,x...)  klog_write(5, "<5>" tag ": " x)
diff --git a/include/cutils/log.h b/include/cutils/log.h
index 878952e..8b045c7 100644
--- a/include/cutils/log.h
+++ b/include/cutils/log.h
@@ -279,7 +279,88 @@
     : (void)0 )
 #endif
 
-    
+// ---------------------------------------------------------------------
+
+/*
+ * Simplified macro to send a verbose radio log message using the current LOG_TAG.
+ */
+#ifndef RLOGV
+#if LOG_NDEBUG
+#define RLOGV(...)   ((void)0)
+#else
+#define RLOGV(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#endif
+#endif
+
+#define CONDITION(cond)     (__builtin_expect((cond)!=0, 0))
+
+#ifndef RLOGV_IF
+#if LOG_NDEBUG
+#define RLOGV_IF(cond, ...)   ((void)0)
+#else
+#define RLOGV_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+#endif
+
+/*
+ * Simplified macro to send a debug radio log message using the current LOG_TAG.
+ */
+#ifndef RLOGD
+#define RLOGD(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGD_IF
+#define RLOGD_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an info radio log message using the current LOG_TAG.
+ */
+#ifndef RLOGI
+#define RLOGI(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGI_IF
+#define RLOGI_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send a warning radio log message using the current LOG_TAG.
+ */
+#ifndef RLOGW
+#define RLOGW(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGW_IF
+#define RLOGW_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an error radio log message using the current LOG_TAG.
+ */
+#ifndef RLOGE
+#define RLOGE(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef RLOGE_IF
+#define RLOGE_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
 
 // ---------------------------------------------------------------------
 
diff --git a/include/cutils/trace.h b/include/cutils/trace.h
new file mode 100644
index 0000000..29034ca
--- /dev/null
+++ b/include/cutils/trace.h
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2012 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 _LIBS_CUTILS_TRACE_H
+#define _LIBS_CUTILS_TRACE_H
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <cutils/compiler.h>
+
+#ifdef ANDROID_SMP
+#include <cutils/atomic-inline.h>
+#else
+#include <cutils/atomic.h>
+#endif
+
+__BEGIN_DECLS
+
+/**
+ * The ATRACE_TAG macro can be defined before including this header to trace
+ * using one of the tags defined below.  It must be defined to one of the
+ * following ATRACE_TAG_* macros.  The trace tag is used to filter tracing in
+ * userland to avoid some of the runtime cost of tracing when it is not desired.
+ *
+ * Defining ATRACE_TAG to be ATRACE_TAG_ALWAYS will result in the tracing always
+ * being enabled - this should ONLY be done for debug code, as userland tracing
+ * has a performance cost even when the trace is not being recorded.  Defining
+ * ATRACE_TAG to be ATRACE_TAG_NEVER or leaving ATRACE_TAG undefined will result
+ * in the tracing always being disabled.
+ *
+ * ATRACE_TAG_HAL should be bitwise ORed with the relevant tags for tracing
+ * within a hardware module.  For example a camera hardware module would set:
+ * #define ATRACE_TAG  (ATRACE_TAG_CAMERA | ATRACE_TAG_HAL)
+ *
+ * Keep these in sync with frameworks/base/core/java/android/os/Trace.java.
+ */
+#define ATRACE_TAG_NEVER            0       // This tag is never enabled.
+#define ATRACE_TAG_ALWAYS           (1<<0)  // This tag is always enabled.
+#define ATRACE_TAG_GRAPHICS         (1<<1)
+#define ATRACE_TAG_INPUT            (1<<2)
+#define ATRACE_TAG_VIEW             (1<<3)
+#define ATRACE_TAG_WEBVIEW          (1<<4)
+#define ATRACE_TAG_WINDOW_MANAGER   (1<<5)
+#define ATRACE_TAG_ACTIVITY_MANAGER (1<<6)
+#define ATRACE_TAG_SYNC_MANAGER     (1<<7)
+#define ATRACE_TAG_AUDIO            (1<<8)
+#define ATRACE_TAG_VIDEO            (1<<9)
+#define ATRACE_TAG_CAMERA           (1<<10)
+#define ATRACE_TAG_HAL              (1<<11)
+#define ATRACE_TAG_APP              (1<<12)
+#define ATRACE_TAG_RESOURCES        (1<<13)
+#define ATRACE_TAG_DALVIK           (1<<14)
+#define ATRACE_TAG_LAST             ATRACE_TAG_DALVIK
+
+// Reserved for initialization.
+#define ATRACE_TAG_NOT_READY        (1LL<<63)
+
+#define ATRACE_TAG_VALID_MASK ((ATRACE_TAG_LAST - 1) | ATRACE_TAG_LAST)
+
+#ifndef ATRACE_TAG
+#define ATRACE_TAG ATRACE_TAG_NEVER
+#elif ATRACE_TAG > ATRACE_TAG_VALID_MASK
+#error ATRACE_TAG must be defined to be one of the tags defined in cutils/trace.h
+#endif
+
+#ifdef HAVE_ANDROID_OS
+/**
+ * Maximum size of a message that can be logged to the trace buffer.
+ * Note this message includes a tag, the pid, and the string given as the name.
+ * Names should be kept short to get the most use of the trace buffer.
+ */
+#define ATRACE_MESSAGE_LENGTH 1024
+
+/**
+ * Opens the trace file for writing and reads the property for initial tags.
+ * The atrace.tags.enableflags property sets the tags to trace.
+ * This function should not be explicitly called, the first call to any normal
+ * trace function will cause it to be run safely.
+ */
+void atrace_setup();
+
+/**
+ * If tracing is ready, set atrace_enabled_tags to the system property
+ * debug.atrace.tags.enableflags. Can be used as a sysprop change callback.
+ */
+void atrace_update_tags();
+
+/**
+ * Set whether the process is debuggable.  By default the process is not
+ * considered debuggable.  If the process is not debuggable then application-
+ * level tracing is not allowed unless the ro.debuggable system property is
+ * set to '1'.
+ */
+void atrace_set_debuggable(bool debuggable);
+
+/**
+ * Set whether tracing is enabled for the current process.  This is used to
+ * prevent tracing within the Zygote process.
+ */
+void atrace_set_tracing_enabled(bool enabled);
+
+/**
+ * Flag indicating whether setup has been completed, initialized to 0.
+ * Nonzero indicates setup has completed.
+ * Note: This does NOT indicate whether or not setup was successful.
+ */
+extern volatile int32_t atrace_is_ready;
+
+/**
+ * Set of ATRACE_TAG flags to trace for, initialized to ATRACE_TAG_NOT_READY.
+ * A value of zero indicates setup has failed.
+ * Any other nonzero value indicates setup has succeeded, and tracing is on.
+ */
+extern uint64_t atrace_enabled_tags;
+
+/**
+ * Handle to the kernel's trace buffer, initialized to -1.
+ * Any other value indicates setup has succeeded, and is a valid fd for tracing.
+ */
+extern int atrace_marker_fd;
+
+/**
+ * atrace_init readies the process for tracing by opening the trace_marker file.
+ * Calling any trace function causes this to be run, so calling it is optional.
+ * This can be explicitly run to avoid setup delay on first trace function.
+ */
+#define ATRACE_INIT() atrace_init()
+static inline void atrace_init()
+{
+    if (CC_UNLIKELY(!android_atomic_acquire_load(&atrace_is_ready))) {
+        atrace_setup();
+    }
+}
+
+/**
+ * Get the mask of all tags currently enabled.
+ * It can be used as a guard condition around more expensive trace calculations.
+ * Every trace function calls this, which ensures atrace_init is run.
+ */
+#define ATRACE_GET_ENABLED_TAGS() atrace_get_enabled_tags()
+static inline uint64_t atrace_get_enabled_tags()
+{
+    atrace_init();
+    return atrace_enabled_tags;
+}
+
+/**
+ * Test if a given tag is currently enabled.
+ * Returns nonzero if the tag is enabled, otherwise zero.
+ * It can be used as a guard condition around more expensive trace calculations.
+ */
+#define ATRACE_ENABLED() atrace_is_tag_enabled(ATRACE_TAG)
+static inline uint64_t atrace_is_tag_enabled(uint64_t tag)
+{
+    return atrace_get_enabled_tags() & tag;
+}
+
+/**
+ * Trace the beginning of a context.  name is used to identify the context.
+ * This is often used to time function execution.
+ */
+#define ATRACE_BEGIN(name) atrace_begin(ATRACE_TAG, name)
+static inline void atrace_begin(uint64_t tag, const char* name)
+{
+    if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
+        char buf[ATRACE_MESSAGE_LENGTH];
+        size_t len;
+
+        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "B|%d|%s", getpid(), name);
+        write(atrace_marker_fd, buf, len);
+    }
+}
+
+/**
+ * Trace the end of a context.
+ * This should match up (and occur after) a corresponding ATRACE_BEGIN.
+ */
+#define ATRACE_END() atrace_end(ATRACE_TAG)
+static inline void atrace_end(uint64_t tag)
+{
+    if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
+        char c = 'E';
+        write(atrace_marker_fd, &c, 1);
+    }
+}
+
+/**
+ * Trace the beginning of an asynchronous event. Unlike ATRACE_BEGIN/ATRACE_END
+ * contexts, asynchronous events do not need to be nested. The name describes
+ * the event, and the cookie provides a unique identifier for distinguishing
+ * simultaneous events. The name and cookie used to begin an event must be
+ * used to end it.
+ */
+#define ATRACE_ASYNC_BEGIN(name, cookie) \
+    atrace_async_begin(ATRACE_TAG, name, cookie)
+static inline void atrace_async_begin(uint64_t tag, const char* name,
+        int32_t cookie)
+{
+    if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
+        char buf[ATRACE_MESSAGE_LENGTH];
+        size_t len;
+
+        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "S|%d|%s|%d", getpid(),
+                name, cookie);
+        write(atrace_marker_fd, buf, len);
+    }
+}
+
+/**
+ * Trace the end of an asynchronous event.
+ * This should have a corresponding ATRACE_ASYNC_BEGIN.
+ */
+#define ATRACE_ASYNC_END(name, cookie) atrace_async_end(ATRACE_TAG, name, cookie)
+static inline void atrace_async_end(uint64_t tag, const char* name,
+        int32_t cookie)
+{
+    if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
+        char buf[ATRACE_MESSAGE_LENGTH];
+        size_t len;
+
+        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "F|%d|%s|%d", getpid(),
+                name, cookie);
+        write(atrace_marker_fd, buf, len);
+    }
+}
+
+
+/**
+ * Traces an integer counter value.  name is used to identify the counter.
+ * This can be used to track how a value changes over time.
+ */
+#define ATRACE_INT(name, value) atrace_int(ATRACE_TAG, name, value)
+static inline void atrace_int(uint64_t tag, const char* name, int32_t value)
+{
+    if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
+        char buf[ATRACE_MESSAGE_LENGTH];
+        size_t len;
+
+        len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%d",
+                getpid(), name, value);
+        write(atrace_marker_fd, buf, len);
+    }
+}
+
+#else // not HAVE_ANDROID_OS
+
+#define ATRACE_INIT()
+#define ATRACE_GET_ENABLED_TAGS()
+#define ATRACE_ENABLED()
+#define ATRACE_BEGIN(name)
+#define ATRACE_END()
+#define ATRACE_ASYNC_BEGIN(name, cookie)
+#define ATRACE_ASYNC_END(name, cookie)
+#define ATRACE_INT(name, value)
+
+#endif // not HAVE_ANDROID_OS
+
+__END_DECLS
+
+#endif // _LIBS_CUTILS_TRACE_H
diff --git a/include/cutils/tztime.h b/include/cutils/tztime.h
index 36ac25d..dbdbd60 100644
--- a/include/cutils/tztime.h
+++ b/include/cutils/tztime.h
@@ -17,45 +17,8 @@
 #ifndef _CUTILS_TZTIME_H
 #define _CUTILS_TZTIME_H
 
-#include <time.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-time_t mktime_tz(struct tm * const tmp, char const * tz);
-void localtime_tz(const time_t * const timep, struct tm * tmp, const char* tz);
-
-#ifdef HAVE_ANDROID_OS
-
-/* the following is defined in the Bionic C library on Android, but the
- * declarations are only available through a platform-private header
- */
+// TODO: fix both callers to just include <bionic_time.h> themselves.
 #include <bionic_time.h>
 
-#else /* !HAVE_ANDROID_OS */
-
-struct strftime_locale {
-    const char *mon[12];    /* short names */
-    const char *month[12];  /* long names */
-    const char *standalone_month[12];  /* long standalone names */
-    const char *wday[7];    /* short names */
-    const char *weekday[7]; /* long names */
-    const char *X_fmt;
-    const char *x_fmt;
-    const char *c_fmt;
-    const char *am;
-    const char *pm;
-    const char *date_fmt;
-};
-
-size_t strftime_tz(char *s, size_t max, const char *format, const struct tm *tm, const struct strftime_locale *locale);
-
-#endif /* !HAVE_ANDROID_OS */
-
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* __CUTILS_TZTIME_H */ 
 
diff --git a/include/cutils/zygote.h b/include/cutils/zygote.h
index 22721a6..a7480d3 100644
--- a/include/cutils/zygote.h
+++ b/include/cutils/zygote.h
@@ -23,7 +23,6 @@
 
 int zygote_run_oneshot(int sendStdio, int argc, const char **argv);
 int zygote_run(int argc, const char **argv);
-int zygote_run_wait(int argc, const char **argv, void (*post_run_func)(int));
 
 #ifdef __cplusplus
 }
diff --git a/include/netutils/dhcp.h b/include/netutils/dhcp.h
index d25e58f..bd2c957 100644
--- a/include/netutils/dhcp.h
+++ b/include/netutils/dhcp.h
@@ -27,11 +27,18 @@
                           char *ipaddr,
                           char *gateway,
                           uint32_t *prefixLength,
-                          char *dns1,
-                          char *dns2,
+                          char *dns[],
                           char *server,
                           uint32_t *lease,
                           char *vendorInfo);
+extern int dhcp_do_request_renew(const char *ifname,
+                                char *ipaddr,
+                                char *gateway,
+                                uint32_t *prefixLength,
+                                char *dns[],
+                                char *server,
+                                uint32_t *lease,
+                                char *vendorInfo);
 extern int dhcp_stop(const char *ifname);
 extern int dhcp_release_lease(const char *ifname);
 extern char *dhcp_get_errmsg();
diff --git a/include/private/android_filesystem_capability.h b/include/private/android_filesystem_capability.h
new file mode 100644
index 0000000..0505cda
--- /dev/null
+++ b/include/private/android_filesystem_capability.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+/*
+ * Taken from linux/capability.h, with minor modifications
+ */
+
+#ifndef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_FILESYSTEM_CAPABILITY_H
+#define _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_FILESYSTEM_CAPABILITY_H
+
+#include <stdint.h>
+
+#define __user
+#define __u32 uint32_t
+#define __le32 uint32_t
+
+#define _LINUX_CAPABILITY_VERSION_1 0x19980330
+#define _LINUX_CAPABILITY_U32S_1 1
+#define _LINUX_CAPABILITY_VERSION_2 0x20071026
+#define _LINUX_CAPABILITY_U32S_2 2
+#define _LINUX_CAPABILITY_VERSION_3 0x20080522
+#define _LINUX_CAPABILITY_U32S_3 2
+
+typedef struct __user_cap_header_struct {
+ __u32 version;
+ int pid;
+} __user *cap_user_header_t;
+
+typedef struct __user_cap_data_struct {
+ __u32 effective;
+ __u32 permitted;
+ __u32 inheritable;
+} __user *cap_user_data_t;
+
+#define VFS_CAP_REVISION_MASK 0xFF000000
+#define VFS_CAP_REVISION_SHIFT 24
+#define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK
+#define VFS_CAP_FLAGS_EFFECTIVE 0x000001
+#define VFS_CAP_REVISION_1 0x01000000
+#define VFS_CAP_U32_1 1
+#define XATTR_CAPS_SZ_1 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_1))
+#define VFS_CAP_REVISION_2 0x02000000
+#define VFS_CAP_U32_2 2
+#define XATTR_CAPS_SZ_2 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_2))
+#define XATTR_CAPS_SZ XATTR_CAPS_SZ_2
+#define VFS_CAP_U32 VFS_CAP_U32_2
+#define VFS_CAP_REVISION VFS_CAP_REVISION_2
+
+struct vfs_cap_data {
+ __le32 magic_etc;
+ struct {
+ __le32 permitted;
+ __le32 inheritable;
+ } data[VFS_CAP_U32];
+};
+
+#define _LINUX_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_1
+#define _LINUX_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_1
+#define CAP_CHOWN 0
+#define CAP_DAC_OVERRIDE 1
+#define CAP_DAC_READ_SEARCH 2
+#define CAP_FOWNER 3
+#define CAP_FSETID 4
+#define CAP_KILL 5
+#define CAP_SETGID 6
+#define CAP_SETUID 7
+#define CAP_SETPCAP 8
+#define CAP_LINUX_IMMUTABLE 9
+#define CAP_NET_BIND_SERVICE 10
+#define CAP_NET_BROADCAST 11
+#define CAP_NET_ADMIN 12
+#define CAP_NET_RAW 13
+#define CAP_IPC_LOCK 14
+#define CAP_IPC_OWNER 15
+#define CAP_SYS_MODULE 16
+#define CAP_SYS_RAWIO 17
+#define CAP_SYS_CHROOT 18
+#define CAP_SYS_PTRACE 19
+#define CAP_SYS_PACCT 20
+#define CAP_SYS_ADMIN 21
+#define CAP_SYS_BOOT 22
+#define CAP_SYS_NICE 23
+#define CAP_SYS_RESOURCE 24
+#define CAP_SYS_TIME 25
+#define CAP_SYS_TTY_CONFIG 26
+#define CAP_MKNOD 27
+#define CAP_LEASE 28
+#define CAP_AUDIT_WRITE 29
+#define CAP_AUDIT_CONTROL 30
+#define CAP_SETFCAP 31
+#define CAP_MAC_OVERRIDE 32
+#define CAP_MAC_ADMIN 33
+#define CAP_SYSLOG 34
+#define CAP_WAKE_ALARM 35
+#define CAP_LAST_CAP CAP_WAKE_ALARM
+#define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
+#define CAP_TO_INDEX(x) ((x) >> 5)
+#define CAP_TO_MASK(x) (1 << ((x) & 31))
+
+#undef __user
+#undef __u32
+#undef __le32
+
+#endif
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 3a2500e..5d363a7 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -25,6 +25,13 @@
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <stdint.h>
+
+#ifdef HAVE_ANDROID_OS
+#include <linux/capability.h>
+#else
+#include "android_filesystem_capability.h"
+#endif
 
 /* This is the master Users and Groups config for the platform.
 ** DO NOT EVER RENUMBER.
@@ -63,6 +70,8 @@
 #define AID_NFC           1027  /* nfc subsystem */
 #define AID_SDCARD_R      1028  /* external storage read access */
 #define AID_CLAT          1029  /* clat part of nat464 */
+#define AID_LOOP_RADIO    1030  /* loop radio devices */
+#define AID_MEDIA_DRM     1031  /* MediaDrm plugins */
 
 #define AID_SHELL         2000  /* adb and debug shell user */
 #define AID_CACHE         2001  /* cache access */
@@ -138,9 +147,11 @@
     { "net_admin", AID_NET_ADMIN, },
     { "net_bw_stats", AID_NET_BW_STATS, },
     { "net_bw_acct", AID_NET_BW_ACCT, },
+    { "loop_radio", AID_LOOP_RADIO, },
     { "misc",      AID_MISC, },
     { "nobody",    AID_NOBODY, },
     { "clat",      AID_CLAT, },
+    { "mediadrm",  AID_MEDIA_DRM, },
 };
 
 #define android_id_count \
@@ -150,6 +161,7 @@
     unsigned mode;
     unsigned uid;
     unsigned gid;
+    uint64_t capabilities;
     const char *prefix;
 };
 
@@ -159,26 +171,27 @@
 ** way up to the root.
 */
 
-static struct fs_path_config android_dirs[] = {
-    { 00770, AID_SYSTEM, AID_CACHE,  "cache" },
-    { 00771, AID_SYSTEM, AID_SYSTEM, "data/app" },
-    { 00771, AID_SYSTEM, AID_SYSTEM, "data/app-private" },
-    { 00771, AID_SYSTEM, AID_SYSTEM, "data/dalvik-cache" },
-    { 00771, AID_SYSTEM, AID_SYSTEM, "data/data" },
-    { 00771, AID_SHELL,  AID_SHELL,  "data/local/tmp" },
-    { 00771, AID_SHELL,  AID_SHELL,  "data/local" },
-    { 01771, AID_SYSTEM, AID_MISC,   "data/misc" },
-    { 00770, AID_DHCP,   AID_DHCP,   "data/misc/dhcp" },
-    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, "data/media" },
-    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, "data/media/Music" },
-    { 00771, AID_SYSTEM, AID_SYSTEM, "data" },
-    { 00750, AID_ROOT,   AID_SHELL,  "sbin" },
-    { 00755, AID_ROOT,   AID_SHELL,  "system/bin" },
-    { 00755, AID_ROOT,   AID_SHELL,  "system/vendor" },
-    { 00755, AID_ROOT,   AID_SHELL,  "system/xbin" },
-    { 00755, AID_ROOT,   AID_ROOT,   "system/etc/ppp" },
-    { 00777, AID_ROOT,   AID_ROOT,   "sdcard" },
-    { 00755, AID_ROOT,   AID_ROOT,   0 },
+static const struct fs_path_config android_dirs[] = {
+    { 00770, AID_SYSTEM, AID_CACHE,  0, "cache" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/dalvik-cache" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" },
+    { 00771, AID_SHELL,  AID_SHELL,  0, "data/local/tmp" },
+    { 00771, AID_SHELL,  AID_SHELL,  0, "data/local" },
+    { 01771, AID_SYSTEM, AID_MISC,   0, "data/misc" },
+    { 00770, AID_DHCP,   AID_DHCP,   0, "data/misc/dhcp" },
+    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" },
+    { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" },
+    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" },
+    { 00750, AID_ROOT,   AID_SHELL,  0, "sbin" },
+    { 00755, AID_ROOT,   AID_SHELL,  0, "system/bin" },
+    { 00755, AID_ROOT,   AID_SHELL,  0, "system/vendor" },
+    { 00755, AID_ROOT,   AID_SHELL,  0, "system/xbin" },
+    { 00755, AID_ROOT,   AID_ROOT,   0, "system/etc/ppp" },
+    { 00755, AID_ROOT,   AID_SHELL,  0, "vendor" },
+    { 00777, AID_ROOT,   AID_ROOT,   0, "sdcard" },
+    { 00755, AID_ROOT,   AID_ROOT,   0, 0 },
 };
 
 /* Rules for files.
@@ -187,55 +200,62 @@
 ** way up to the root. Prefixes ending in * denotes wildcard
 ** and will allow partial matches.
 */
-static struct fs_path_config android_files[] = {
-    { 00440, AID_ROOT,      AID_SHELL,     "system/etc/init.goldfish.rc" },
-    { 00550, AID_ROOT,      AID_SHELL,     "system/etc/init.goldfish.sh" },
-    { 00440, AID_ROOT,      AID_SHELL,     "system/etc/init.trout.rc" },
-    { 00550, AID_ROOT,      AID_SHELL,     "system/etc/init.ril" },
-    { 00550, AID_ROOT,      AID_SHELL,     "system/etc/init.testmenu" },
-    { 00550, AID_DHCP,      AID_SHELL,     "system/etc/dhcpcd/dhcpcd-run-hooks" },
-    { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/dbus.conf" },
-    { 00444, AID_RADIO,     AID_AUDIO,     "system/etc/AudioPara4.csv" },
-    { 00555, AID_ROOT,      AID_ROOT,      "system/etc/ppp/*" },
-    { 00555, AID_ROOT,      AID_ROOT,      "system/etc/rc.*" },
-    { 00644, AID_SYSTEM,    AID_SYSTEM,    "data/app/*" },
-    { 00644, AID_MEDIA_RW,  AID_MEDIA_RW,  "data/media/*" },
-    { 00644, AID_SYSTEM,    AID_SYSTEM,    "data/app-private/*" },
-    { 00644, AID_APP,       AID_APP,       "data/data/*" },
-        /* the following two files are INTENTIONALLY set-gid and not set-uid.
-         * Do not change. */
-    { 02755, AID_ROOT,      AID_NET_RAW,   "system/bin/ping" },
-    { 02750, AID_ROOT,      AID_INET,      "system/bin/netcfg" },
-    	/* the following five files are INTENTIONALLY set-uid, but they
-	 * are NOT included on user builds. */
-    { 06755, AID_ROOT,      AID_ROOT,      "system/xbin/su" },
-    { 06755, AID_ROOT,      AID_ROOT,      "system/xbin/librank" },
-    { 06755, AID_ROOT,      AID_ROOT,      "system/xbin/procrank" },
-    { 06755, AID_ROOT,      AID_ROOT,      "system/xbin/procmem" },
-    { 06755, AID_ROOT,      AID_ROOT,      "system/xbin/tcpdump" },
-    { 04770, AID_ROOT,      AID_RADIO,     "system/bin/pppd-ril" },
-		/* the following file is INTENTIONALLY set-uid, and IS included
-		 * 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/*" },
-    { 00755, AID_ROOT,      AID_ROOT,      "bin/*" },
-    { 00750, AID_ROOT,      AID_SHELL,     "init*" },
-    { 00750, AID_ROOT,      AID_SHELL,     "charger*" },
-    { 00750, AID_ROOT,      AID_SHELL,     "sbin/fs_mgr" },
-    { 00640, AID_ROOT,      AID_SHELL,     "fstab.*" },
-    { 00644, AID_ROOT,      AID_ROOT,       0 },
+static const struct fs_path_config android_files[] = {
+    { 00440, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.rc" },
+    { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.sh" },
+    { 00440, AID_ROOT,      AID_SHELL,     0, "system/etc/init.trout.rc" },
+    { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.ril" },
+    { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.testmenu" },
+    { 00550, AID_DHCP,      AID_SHELL,     0, "system/etc/dhcpcd/dhcpcd-run-hooks" },
+    { 00444, AID_RADIO,     AID_AUDIO,     0, "system/etc/AudioPara4.csv" },
+    { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/ppp/*" },
+    { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/rc.*" },
+    { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app/*" },
+    { 00644, AID_MEDIA_RW,  AID_MEDIA_RW,  0, "data/media/*" },
+    { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app-private/*" },
+    { 00644, AID_APP,       AID_APP,       0, "data/data/*" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "system/bin/ping" },
+
+    /* the following file is INTENTIONALLY set-gid and not set-uid.
+     * Do not change. */
+    { 02750, AID_ROOT,      AID_INET,      0, "system/bin/netcfg" },
+
+    /* the following five files are INTENTIONALLY set-uid, but they
+     * are NOT included on user builds. */
+    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/su" },
+    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/librank" },
+    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procrank" },
+    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procmem" },
+    { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/tcpdump" },
+    { 04770, AID_ROOT,      AID_RADIO,     0, "system/bin/pppd-ril" },
+
+    /* the following file has enhanced capabilities and IS included in user builds. */
+    { 00750, AID_ROOT,      AID_SHELL,     (1 << CAP_SETUID) | (1 << CAP_SETGID), "system/bin/run-as" },
+
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib/valgrind/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/xbin/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system/vendor/bin/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/bin/*" },
+    { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/*" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "bin/*" },
+    { 00750, AID_ROOT,      AID_SHELL,     0, "init*" },
+    { 00750, AID_ROOT,      AID_SHELL,     0, "charger*" },
+    { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/fs_mgr" },
+    { 00640, AID_ROOT,      AID_SHELL,     0, "fstab.*" },
+    { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
 };
 
 static inline void fs_config(const char *path, int dir,
-                             unsigned *uid, unsigned *gid, unsigned *mode)
+                             unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities)
 {
-    struct fs_path_config *pc;
+    const struct fs_path_config *pc;
     int plen;
 
+    if (path[0] == '/') {
+        path++;
+    }
+
     pc = dir ? android_dirs : android_files;
     plen = strlen(path);
     for(; pc->prefix; pc++){
@@ -255,6 +275,7 @@
     *uid = pc->uid;
     *gid = pc->gid;
     *mode = (*mode & (~07777)) | pc->mode;
+    *capabilities = pc->capabilities;
 
 #if 0
     fprintf(stderr,"< '%s' '%s' %d %d %o >\n",
diff --git a/include/sync/sw_sync.h b/include/sync/sw_sync.h
new file mode 100644
index 0000000..3bf4110
--- /dev/null
+++ b/include/sync/sw_sync.h
@@ -0,0 +1,37 @@
+/*
+ *  sw_sync.h
+ *
+ *   Copyright 2013 Google, Inc
+ *
+ *  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 __SYS_CORE_SW_SYNC_H
+#define __SYS_CORE_SW_SYNC_H
+
+#include "sync.h"
+
+__BEGIN_DECLS
+
+/*
+ * sw_sync is mainly intended for testing and should not be compiled into
+ * production kernels
+ */
+
+int sw_sync_timeline_create(void);
+int sw_sync_timeline_inc(int fd, unsigned count);
+int sw_sync_fence_create(int fd, const char *name, unsigned value);
+
+__END_DECLS
+
+#endif /* __SYS_CORE_SW_SYNC_H */
diff --git a/include/sync/sync.h b/include/sync/sync.h
index 918acf6..2e5d82f 100644
--- a/include/sync/sync.h
+++ b/include/sync/sync.h
@@ -49,14 +49,6 @@
                                   struct sync_pt_info *itr);
 void sync_fence_info_free(struct sync_fence_info_data *info);
 
-/* sw_sync is mainly inteded for testing and should not be complied into
- * production kernels
- */
-
-int sw_sync_timeline_create(void);
-int sw_sync_timeline_inc(int fd, unsigned count);
-int sw_sync_fence_create(int fd, const char *name, unsigned value);
-
 __END_DECLS
 
 #endif /* __SYS_CORE_SYNC_H */
diff --git a/include/system/audio.h b/include/system/audio.h
index d246070..da235dd 100644
--- a/include/system/audio.h
+++ b/include/system/audio.h
@@ -239,6 +239,7 @@
 
     AUDIO_CHANNEL_IN_MONO   = AUDIO_CHANNEL_IN_FRONT,
     AUDIO_CHANNEL_IN_STEREO = (AUDIO_CHANNEL_IN_LEFT | AUDIO_CHANNEL_IN_RIGHT),
+    AUDIO_CHANNEL_IN_FRONT_BACK = (AUDIO_CHANNEL_IN_FRONT | AUDIO_CHANNEL_IN_BACK),
     AUDIO_CHANNEL_IN_ALL    = (AUDIO_CHANNEL_IN_LEFT |
                                AUDIO_CHANNEL_IN_RIGHT |
                                AUDIO_CHANNEL_IN_FRONT |
diff --git a/include/system/graphics.h b/include/system/graphics.h
index 82b5fcc..ed493f5 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -17,6 +17,8 @@
 #ifndef SYSTEM_CORE_INCLUDE_ANDROID_GRAPHICS_H
 #define SYSTEM_CORE_INCLUDE_ANDROID_GRAPHICS_H
 
+#include <stdint.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -87,6 +89,54 @@
      */
     HAL_PIXEL_FORMAT_YV12   = 0x32315659, // YCrCb 4:2:0 Planar
 
+
+    /*
+     * Android Y8 format:
+     *
+     * This format is exposed outside of the HAL to the framework.
+     * The expected gralloc usage flags are SW_* and HW_CAMERA_*,
+     * and no other HW_ flags will be used.
+     *
+     * Y8 is a YUV planar format comprised of a WxH Y plane,
+     * with each pixel being represented by 8 bits.
+     *
+     * It is equivalent to just the Y plane from YV12.
+     *
+     * This format assumes
+     * - an even width
+     * - an even height
+     * - a horizontal stride multiple of 16 pixels
+     * - a vertical stride equal to the height
+     *
+     *   size = stride * height
+     *
+     */
+    HAL_PIXEL_FORMAT_Y8     = 0x20203859,
+
+    /*
+     * Android Y16 format:
+     *
+     * This format is exposed outside of the HAL to the framework.
+     * The expected gralloc usage flags are SW_* and HW_CAMERA_*,
+     * and no other HW_ flags will be used.
+     *
+     * Y16 is a YUV planar format comprised of a WxH Y plane,
+     * with each pixel being represented by 16 bits.
+     *
+     * It is just like Y8, but has double the bits per pixel (little endian).
+     *
+     * This format assumes
+     * - an even width
+     * - an even height
+     * - a horizontal stride multiple of 16 pixels
+     * - a vertical stride equal to the height
+     * - strides are specified in pixels, not in bytes
+     *
+     *   size = stride * height * 2
+     *
+     */
+    HAL_PIXEL_FORMAT_Y16    = 0x20363159,
+
     /*
      * Android RAW sensor format:
      *
@@ -140,12 +190,64 @@
      */
     HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22,
 
+    /*
+     * Android flexible YCbCr formats
+     *
+     * This format allows platforms to use an efficient YCbCr/YCrCb buffer
+     * layout, while still describing the buffer layout in a way accessible to
+     * the CPU in a device-independent manner.  While called YCbCr, it can be
+     * used to describe formats with either chromatic ordering, as well as
+     * whole planar or semiplanar layouts.
+     *
+     * struct android_ycbcr (below) is the the struct used to describe it.
+     *
+     * This format must be accepted by the gralloc module when
+     * USAGE_HW_CAMERA_WRITE and USAGE_SW_READ_* are set.
+     *
+     * This format is locked for use by gralloc's (*lock_ycbcr) method, and
+     * locking with the (*lock) method will return an error.
+     */
+    HAL_PIXEL_FORMAT_YCbCr_420_888 = 0x23,
+
     /* 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
 };
 
+/*
+ * Structure for describing YCbCr formats for consumption by applications.
+ * This is used with HAL_PIXEL_FORMAT_YCbCr_*_888.
+ *
+ * Buffer chroma subsampling is defined in the format.
+ * e.g. HAL_PIXEL_FORMAT_YCbCr_420_888 has subsampling 4:2:0.
+ *
+ * Buffers must have a 8 bit depth.
+ *
+ * @y, @cb, and @cr point to the first byte of their respective planes.
+ *
+ * Stride describes the distance in bytes from the first value of one row of
+ * the image to the first value of the next row.  It includes the width of the
+ * image plus padding.
+ * @ystride is the stride of the luma plane.
+ * @cstride is the stride of the chroma planes.
+ *
+ * @chroma_step is the distance in bytes from one chroma pixel value to the
+ * next.  This is 2 bytes for semiplanar (because chroma values are interleaved
+ * and each chroma value is one byte) and 1 for planar.
+ */
+
+struct android_ycbcr {
+    void *y;
+    void *cb;
+    void *cr;
+    size_t ystride;
+    size_t cstride;
+    size_t chroma_step;
+
+    /** reserved for future use, set to 0 by gralloc's (*lock_ycbcr)() */
+    uint32_t reserved[8];
+};
 
 /**
  * Transformation definitions
diff --git a/include/system/window.h b/include/system/window.h
index 4698fb3..b8a19c8 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -321,7 +321,6 @@
 enum {
     NATIVE_WINDOW_FRAMEBUFFER               = 0, /* FramebufferNativeWindow */
     NATIVE_WINDOW_SURFACE                   = 1, /* Surface */
-    NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT    = 2, /* SurfaceTextureClient */
 };
 
 /* parameter for NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
diff --git a/include/sysutils/FrameworkListener.h b/include/sysutils/FrameworkListener.h
index 756bacf..f1a4b43 100644
--- a/include/sysutils/FrameworkListener.h
+++ b/include/sysutils/FrameworkListener.h
@@ -23,10 +23,11 @@
 
 class FrameworkListener : public SocketListener {
 public:
-    static const int CMD_ARGS_MAX = 16;
+    static const int CMD_ARGS_MAX = 26;
 
     /* 1 out of errorRate will be dropped */
     int errorRate;
+
 private:
     int mCommandCount;
     bool mWithSeq;
diff --git a/include/usbhost/usbhost.h b/include/usbhost/usbhost.h
index 9a6b59c..1d67c12 100644
--- a/include/usbhost/usbhost.h
+++ b/include/usbhost/usbhost.h
@@ -72,6 +72,19 @@
 /* Call this to cleanup the USB host library. */
 void usb_host_cleanup(struct usb_host_context *context);
 
+/* Call this to get the inotify file descriptor. */
+int usb_host_get_fd(struct usb_host_context *context);
+
+/* Call this to initialize the usb host context. */
+int usb_host_load(struct usb_host_context *context,
+                  usb_device_added_cb added_cb,
+                  usb_device_removed_cb removed_cb,
+                  usb_discovery_done_cb discovery_done_cb,
+                  void *client_data);
+
+/* Call this to read and handle occuring usb event. */
+int usb_host_read_event(struct usb_host_context *context);
+
 /* Call this to monitor the USB bus for new and removed devices.
  * This is intended to be called from a dedicated thread,
  * as it will not return until one of the callbacks returns true.
diff --git a/init/Android.mk b/init/Android.mk
index 00d2144..ef62bce 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -35,7 +35,9 @@
 
 LOCAL_STATIC_LIBRARIES := \
 	libfs_mgr \
+	liblogwrap \
 	libcutils \
+	liblog \
 	libc \
 	libselinux
 
diff --git a/init/builtins.c b/init/builtins.c
index baa3e7f..576f0d9 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -464,6 +464,7 @@
     int child_ret = -1;
     int status;
     const char *prop;
+    struct fstab *fstab;
 
     if (nargs != 2) {
         return -1;
@@ -487,7 +488,9 @@
     } else if (pid == 0) {
         /* child, call fs_mgr_mount_all() */
         klog_set_level(6);  /* So we can see what fs_mgr_mount_all() does */
-        child_ret = fs_mgr_mount_all(args[1]);
+        fstab = fs_mgr_read_fstab(args[1]);
+        child_ret = fs_mgr_mount_all(fstab);
+        fs_mgr_free_fstab(fstab);
         if (child_ret == -1) {
             ERROR("fs_mgr_mount_all returned an error\n");
         }
@@ -590,8 +593,7 @@
     struct service *svc;
     svc = service_find_by_name(args[1]);
     if (svc) {
-        service_stop(svc);
-        service_start(svc, NULL);
+        service_restart(svc);
     }
     return 0;
 }
@@ -754,34 +756,29 @@
 }
 
 int do_setsebool(int nargs, char **args) {
-    SELboolean *b = alloca(nargs * sizeof(SELboolean));
-    char *v;
-    int i;
+    const char *name = args[1];
+    const char *value = args[2];
+    SELboolean b;
+    int ret;
 
     if (is_selinux_enabled() <= 0)
         return 0;
 
-    for (i = 1; i < nargs; i++) {
-        char *name = args[i];
-        v = strchr(name, '=');
-        if (!v) {
-            ERROR("setsebool: argument %s had no =\n", name);
-            return -EINVAL;
-        }
-        *v++ = 0;
-        b[i-1].name = name;
-        if (!strcmp(v, "1") || !strcasecmp(v, "true") || !strcasecmp(v, "on"))
-            b[i-1].value = 1;
-        else if (!strcmp(v, "0") || !strcasecmp(v, "false") || !strcasecmp(v, "off"))
-            b[i-1].value = 0;
-        else {
-            ERROR("setsebool: invalid value %s\n", v);
-            return -EINVAL;
-        }
+    b.name = name;
+    if (!strcmp(value, "1") || !strcasecmp(value, "true") || !strcasecmp(value, "on"))
+        b.value = 1;
+    else if (!strcmp(value, "0") || !strcasecmp(value, "false") || !strcasecmp(value, "off"))
+        b.value = 0;
+    else {
+        ERROR("setsebool: invalid value %s\n", value);
+        return -EINVAL;
     }
 
-    if (security_set_boolean_list(nargs - 1, b, 0) < 0)
-        return -errno;
+    if (security_set_boolean_list(1, &b, 0) < 0) {
+        ret = -errno;
+        ERROR("setsebool: could not set %s to %s\n", name, value);
+        return ret;
+    }
 
     return 0;
 }
diff --git a/init/devices.c b/init/devices.c
index dd875d6..af88c5f 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -33,6 +33,7 @@
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 #include <selinux/android.h>
+#include <selinux/avc.h>
 
 #include <private/android_filesystem_config.h>
 #include <sys/time.h>
@@ -83,7 +84,8 @@
 
 struct platform_node {
     char *name;
-    int name_len;
+    char *path;
+    int path_len;
     struct listnode list;
 };
 
@@ -126,6 +128,7 @@
     char buf[512];
     struct listnode *node;
     struct perms_ *dp;
+    char *secontext;
 
         /* upaths omit the "/sys" that paths in this list
          * contain, so we add 4 when comparing...
@@ -147,6 +150,14 @@
         INFO("fixup %s %d %d 0%o\n", buf, dp->uid, dp->gid, dp->perm);
         chown(buf, dp->uid, dp->gid);
         chmod(buf, dp->perm);
+        if (sehandle) {
+            secontext = NULL;
+            selabel_lookup(sehandle, &secontext, buf, 0);
+            if (secontext) {
+                setfilecon(buf, secontext);
+                freecon(secontext);
+           }
+        }
     }
 }
 
@@ -215,61 +226,69 @@
     }
 }
 
-static void add_platform_device(const char *name)
+static void add_platform_device(const char *path)
 {
-    int name_len = strlen(name);
+    int path_len = strlen(path);
     struct listnode *node;
     struct platform_node *bus;
+    const char *name = path;
+
+    if (!strncmp(path, "/devices/", 9)) {
+        name += 9;
+        if (!strncmp(name, "platform/", 9))
+            name += 9;
+    }
 
     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))
+        if ((bus->path_len < path_len) &&
+                (path[bus->path_len] == '/') &&
+                !strncmp(path, bus->path, bus->path_len))
             /* subdevice of an existing platform, ignore it */
             return;
     }
 
-    INFO("adding platform device %s\n", name);
+    INFO("adding platform device %s (%s)\n", name, path);
 
     bus = calloc(1, sizeof(struct platform_node));
-    bus->name = strdup(name);
-    bus->name_len = name_len;
+    bus->path = strdup(path);
+    bus->path_len = path_len;
+    bus->name = bus->path + (name - path);
     list_add_tail(&platform_names, &bus->list);
 }
 
 /*
- * given a name that may start with a platform device, find the length of the
+ * given a path 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)
+static struct platform_node *find_platform_device(const char *path)
 {
-    int name_len = strlen(name);
+    int path_len = strlen(path);
     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;
+        if ((bus->path_len < path_len) &&
+                (path[bus->path_len] == '/') &&
+                !strncmp(path, bus->path, bus->path_len))
+            return bus;
     }
 
     return NULL;
 }
 
-static void remove_platform_device(const char *name)
+static void remove_platform_device(const char *path)
 {
     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);
+        if (!strcmp(path, bus->path)) {
+            INFO("removing platform device %s\n", bus->name);
+            free(bus->path);
             list_remove(node);
             free(bus);
             return;
@@ -355,8 +374,10 @@
     char **links;
     int link_num = 0;
     int width;
+    struct platform_node *pdev;
 
-    if (strncmp(uevent->path, "/devices/platform/", 18))
+    pdev = find_platform_device(uevent->path);
+    if (!pdev)
         return NULL;
 
     links = malloc(sizeof(char *) * 2);
@@ -365,7 +386,7 @@
     memset(links, 0, sizeof(char *) * 2);
 
     /* skip "/devices/platform/<driver>" */
-    parent = strchr(uevent->path + 18, '/');
+    parent = strchr(uevent->path + pdev->path_len, '/');
     if (!*parent)
         goto err;
 
@@ -402,7 +423,7 @@
 static char **parse_platform_block_device(struct uevent *uevent)
 {
     const char *device;
-    const char *path;
+    struct platform_node *pdev;
     char *slash;
     int width;
     char buf[256];
@@ -414,18 +435,16 @@
     unsigned int size;
     struct stat info;
 
+    pdev = find_platform_device(uevent->path);
+    if (!pdev)
+        return NULL;
+    device = pdev->name;
+
     char **links = malloc(sizeof(char *) * 4);
     if (!links)
         return NULL;
     memset(links, 0, sizeof(char *) * 4);
 
-    /* Drop "/devices/platform/" */
-    path = uevent->path;
-    device = path + 18;
-    device = find_platform_device(device);
-    if (!device)
-        goto err;
-
     INFO("found platform device %s\n", device);
 
     snprintf(link_path, sizeof(link_path), "/dev/block/platform/%s", device);
@@ -433,6 +452,8 @@
     if (uevent->partition_name) {
         p = strdup(uevent->partition_name);
         sanitize(p);
+        if (strcmp(uevent->partition_name, p))
+            NOTICE("Linking partition '%s' as '%s'\n", uevent->partition_name, p);
         if (asprintf(&links[link_num], "%s/by-name/%s", link_path, p) > 0)
             link_num++;
         else
@@ -447,17 +468,13 @@
             links[link_num] = NULL;
     }
 
-    slash = strrchr(path, '/');
+    slash = strrchr(uevent->path, '/');
     if (asprintf(&links[link_num], "%s/%s", link_path, slash + 1) > 0)
         link_num++;
     else
         links[link_num] = NULL;
 
     return links;
-
-err:
-    free(links);
-    return NULL;
 }
 
 static void handle_device(const char *action, const char *devpath,
@@ -490,12 +507,12 @@
 
 static void handle_platform_device_event(struct uevent *uevent)
 {
-    const char *name = uevent->path + 18; /* length of /devices/platform/ */
+    const char *path = uevent->path;
 
     if (!strcmp(uevent->action, "add"))
-        add_platform_device(name);
+        add_platform_device(path);
     else if (!strcmp(uevent->action, "remove"))
-        remove_platform_device(name);
+        remove_platform_device(path);
 }
 
 static const char *parse_device_name(struct uevent *uevent, unsigned int len)
@@ -533,7 +550,7 @@
     snprintf(devpath, sizeof(devpath), "%s%s", base, name);
     make_dir(base, 0755);
 
-    if (!strncmp(uevent->path, "/devices/platform/", 18))
+    if (!strncmp(uevent->path, "/devices/", 9))
         links = parse_platform_block_device(uevent);
 
     handle_device(uevent->action, devpath, uevent->path, 1,
@@ -771,6 +788,7 @@
 file_free_out:
     free(file1);
     free(file2);
+    free(file3);
 data_free_out:
     free(data);
 loading_free_out:
@@ -813,6 +831,15 @@
         struct uevent uevent;
         parse_event(msg, &uevent);
 
+        if (sehandle && selinux_status_updated() > 0) {
+            struct selabel_handle *sehandle2;
+            sehandle2 = selinux_android_file_context_handle();
+            if (sehandle2) {
+                selabel_close(sehandle);
+                sehandle = sehandle2;
+            }
+        }
+
         handle_device_event(&uevent);
         handle_firmware_event(&uevent);
     }
@@ -879,10 +906,11 @@
     sehandle = NULL;
     if (is_selinux_enabled() > 0) {
         sehandle = selinux_android_file_context_handle();
+        selinux_status_open(true);
     }
 
-    /* is 64K enough? udev uses 16MB! */
-    device_fd = uevent_open_socket(64*1024, true);
+    /* is 256K enough? udev uses 16MB! */
+    device_fd = uevent_open_socket(256*1024, true);
     if(device_fd < 0)
         return;
 
diff --git a/init/init.c b/init/init.c
old mode 100755
new mode 100644
index b20b434..b699be0
--- a/init/init.c
+++ b/init/init.c
@@ -31,7 +31,6 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/un.h>
-#include <sys/personality.h>
 
 #include <selinux/selinux.h>
 #include <selinux/label.h>
@@ -40,6 +39,7 @@
 #include <libgen.h>
 
 #include <cutils/list.h>
+#include <cutils/android_reboot.h>
 #include <cutils/sockets.h>
 #include <cutils/iosched_policy.h>
 #include <private/android_filesystem_config.h>
@@ -74,8 +74,6 @@
 static unsigned revision = 0;
 static char qemu[32];
 
-static int selinux_enabled = 1;
-
 static struct action *cur_action = NULL;
 static struct command *cur_command = NULL;
 static struct listnode *command_queue = NULL;
@@ -91,7 +89,7 @@
 }
 
 static int have_console;
-static char *console_name = "/dev/console";
+static char console_name[PROP_VALUE_MAX] = "/dev/console";
 static time_t process_needs_restart;
 
 static const char *ENV[32];
@@ -165,7 +163,7 @@
          * state and immediately takes it out of the restarting
          * state if it was in there
          */
-    svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET));
+    svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART));
     svc->time_started = 0;
 
         /* running processes require no additional work -- if
@@ -198,28 +196,36 @@
     }
 
     if (is_selinux_enabled() > 0) {
-        char *mycon = NULL, *fcon = NULL;
+        if (svc->seclabel) {
+            scon = strdup(svc->seclabel);
+            if (!scon) {
+                ERROR("Out of memory while starting '%s'\n", svc->name);
+                return;
+            }
+        } else {
+            char *mycon = NULL, *fcon = NULL;
 
-        INFO("computing context for service '%s'\n", svc->args[0]);
-        rc = getcon(&mycon);
-        if (rc < 0) {
-            ERROR("could not get context while starting '%s'\n", svc->name);
-            return;
-        }
+            INFO("computing context for service '%s'\n", svc->args[0]);
+            rc = getcon(&mycon);
+            if (rc < 0) {
+                ERROR("could not get context while starting '%s'\n", svc->name);
+                return;
+            }
 
-        rc = getfilecon(svc->args[0], &fcon);
-        if (rc < 0) {
-            ERROR("could not get context while starting '%s'\n", svc->name);
+            rc = getfilecon(svc->args[0], &fcon);
+            if (rc < 0) {
+                ERROR("could not get context while starting '%s'\n", svc->name);
+                freecon(mycon);
+                return;
+            }
+
+            rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &scon);
             freecon(mycon);
-            return;
-        }
-
-        rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &scon);
-        freecon(mycon);
-        freecon(fcon);
-        if (rc < 0) {
-            ERROR("could not get context while starting '%s'\n", svc->name);
-            return;
+            freecon(fcon);
+            if (rc < 0) {
+                ERROR("could not get context while starting '%s'\n", svc->name);
+                return;
+            }
         }
     }
 
@@ -234,21 +240,6 @@
         int fd, sz;
 
         umask(077);
-#ifdef __arm__
-        /*
-         * b/7188322 - Temporarily revert to the compat memory layout
-         * to avoid breaking third party apps.
-         *
-         * THIS WILL GO AWAY IN A FUTURE ANDROID RELEASE.
-         *
-         * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=7dbaa466
-         * changes the kernel mapping from bottom up to top-down.
-         * This breaks some programs which improperly embed
-         * an out of date copy of Android's linker.
-         */
-        int current = personality(0xffffFFFF);
-        personality(current | ADDR_COMPAT_LAYOUT);
-#endif
         if (properties_inited()) {
             get_property_workspace(&fd, &sz);
             sprintf(tmp, "%d,%d", dup(fd), sz);
@@ -258,14 +249,12 @@
         for (ei = svc->envvars; ei; ei = ei->next)
             add_environment(ei->name, ei->value);
 
-        setsockcreatecon(scon);
-
         for (si = svc->sockets; si; si = si->next) {
             int socket_type = (
                     !strcmp(si->type, "stream") ? SOCK_STREAM :
                         (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
             int s = create_socket(si->name, socket_type,
-                                  si->perm, si->uid, si->gid);
+                                  si->perm, si->uid, si->gid, si->socketcon ?: scon);
             if (s >= 0) {
                 publish_socket(si->name, s);
             }
@@ -273,7 +262,6 @@
 
         freecon(scon);
         scon = NULL;
-        setsockcreatecon(NULL);
 
         if (svc->ioprio_class != IoSchedClass_NONE) {
             if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
@@ -367,15 +355,14 @@
         notify_service_state(svc->name, "running");
 }
 
-/* The how field should be either SVC_DISABLED or SVC_RESET */
+/* The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART */
 static void service_stop_or_reset(struct service *svc, int how)
 {
-        /* we are no longer running, nor should we
-         * attempt to restart
-         */
-    svc->flags &= (~(SVC_RUNNING|SVC_RESTARTING));
+    /* The service is still SVC_RUNNING until its process exits, but if it has
+     * already exited it shoudn't attempt a restart yet. */
+    svc->flags &= (~SVC_RESTARTING);
 
-    if ((how != SVC_DISABLED) && (how != SVC_RESET)) {
+    if ((how != SVC_DISABLED) && (how != SVC_RESET) && (how != SVC_RESTART)) {
         /* Hrm, an illegal flag.  Default to SVC_DISABLED */
         how = SVC_DISABLED;
     }
@@ -407,6 +394,17 @@
     service_stop_or_reset(svc, SVC_DISABLED);
 }
 
+void service_restart(struct service *svc)
+{
+    if (svc->flags & SVC_RUNNING) {
+        /* Stop, wait, then start the service. */
+        service_stop_or_reset(svc, SVC_RESTART);
+    } else if (!(svc->flags & SVC_RESTARTING)) {
+        /* Just start the service since it's not running. */
+        service_start(svc, NULL);
+    } /* else: Service is restarting anyways. */
+}
+
 void property_changed(const char *name, const char *value)
 {
     if (property_triggers_enabled)
@@ -438,7 +436,7 @@
 
 static void msg_start(const char *name)
 {
-    struct service *svc;
+    struct service *svc = NULL;
     char *tmp = NULL;
     char *args = NULL;
 
@@ -446,11 +444,13 @@
         svc = service_find_by_name(name);
     else {
         tmp = strdup(name);
-        args = strchr(tmp, ':');
-        *args = '\0';
-        args++;
+        if (tmp) {
+            args = strchr(tmp, ':');
+            *args = '\0';
+            args++;
 
-        svc = service_find_by_name(tmp);
+            svc = service_find_by_name(tmp);
+        }
     }
 
     if (svc) {
@@ -473,6 +473,17 @@
     }
 }
 
+static void msg_restart(const char *name)
+{
+    struct service *svc = service_find_by_name(name);
+
+    if (svc) {
+        service_restart(svc);
+    } else {
+        ERROR("no such service '%s'\n", name);
+    }
+}
+
 void handle_control_message(const char *msg, const char *arg)
 {
     if (!strcmp(msg,"start")) {
@@ -480,8 +491,7 @@
     } else if (!strcmp(msg,"stop")) {
         msg_stop(arg);
     } else if (!strcmp(msg,"restart")) {
-        msg_stop(arg);
-        msg_start(arg);
+        msg_restart(arg);
     } else {
         ERROR("unknown control msg '%s'\n", msg);
     }
@@ -555,11 +565,9 @@
 static int console_init_action(int nargs, char **args)
 {
     int fd;
-    char tmp[PROP_VALUE_MAX];
 
     if (console[0]) {
-        snprintf(tmp, sizeof(tmp), "/dev/%s", console);
-        console_name = strdup(tmp);
+        snprintf(console_name, sizeof(console_name), "/dev/%s", console);
     }
 
     fd = open(console_name, O_RDWR);
@@ -602,10 +610,6 @@
     *value++ = 0;
     if (name_len == 0) return;
 
-    if (!strcmp(name,"selinux")) {
-        selinux_enabled = atoi(value);
-    }
-
     if (for_emulator) {
         /* in the emulator, export any kernel option with the
          * ro.kernel. prefix */
@@ -633,7 +637,7 @@
 static void export_kernel_boot_props(void)
 {
     char tmp[PROP_VALUE_MAX];
-    const char *pval;
+    int ret;
     unsigned i;
     struct {
         const char *src_prop;
@@ -647,22 +651,26 @@
     };
 
     for (i = 0; i < ARRAY_SIZE(prop_map); i++) {
-        pval = property_get(prop_map[i].src_prop);
-        property_set(prop_map[i].dest_prop, pval ?: prop_map[i].def_val);
+        ret = property_get(prop_map[i].src_prop, tmp);
+        if (ret > 0)
+            property_set(prop_map[i].dest_prop, tmp);
+        else
+            property_set(prop_map[i].dest_prop, prop_map[i].def_val);
     }
 
-    pval = property_get("ro.boot.console");
-    if (pval)
-        strlcpy(console, pval, sizeof(console));
+    ret = property_get("ro.boot.console", tmp);
+    if (ret)
+        strlcpy(console, tmp, sizeof(console));
 
     /* save a copy for init's usage during boot */
-    strlcpy(bootmode, property_get("ro.bootmode"), sizeof(bootmode));
+    property_get("ro.bootmode", tmp);
+    strlcpy(bootmode, tmp, sizeof(bootmode));
 
     /* if this was given on kernel command line, override what we read
      * before (e.g. from /proc/cpuinfo), if anything */
-    pval = property_get("ro.boot.hardware");
-    if (pval)
-        strlcpy(hardware, pval, sizeof(hardware));
+    ret = property_get("ro.boot.hardware", tmp);
+    if (ret)
+        strlcpy(hardware, tmp, sizeof(hardware));
     property_set("ro.hardware", hardware);
 
     snprintf(tmp, PROP_VALUE_MAX, "%d", revision);
@@ -753,7 +761,7 @@
 #endif
 
 static const struct selinux_opt seopts_prop[] = {
-        { SELABEL_OPT_PATH, "/data/system/property_contexts" },
+        { SELABEL_OPT_PATH, "/data/security/property_contexts" },
         { SELABEL_OPT_PATH, "/property_contexts" },
         { 0, NULL }
 };
@@ -782,9 +790,49 @@
     sehandle_prop = selinux_android_prop_context_handle();
 }
 
+static bool selinux_is_disabled(void)
+{
+    char tmp[PROP_VALUE_MAX];
+
+    if (access("/sys/fs/selinux", F_OK) != 0) {
+        /* SELinux is not compiled into the kernel, or has been disabled
+         * via the kernel command line "selinux=0".
+         */
+        return true;
+    }
+
+    if ((property_get("ro.boot.selinux", tmp) != 0) && (strcmp(tmp, "disabled") == 0)) {
+        /* SELinux is compiled into the kernel, but we've been told to disable it. */
+        return true;
+    }
+
+    return false;
+}
+
+static bool selinux_is_enforcing(void)
+{
+    char tmp[PROP_VALUE_MAX];
+
+    if (property_get("ro.boot.selinux", tmp) == 0) {
+        /* Property is not set.  Assume enforcing */
+        return true;
+    }
+
+    if (strcmp(tmp, "permissive") == 0) {
+        /* SELinux is in the kernel, but we've been told to go into permissive mode */
+        return false;
+    }
+
+    if (strcmp(tmp, "enforcing") != 0) {
+        ERROR("SELinux: Unknown value of ro.boot.selinux. Got: \"%s\". Assuming enforcing.\n", tmp);
+    }
+
+    return true;
+}
+
 int selinux_reload_policy(void)
 {
-    if (!selinux_enabled) {
+    if (selinux_is_disabled()) {
         return -1;
     }
 
@@ -810,6 +858,25 @@
     return 0;
 }
 
+static void selinux_initialize(void)
+{
+    if (selinux_is_disabled()) {
+        return;
+    }
+
+    INFO("loading selinux policy\n");
+    if (selinux_android_load_policy() < 0) {
+        ERROR("SELinux: Failed to load policy; rebooting into recovery mode\n");
+        android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
+        while (1) { pause(); }  // never reached
+    }
+
+    selinux_init_all_handles();
+    bool is_enforcing = selinux_is_enforcing();
+    INFO("SELinux: security_setenforce(%d)\n", is_enforcing);
+    security_setenforce(is_enforcing);
+}
+
 int main(int argc, char **argv)
 {
     int fd_count = 0;
@@ -870,23 +937,15 @@
     cb.func_audit = audit_callback;
     selinux_set_callback(SELINUX_CB_AUDIT, cb);
 
-    INFO("loading selinux policy\n");
-    if (selinux_enabled) {
-        if (selinux_android_load_policy() < 0) {
-            selinux_enabled = 0;
-            INFO("SELinux: Disabled due to failed policy load\n");
-        } else {
-            selinux_init_all_handles();
-        }
-    } else {
-        INFO("SELinux:  Disabled by command line option\n");
-    }
+    selinux_initialize();
     /* These directories were necessarily created before initial policy load
      * and therefore need their security context restored to the proper value.
      * This must happen before /dev is populated by ueventd.
      */
     restorecon("/dev");
     restorecon("/dev/socket");
+    restorecon("/dev/__properties__");
+    restorecon_recursive("/sys");
 
     is_charger = !strcmp(bootmode, "charger");
 
diff --git a/init/init.h b/init/init.h
index 955e1f0..3928d52 100644
--- a/init/init.h
+++ b/init/init.h
@@ -55,6 +55,7 @@
     uid_t uid;
     gid_t gid;
     int perm;
+    const char *socketcon;
 };
 
 struct svcenvinfo {
@@ -72,6 +73,7 @@
 #define SVC_RESET       0x40  /* Use when stopping a process, but not disabling
                                  so it can be restarted with its class */
 #define SVC_RC_DISABLED 0x80  /* Remember if the disabled flag was set in the rc script */
+#define SVC_RESTART     0x100 /* Use to safely restart (stop, wait, start) a service */
 
 #define NR_SVC_SUPP_GIDS 12    /* twelve supplementary groups */
 
@@ -127,6 +129,7 @@
                             void (*func)(struct service *svc));
 void service_stop(struct service *svc);
 void service_reset(struct service *svc);
+void service_restart(struct service *svc);
 void service_start(struct service *svc, const char *dynamic_args);
 void property_changed(const char *name, const char *value);
 
diff --git a/init/init_parser.c b/init/init_parser.c
index beb9188..616671a 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -206,8 +206,9 @@
     while (*src_ptr && left > 0) {
         char *c;
         char prop[PROP_NAME_MAX + 1];
-        const char *prop_val;
+        char prop_val[PROP_VALUE_MAX];
         int prop_len = 0;
+        int prop_val_len;
 
         c = strchr(src_ptr, '$');
         if (!c) {
@@ -265,14 +266,14 @@
             goto err;
         }
 
-        prop_val = property_get(prop);
-        if (!prop_val) {
+        prop_val_len = property_get(prop, prop_val);
+        if (!prop_val_len) {
             ERROR("property '%s' doesn't exist while expanding '%s'\n",
                   prop, src);
             goto err;
         }
 
-        ret = push_chars(&dst_ptr, &left, prop_val, strlen(prop_val));
+        ret = push_chars(&dst_ptr, &left, prop_val, prop_val_len);
         if (ret < 0)
             goto err_nospace;
         src_ptr = c;
@@ -543,7 +544,7 @@
             const char* equals = strchr(name, '=');
             if (equals) {
                 char prop_name[PROP_NAME_MAX + 1];
-                const char* value;
+                char value[PROP_VALUE_MAX];
                 int length = equals - name;
                 if (length > PROP_NAME_MAX) {
                     ERROR("property name too long in trigger %s", act->name);
@@ -552,9 +553,8 @@
                     prop_name[length] = 0;
 
                     /* does the property exist, and match the trigger value? */
-                    value = property_get(prop_name);
-                    if (value && (!strcmp(equals + 1, value) ||
-                                  !strcmp(equals + 1, "*"))) {
+                    property_get(prop_name, value);
+                    if (!strcmp(equals + 1, value) ||!strcmp(equals + 1, "*")) {
                         action_add_queue_tail(act);
                     }
                 }
@@ -571,6 +571,7 @@
     act = calloc(1, sizeof(*act));
     act->name = name;
     list_init(&act->commands);
+    list_init(&act->qlist);
 
     cmd = calloc(1, sizeof(*cmd));
     cmd->func = func;
@@ -583,7 +584,9 @@
 
 void action_add_queue_tail(struct action *act)
 {
-    list_add_tail(&action_queue, &act->qlist);
+    if (list_empty(&act->qlist)) {
+        list_add_tail(&action_queue, &act->qlist);
+    }
 }
 
 struct action *action_remove_queue_head(void)
@@ -594,6 +597,7 @@
         struct listnode *node = list_head(&action_queue);
         struct action *act = node_to_item(node, struct action, qlist);
         list_remove(node);
+        list_init(node);
         return act;
     }
 }
@@ -764,7 +768,7 @@
         svc->envvars = ei;
         break;
     }
-    case K_socket: {/* name type perm [ uid gid ] */
+    case K_socket: {/* name type perm [ uid gid context ] */
         struct socketinfo *si;
         if (nargs < 4) {
             parse_error(state, "socket option requires name, type, perm arguments\n");
@@ -787,6 +791,8 @@
             si->uid = decode_uid(args[4]);
         if (nargs > 5)
             si->gid = decode_uid(args[5]);
+        if (nargs > 6)
+            si->socketcon = args[6];
         si->next = svc->sockets;
         svc->sockets = si;
         break;
@@ -825,6 +831,7 @@
     act = calloc(1, sizeof(*act));
     act->name = args[1];
     list_init(&act->commands);
+    list_init(&act->qlist);
     list_add_tail(&action_list, &act->alist);
         /* XXX add to hash */
     return act;
diff --git a/init/keychords.c b/init/keychords.c
index aab0819..4a64042 100644
--- a/init/keychords.c
+++ b/init/keychords.c
@@ -95,24 +95,19 @@
 void handle_keychord()
 {
     struct service *svc;
-    const char* debuggable;
-    const char* adb_enabled;
+    char adb_enabled[PROP_VALUE_MAX];
     int ret;
     __u16 id;
 
-    // only handle keychords if ro.debuggable is set or adb is enabled.
-    // the logic here is that bugreports should be enabled in userdebug or eng builds
-    // and on user builds for users that are developers.
-    debuggable = property_get("ro.debuggable");
-    adb_enabled = property_get("init.svc.adbd");
+    // Only handle keychords if adb is enabled.
+    property_get("init.svc.adbd", adb_enabled);
     ret = read(keychord_fd, &id, sizeof(id));
     if (ret != sizeof(id)) {
         ERROR("could not read keychord id\n");
         return;
     }
 
-    if ((debuggable && !strcmp(debuggable, "1")) ||
-        (adb_enabled && !strcmp(adb_enabled, "running"))) {
+    if (!strcmp(adb_enabled, "running")) {
         svc = service_find_by_keychord(id);
         if (svc) {
             INFO("starting service %s from keychord\n", svc->name);
diff --git a/init/keywords.h b/init/keywords.h
index 97d4950..f188db5 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -78,7 +78,7 @@
     KEYWORD(setkey,      COMMAND, 0, do_setkey)
     KEYWORD(setprop,     COMMAND, 2, do_setprop)
     KEYWORD(setrlimit,   COMMAND, 3, do_setrlimit)
-    KEYWORD(setsebool,   COMMAND, 1, do_setsebool)
+    KEYWORD(setsebool,   COMMAND, 2, do_setsebool)
     KEYWORD(socket,      OPTION,  0, 0)
     KEYWORD(start,       COMMAND, 1, do_start)
     KEYWORD(stop,        COMMAND, 1, do_stop)
diff --git a/init/property_service.c b/init/property_service.c
index 61dd86f..f5f5457 100755
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -27,6 +27,7 @@
 
 #include <cutils/misc.h>
 #include <cutils/sockets.h>
+#include <cutils/multiuser.h>
 
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
 #include <sys/_system_properties.h>
@@ -79,6 +80,7 @@
     { "sys.",             AID_SYSTEM,   0 },
     { "service.",         AID_SYSTEM,   0 },
     { "wlan.",            AID_SYSTEM,   0 },
+    { "gps.",             AID_GPS,      0 },
     { "bluetooth.",       AID_BLUETOOTH,   0 },
     { "dhcp.",            AID_SYSTEM,   0 },
     { "dhcp.",            AID_DHCP,     0 },
@@ -90,6 +92,7 @@
     { "persist.sys.",     AID_SYSTEM,   0 },
     { "persist.service.", AID_SYSTEM,   0 },
     { "persist.security.", AID_SYSTEM,   0 },
+    { "persist.gps.",      AID_GPS,      0 },
     { "persist.service.bdroid.", AID_BLUETOOTH,   0 },
     { "selinux."         , AID_SYSTEM,   0 },
     { NULL, 0, 0 }
@@ -110,7 +113,6 @@
 };
 
 typedef struct {
-    void *data;
     size_t size;
     int fd;
 } workspace;
@@ -118,85 +120,34 @@
 static int init_workspace(workspace *w, size_t size)
 {
     void *data;
-    int fd;
-
-        /* dev is a tmpfs that we can use to carve a shared workspace
-         * out of, so let's do that...
-         */
-    fd = open("/dev/__properties__", O_RDWR | O_CREAT | O_NOFOLLOW, 0600);
+    int fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW);
     if (fd < 0)
         return -1;
 
-    if (ftruncate(fd, size) < 0)
-        goto out;
-
-    data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-    if(data == MAP_FAILED)
-        goto out;
-
-    close(fd);
-
-    fd = open("/dev/__properties__", O_RDONLY | O_NOFOLLOW);
-    if (fd < 0)
-        return -1;
-
-    unlink("/dev/__properties__");
-
-    w->data = data;
     w->size = size;
     w->fd = fd;
     return 0;
-
-out:
-    close(fd);
-    return -1;
 }
 
-/* (8 header words + 247 toc words) = 1020 bytes */
-/* 1024 bytes header and toc + 247 prop_infos @ 128 bytes = 32640 bytes */
-
-#define PA_COUNT_MAX  247
-#define PA_INFO_START 1024
-#define PA_SIZE       32768
-
 static workspace pa_workspace;
-static prop_info *pa_info_array;
-
-extern prop_area *__system_property_area__;
 
 static int init_property_area(void)
 {
-    prop_area *pa;
-
-    if(pa_info_array)
+    if (property_area_inited)
         return -1;
 
-    if(init_workspace(&pa_workspace, PA_SIZE))
+    if(__system_property_area_init())
+        return -1;
+
+    if(init_workspace(&pa_workspace, 0))
         return -1;
 
     fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);
 
-    pa_info_array = (void*) (((char*) pa_workspace.data) + PA_INFO_START);
-
-    pa = pa_workspace.data;
-    memset(pa, 0, PA_SIZE);
-    pa->magic = PROP_AREA_MAGIC;
-    pa->version = PROP_AREA_VERSION;
-
-        /* plug into the lib property services */
-    __system_property_area__ = pa;
     property_area_inited = 1;
     return 0;
 }
 
-static void update_prop_info(prop_info *pi, const char *value, unsigned len)
-{
-    pi->serial = pi->serial | 1;
-    memcpy(pi->value, value, len + 1);
-    pi->serial = (len << 24) | ((pi->serial + 1) & 0xffffff);
-    __futex_wake(&pi->serial, INT32_MAX);
-}
-
 static int check_mac_perms(const char *name, char *sctx)
 {
     if (is_selinux_enabled() <= 0)
@@ -272,12 +223,19 @@
 static int check_perms(const char *name, unsigned int uid, unsigned int gid, char *sctx)
 {
     int i;
+    unsigned int app_id;
+
     if(!strncmp(name, "ro.", 3))
         name +=3;
 
     if (uid == 0)
         return check_mac_perms(name, sctx);
 
+    app_id = multiuser_get_app_id(uid);
+    if (app_id == AID_BLUETOOTH) {
+        uid = app_id;
+    }
+
     for (i = 0; property_perms[i].prefix; i++) {
         if (strncmp(property_perms[i].prefix, name,
                     strlen(property_perms[i].prefix)) == 0) {
@@ -292,19 +250,9 @@
     return 0;
 }
 
-const char* property_get(const char *name)
+int __property_get(const char *name, char *value)
 {
-    prop_info *pi;
-
-    if(strlen(name) >= PROP_NAME_MAX) return 0;
-
-    pi = (prop_info*) __system_property_find(name);
-
-    if(pi != 0) {
-        return pi->value;
-    } else {
-        return 0;
-    }
+    return __system_property_get(name, value);
 }
 
 static void write_persistent_property(const char *name, const char *value)
@@ -331,8 +279,8 @@
 
 int property_set(const char *name, const char *value)
 {
-    prop_area *pa;
     prop_info *pi;
+    int ret;
 
     size_t namelen = strlen(name);
     size_t valuelen = strlen(value);
@@ -347,25 +295,13 @@
         /* ro.* properties may NEVER be modified once set */
         if(!strncmp(name, "ro.", 3)) return -1;
 
-        pa = __system_property_area__;
-        update_prop_info(pi, value, valuelen);
-        pa->serial++;
-        __futex_wake(&pa->serial, INT32_MAX);
+        __system_property_update(pi, value, valuelen);
     } else {
-        pa = __system_property_area__;
-        if(pa->count == PA_COUNT_MAX) return -1;
-
-        pi = pa_info_array + pa->count;
-        pi->serial = (valuelen << 24);
-        memcpy(pi->name, name, namelen + 1);
-        memcpy(pi->value, value, valuelen + 1);
-
-        pa->toc[pa->count] =
-            (namelen << 24) | (((unsigned) pi) - ((unsigned) pa));
-
-        pa->count++;
-        pa->serial++;
-        __futex_wake(&pa->serial, INT32_MAX);
+        ret = __system_property_add(name, namelen, value, valuelen);
+        if (ret < 0) {
+            ERROR("Failed to set '%s'='%s'", name, value);
+            return ret;
+        }
     }
     /* If name starts with "net." treat as a DNS property. */
     if (strncmp("net.", name, strlen("net.")) == 0)  {
@@ -469,10 +405,13 @@
     *sz = pa_workspace.size;
 }
 
-static void load_properties(char *data)
+static void load_properties(char *data, char *prefix)
 {
     char *key, *value, *eol, *sol, *tmp;
+    size_t plen;
 
+    if (prefix)
+        plen = strlen(prefix);
     sol = data;
     while((eol = strchr(sol, '\n'))) {
         key = sol;
@@ -488,6 +427,9 @@
         tmp = value - 2;
         while((tmp > key) && isspace(*tmp)) *tmp-- = 0;
 
+        if (prefix && strncmp(key, prefix, plen))
+            continue;
+
         while(isspace(*value)) value++;
         tmp = eol - 2;
         while((tmp > value) && isspace(*tmp)) *tmp-- = 0;
@@ -496,7 +438,7 @@
     }
 }
 
-static void load_properties_from_file(const char *fn)
+static void load_properties_from_file(const char *fn, char *prefix)
 {
     char *data;
     unsigned sz;
@@ -504,7 +446,7 @@
     data = read_file(fn, &sz);
 
     if(data != 0) {
-        load_properties(data);
+        load_properties(data, prefix);
         free(data);
     }
 }
@@ -577,7 +519,7 @@
 
 void property_load_boot_defaults(void)
 {
-    load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);
+    load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT, NULL);
 }
 
 int properties_inited(void)
@@ -587,9 +529,12 @@
 
 static void load_override_properties() {
 #ifdef ALLOW_LOCAL_PROP_OVERRIDE
-    const char *debuggable = property_get("ro.debuggable");
-    if (debuggable && (strcmp(debuggable, "1") == 0)) {
-        load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
+    char debuggable[PROP_VALUE_MAX];
+    int ret;
+
+    ret = property_get("ro.debuggable", debuggable);
+    if (ret && (strcmp(debuggable, "1") == 0)) {
+        load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE, NULL);
     }
 #endif /* ALLOW_LOCAL_PROP_OVERRIDE */
 }
@@ -611,13 +556,14 @@
 {
     int fd;
 
-    load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
-    load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
+    load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
+    load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL);
+    load_properties_from_file(PROP_PATH_FACTORY, "ro.");
     load_override_properties();
     /* Read persistent properties after all default values have been loaded. */
     load_persistent_properties();
 
-    fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0);
+    fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL);
     if(fd < 0) return;
     fcntl(fd, F_SETFD, FD_CLOEXEC);
     fcntl(fd, F_SETFL, O_NONBLOCK);
diff --git a/init/property_service.h b/init/property_service.h
index b9d1bf6..46cbd8f 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -18,6 +18,7 @@
 #define _INIT_PROPERTY_H
 
 #include <stdbool.h>
+#include <sys/system_properties.h>
 
 extern void handle_property_set_fd(void);
 extern void property_init(void);
@@ -25,9 +26,25 @@
 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);
+extern int __property_get(const char *name, char *value);
 extern int property_set(const char *name, const char *value);
 extern int properties_inited();
 int get_property_set_fd(void);
 
+extern void __property_get_size_error()
+    __attribute__((__error__("property_get called with too small buffer")));
+
+static inline
+__attribute__ ((always_inline))
+__attribute__ ((gnu_inline))
+__attribute__ ((artificial))
+int property_get(const char *name, char *value)
+{
+    size_t value_len = __builtin_object_size(value, 0);
+    if (value_len != PROP_VALUE_MAX)
+        __property_get_size_error();
+
+    return __property_get(name, value);
+}
+
 #endif	/* _INIT_PROPERTY_H */
diff --git a/init/readme.txt b/init/readme.txt
index 9cc291c..1e8c392 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -70,10 +70,13 @@
 setenv <name> <value>
    Set the environment variable <name> to <value> in the launched process.
 
-socket <name> <type> <perm> [ <user> [ <group> ] ]
+socket <name> <type> <perm> [ <user> [ <group> [ <context> ] ] ]
    Create a unix domain socket named /dev/socket/<name> and pass
    its fd to the launched process.  <type> must be "dgram", "stream" or "seqpacket".
    User and group default to 0.
+   Context is the SELinux security context for the socket.
+   It defaults to the service security context, as specified by seclabel or
+   computed based on the service executable file security context.
 
 user <username>
    Change to username before exec'ing this service.
@@ -213,7 +216,7 @@
 setrlimit <resource> <cur> <max>
    Set the rlimit for a resource.
 
-setsebool <name>=<value>
+setsebool <name> <value>
    Set SELinux boolean <name> to <value>.
    <value> may be 1|true|on or 0|false|off
 
diff --git a/init/signal_handler.c b/init/signal_handler.c
index abccb40..d31ad63 100644
--- a/init/signal_handler.c
+++ b/init/signal_handler.c
@@ -63,7 +63,7 @@
 
     NOTICE("process '%s', pid %d exited\n", svc->name, pid);
 
-    if (!(svc->flags & SVC_ONESHOT)) {
+    if (!(svc->flags & SVC_ONESHOT) || (svc->flags & SVC_RESTART)) {
         kill(-pid, SIGKILL);
         NOTICE("process '%s' killing any children in process group\n", svc->name);
     }
@@ -78,8 +78,9 @@
     svc->pid = 0;
     svc->flags &= (~SVC_RUNNING);
 
-        /* oneshot processes go into the disabled state on exit */
-    if (svc->flags & SVC_ONESHOT) {
+        /* oneshot processes go into the disabled state on exit,
+         * except when manually restarted. */
+    if ((svc->flags & SVC_ONESHOT) && !(svc->flags & SVC_RESTART)) {
         svc->flags |= SVC_DISABLED;
     }
 
@@ -90,7 +91,7 @@
     }
 
     now = gettime();
-    if (svc->flags & SVC_CRITICAL) {
+    if ((svc->flags & SVC_CRITICAL) && !(svc->flags & SVC_RESTART)) {
         if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
             if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
                 ERROR("critical process '%s' exited %d times in %d minutes; "
@@ -105,6 +106,7 @@
         }
     }
 
+    svc->flags &= (~SVC_RESTART);
     svc->flags |= SVC_RESTARTING;
 
     /* Execute all onrestart commands for this service. */
diff --git a/init/util.c b/init/util.c
old mode 100755
new mode 100644
index e9d8094..9aaa77d
--- a/init/util.c
+++ b/init/util.c
@@ -22,6 +22,7 @@
 #include <ctype.h>
 #include <errno.h>
 #include <time.h>
+#include <ftw.h>
 
 #include <selinux/label.h>
 
@@ -83,11 +84,15 @@
  * daemon. We communicate the file descriptor's value via the environment
  * variable ANDROID_SOCKET_ENV_PREFIX<name> ("ANDROID_SOCKET_foo").
  */
-int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid)
+int create_socket(const char *name, int type, mode_t perm, uid_t uid,
+                  gid_t gid, const char *socketcon)
 {
     struct sockaddr_un addr;
     int fd, ret;
-    char *secon;
+    char *filecon;
+
+    if (socketcon)
+        setsockcreatecon(socketcon);
 
     fd = socket(PF_UNIX, type, 0);
     if (fd < 0) {
@@ -95,6 +100,9 @@
         return -1;
     }
 
+    if (socketcon)
+        setsockcreatecon(NULL);
+
     memset(&addr, 0 , sizeof(addr));
     addr.sun_family = AF_UNIX;
     snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
@@ -106,11 +114,11 @@
         goto out_close;
     }
 
-    secon = NULL;
+    filecon = NULL;
     if (sehandle) {
-        ret = selabel_lookup(sehandle, &secon, addr.sun_path, S_IFSOCK);
+        ret = selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK);
         if (ret == 0)
-            setfscreatecon(secon);
+            setfscreatecon(filecon);
     }
 
     ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
@@ -120,7 +128,7 @@
     }
 
     setfscreatecon(NULL);
-    freecon(secon);
+    freecon(filecon);
 
     chown(addr.sun_path, uid, gid);
     chmod(addr.sun_path, perm);
@@ -305,14 +313,27 @@
     return 0;
 }
 
+/*
+ * replaces any unacceptable characters with '_', the
+ * length of the resulting string is equal to the input string
+ */
 void sanitize(char *s)
 {
+    const char* accept =
+            "abcdefghijklmnopqrstuvwxyz"
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+            "0123456789"
+            "_-.";
+
     if (!s)
         return;
-    while (isalnum(*s))
-        s++;
-    *s = 0;
+
+    for (; *s; s++) {
+        s += strspn(s, accept);
+        if (*s) *s = '_';
+    }
 }
+
 void make_link(const char *oldpath, const char *newpath)
 {
     int ret;
@@ -453,13 +474,13 @@
 void import_kernel_cmdline(int in_qemu,
                            void (*import_kernel_nv)(char *name, int in_qemu))
 {
-    char cmdline[1024];
+    char cmdline[2048];
     char *ptr;
     int fd;
 
     fd = open("/proc/cmdline", O_RDONLY);
     if (fd >= 0) {
-        int n = read(fd, cmdline, 1023);
+        int n = read(fd, cmdline, sizeof(cmdline) - 1);
         if (n < 0) n = 0;
 
         /* get rid of trailing newline, it happens */
@@ -523,3 +544,17 @@
     freecon(secontext);
     return 0;
 }
+
+static int nftw_restorecon(const char* filename, const struct stat* statptr,
+    int fileflags, struct FTW* pftw)
+{
+    restorecon(filename);
+    return 0;
+}
+
+int restorecon_recursive(const char* pathname)
+{
+    int fd_limit = 20;
+    int flags = FTW_DEPTH | FTW_MOUNT | FTW_PHYS;
+    return nftw(pathname, nftw_restorecon, fd_limit, flags);
+}
diff --git a/init/util.h b/init/util.h
index 45905b6..04b8129 100644
--- a/init/util.h
+++ b/init/util.h
@@ -26,7 +26,7 @@
 
 int mtd_name_to_number(const char *name);
 int create_socket(const char *name, int type, mode_t perm,
-                  uid_t uid, gid_t gid);
+                  uid_t uid, gid_t gid, const char *socketcon);
 void *read_file(const char *fn, unsigned *_sz);
 time_t gettime(void);
 unsigned int decode_uid(const char *s);
@@ -41,4 +41,5 @@
 void import_kernel_cmdline(int in_qemu, void (*import_kernel_nv)(char *name, int in_qemu));
 int make_dir(const char *path, mode_t mode);
 int restorecon(const char *pathname);
+int restorecon_recursive(const char *pathname);
 #endif
diff --git a/libcorkscrew/Android.mk b/libcorkscrew/Android.mk
index 2786d8f..e275317 100644
--- a/libcorkscrew/Android.mk
+++ b/libcorkscrew/Android.mk
@@ -49,9 +49,9 @@
 LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
 endif
 
-LOCAL_SHARED_LIBRARIES += libdl libcutils libgccdemangle
+LOCAL_SHARED_LIBRARIES += libdl libcutils liblog libgccdemangle
 
-LOCAL_CFLAGS += -std=gnu99 -Werror
+LOCAL_CFLAGS += -std=gnu99 -Werror -Wno-unused-parameter
 LOCAL_MODULE := libcorkscrew
 LOCAL_MODULE_TAGS := optional
 
@@ -59,35 +59,40 @@
 
 # Build test.
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := test.c
-LOCAL_CFLAGS += -std=gnu99 -Werror -fno-inline-small-functions
+LOCAL_SRC_FILES := test.cpp
+LOCAL_CFLAGS += -Werror -fno-inline-small-functions
 LOCAL_SHARED_LIBRARIES := libcorkscrew
 LOCAL_MODULE := libcorkscrew_test
 LOCAL_MODULE_TAGS := optional
 include $(BUILD_EXECUTABLE)
 
 
+# TODO: reenable darwin-x86
+# ifeq ($(HOST_ARCH),x86)
 ifeq ($(HOST_OS)-$(HOST_ARCH),linux-x86)
 
 # Build libcorkscrew.
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES += $(generic_src_files) $(x86_src_files)
 LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
-LOCAL_SHARED_LIBRARIES += libgccdemangle
-LOCAL_STATIC_LIBRARIES += libcutils
-LOCAL_LDLIBS += -ldl -lrt
-LOCAL_CFLAGS += -std=gnu99 -Werror
+LOCAL_STATIC_LIBRARIES += libcutils liblog
+LOCAL_LDLIBS += -ldl
+ifeq ($(HOST_OS),linux)
+  LOCAL_SHARED_LIBRARIES += libgccdemangle # TODO: is this even needed on Linux?
+  LOCAL_LDLIBS += -lrt
+endif
+LOCAL_CFLAGS += -std=gnu99 -Werror -Wno-unused-parameter
 LOCAL_MODULE := libcorkscrew
 LOCAL_MODULE_TAGS := optional
 include $(BUILD_HOST_SHARED_LIBRARY)
 
 # Build test.
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := test.c
-LOCAL_CFLAGS += -std=gnu99 -Werror -fno-inline-small-functions
+LOCAL_SRC_FILES := test.cpp
+LOCAL_CFLAGS += -Werror
 LOCAL_SHARED_LIBRARIES := libcorkscrew
 LOCAL_MODULE := libcorkscrew_test
 LOCAL_MODULE_TAGS := optional
 include $(BUILD_HOST_EXECUTABLE)
 
-endif # linux-x86
+endif # HOST_ARCH == x86
diff --git a/libcorkscrew/arch-arm/ptrace-arm.c b/libcorkscrew/arch-arm/ptrace-arm.c
index 868230c..78a9ea9 100644
--- a/libcorkscrew/arch-arm/ptrace-arm.c
+++ b/libcorkscrew/arch-arm/ptrace-arm.c
@@ -29,12 +29,15 @@
 static void load_exidx_header(pid_t pid, map_info_t* mi,
         uintptr_t* out_exidx_start, size_t* out_exidx_size) {
     uint32_t elf_phoff;
-    uint32_t elf_phentsize_phnum;
+    uint32_t elf_phentsize_ehsize;
+    uint32_t elf_shentsize_phnum;
     if (try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phoff), &elf_phoff)
+            && try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_ehsize),
+                    &elf_phentsize_ehsize)
             && try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phnum),
-                    &elf_phentsize_phnum)) {
-        uint32_t elf_phentsize = elf_phentsize_phnum >> 16;
-        uint32_t elf_phnum = elf_phentsize_phnum & 0xffff;
+                    &elf_shentsize_phnum)) {
+        uint32_t elf_phentsize = elf_phentsize_ehsize >> 16;
+        uint32_t elf_phnum = elf_shentsize_phnum & 0xffff;
         for (uint32_t i = 0; i < elf_phnum; i++) {
             uintptr_t elf_phdr = mi->start + elf_phoff + i * elf_phentsize;
             uint32_t elf_phdr_type;
diff --git a/libcorkscrew/arch-mips/backtrace-mips.c b/libcorkscrew/arch-mips/backtrace-mips.c
index 07d4a24..1abdd83 100644
--- a/libcorkscrew/arch-mips/backtrace-mips.c
+++ b/libcorkscrew/arch-mips/backtrace-mips.c
@@ -90,7 +90,8 @@
         if (frame)
             frame->stack_top = state->sp;
 
-        ALOGV("#%d: frame=%p pc=%08x sp=%08x\n", index, frame, frame->absolute_pc, frame->stack_top);
+        ALOGV("#%d: frame=%p pc=%08x sp=%08x\n",
+              index, frame, frame->absolute_pc, frame->stack_top);
 
         for (addr = state->pc; maxcheck-- > 0 && !found_start; addr -= 4) {
             uint32_t op;
@@ -115,7 +116,7 @@
                 ALOGV("@0x%08x: found ra offset=%d\n", addr, ra_offset);
                 break;
             case 0x3c1c0000: // lui gp
-                    ALOGV("@0x%08x: found function boundary\n", addr);
+                ALOGV("@0x%08x: found function boundary\n", addr);
                 found_start = true;
                 break;
             default:
@@ -162,7 +163,8 @@
     state.pc = uc->pc;
     state.ra = uc->ra;
 
-    ALOGV("unwind_backtrace_signal_arch: ignore_depth=%d max_depth=%d pc=0x%08x sp=0x%08x ra=0x%08x\n",
+    ALOGV("unwind_backtrace_signal_arch: "
+          "ignore_depth=%d max_depth=%d pc=0x%08x sp=0x%08x ra=0x%08x\n",
           ignore_depth, max_depth, state.pc, state.sp, state.ra);
 
     memory_t memory;
@@ -184,7 +186,8 @@
     state.ra = regs.regs[31];
     state.pc = regs.epc;
 
-    ALOGV("unwind_backtrace_ptrace_arch: ignore_depth=%d max_depth=%d pc=0x%08x sp=0x%08x ra=0x%08x\n",
+    ALOGV("unwind_backtrace_ptrace_arch: "
+          "ignore_depth=%d max_depth=%d pc=0x%08x sp=0x%08x ra=0x%08x\n",
           ignore_depth, max_depth, state.pc, state.sp, state.ra);
 
     memory_t memory;
diff --git a/libcorkscrew/arch-x86/backtrace-x86.c b/libcorkscrew/arch-x86/backtrace-x86.c
old mode 100644
new mode 100755
index fb79a0c..ef22821
--- a/libcorkscrew/arch-x86/backtrace-x86.c
+++ b/libcorkscrew/arch-x86/backtrace-x86.c
@@ -23,13 +23,16 @@
 
 #include "../backtrace-arch.h"
 #include "../backtrace-helper.h"
+#include "../ptrace-arch.h"
 #include <corkscrew/ptrace.h>
+#include "dwarf.h"
 
 #include <stdlib.h>
 #include <signal.h>
 #include <stdbool.h>
 #include <limits.h>
 #include <errno.h>
+#include <string.h>
 #include <sys/ptrace.h>
 #include <cutils/log.h>
 
@@ -72,53 +75,745 @@
 
 #endif /* __BIONIC_HAVE_UCONTEXT_T */
 
-#else /* __BIONIC__ */
+#elif defined(__APPLE__)
+
+#define _XOPEN_SOURCE
+#include <ucontext.h>
+
+#else
 
 // glibc has its own renaming of the Linux kernel's structures.
 #define __USE_GNU // For REG_EBP, REG_ESP, and REG_EIP.
 #include <ucontext.h>
 
-#endif /* __ BIONIC__ */
+#endif
 
 /* Unwind state. */
 typedef struct {
-    uint32_t ebp;
-    uint32_t eip;
-    uint32_t esp;
+    uint32_t reg[DWARF_REGISTERS];
 } unwind_state_t;
 
+typedef struct {
+    backtrace_frame_t* backtrace;
+    size_t ignore_depth;
+    size_t max_depth;
+    size_t ignored_frames;
+    size_t returned_frames;
+    memory_t memory;
+} backtrace_state_t;
+
 uintptr_t rewind_pc_arch(const memory_t* memory __attribute__((unused)), uintptr_t pc) {
-    // TODO: Implement for x86.
-    return pc;
+    /* TODO: x86 instructions are 1-16 bytes, to define exact size of previous instruction
+       we have to disassemble from the function entry point up to pc.
+       Returning pc-1 is probably enough for now, the only drawback is that
+       it points somewhere between the first byte of instruction we are looking for and
+       the first byte of the next instruction. */
+
+    return pc-1;
+    /* TODO: We should adjust that for the signal frames and return pc for them instead of pc-1.
+       To recognize signal frames we should read cie_info property. */
 }
 
-static ssize_t unwind_backtrace_common(const memory_t* memory,
-        const map_info_t* map_info_list __attribute__((unused)),
-        unwind_state_t* state, backtrace_frame_t* backtrace,
-        size_t ignore_depth, size_t max_depth) {
-    size_t ignored_frames = 0;
-    size_t returned_frames = 0;
+/* Read byte through 4 byte cache. Usually we read byte by byte and updating cursor. */
+static bool try_get_byte(const memory_t* memory, uintptr_t ptr, uint8_t* out_value, uint32_t* cursor) {
+    static uintptr_t lastptr;
+    static uint32_t buf;
 
-    for (size_t index = 0; state->ebp && returned_frames < max_depth; index++) {
-        backtrace_frame_t* frame = add_backtrace_entry(
-                index ? rewind_pc_arch(memory, state->eip) : state->eip,
-                backtrace, ignore_depth, max_depth,
-                &ignored_frames, &returned_frames);
-        uint32_t next_esp = state->ebp + 8;
-        if (frame) {
-            frame->stack_top = state->esp;
-            if (state->esp < next_esp) {
-                frame->stack_size = next_esp - state->esp;
-            }
+    ptr += *cursor;
+
+    if (ptr < lastptr || lastptr + 3 < ptr) {
+        lastptr = (ptr >> 2) << 2;
+        if (!try_get_word(memory, lastptr, &buf)) {
+            return false;
         }
-        state->esp = next_esp;
-        if (!try_get_word(memory, state->ebp + 4, &state->eip)
-                || !try_get_word(memory, state->ebp, &state->ebp)
-                || !state->eip) {
+    }
+    *out_value = (uint8_t)((buf >> ((ptr & 3) * 8)) & 0xff);
+    ++*cursor;
+    return true;
+}
+
+/* Getting X bytes. 4 is maximum for now. */
+static bool try_get_xbytes(const memory_t* memory, uintptr_t ptr, uint32_t* out_value, uint8_t bytes, uint32_t* cursor) {
+    uint32_t data = 0;
+    if (bytes > 4) {
+        ALOGE("can't read more than 4 bytes, trying to read %d", bytes);
+        return false;
+    }
+    for (int i = 0; i < bytes; i++) {
+        uint8_t buf;
+        if (!try_get_byte(memory, ptr, &buf, cursor)) {
+            return false;
+        }
+        data |= (uint32_t)buf << (i * 8);
+    }
+    *out_value = data;
+    return true;
+}
+
+/* Reads signed/unsigned LEB128 encoded data. From 1 to 4 bytes. */
+static bool try_get_leb128(const memory_t* memory, uintptr_t ptr, uint32_t* out_value, uint32_t* cursor, bool sign_extend) {
+    uint8_t buf = 0;
+    uint32_t val = 0;
+    uint8_t c = 0;
+    do {
+       if (!try_get_byte(memory, ptr, &buf, cursor)) {
+           return false;
+       }
+       val |= ((uint32_t)buf & 0x7f) << (c * 7);
+       c++;
+    } while (buf & 0x80 && (c * 7) <= 32);
+    if (c * 7 > 32) {
+       ALOGE("%s: data exceeds expected 4 bytes maximum", __FUNCTION__);
+       return false;
+    }
+    if (sign_extend) {
+        if (buf & 0x40) {
+            val |= ((uint32_t)-1 << (c * 7));
+        }
+    }
+    *out_value = val;
+    return true;
+}
+
+/* Reads signed LEB128 encoded data. From 1 to 4 bytes. */
+static bool try_get_sleb128(const memory_t* memory, uintptr_t ptr, uint32_t* out_value, uint32_t* cursor) {
+  return try_get_leb128(memory, ptr, out_value, cursor, true);
+}
+
+/* Reads unsigned LEB128 encoded data. From 1 to 4 bytes. */
+static bool try_get_uleb128(const memory_t* memory, uintptr_t ptr, uint32_t* out_value, uint32_t* cursor) {
+  return try_get_leb128(memory, ptr, out_value, cursor, false);
+}
+
+/* Getting data encoded by dwarf encodings. */
+static bool read_dwarf(const memory_t* memory, uintptr_t ptr, uint32_t* out_value, uint8_t encoding, uint32_t* cursor) {
+    uint32_t data = 0;
+    bool issigned = true;
+    uintptr_t addr = ptr + *cursor;
+    /* Lower 4 bits is data type/size */
+    /* TODO: add more encodings if it becomes necessary */
+    switch (encoding & 0xf) {
+        case DW_EH_PE_absptr:
+            if (!try_get_xbytes(memory, ptr, &data, 4, cursor)) {
+                return false;
+            }
+            *out_value = data;
+            return true;
+        case DW_EH_PE_udata4:
+            issigned = false;
+        case DW_EH_PE_sdata4:
+            if (!try_get_xbytes(memory, ptr, &data, 4, cursor)) {
+                return false;
+            }
             break;
+        default:
+            ALOGE("unrecognized dwarf lower part encoding: 0x%x", encoding);
+            return false;
+    }
+    /* Higher 4 bits is modifier */
+    /* TODO: add more encodings if it becomes necessary */
+    switch (encoding & 0xf0) {
+        case 0:
+            *out_value = data;
+            break;
+        case DW_EH_PE_pcrel:
+            if (issigned) {
+                *out_value = addr + (int32_t)data;
+            } else {
+                *out_value = addr + data;
+            }
+            break;
+        /* Assuming ptr is correct base to calculate datarel */
+        case DW_EH_PE_datarel:
+            if (issigned) {
+                *out_value = ptr + (int32_t)data;
+            } else {
+                *out_value = ptr + data;
+            }
+            break;
+        default:
+            ALOGE("unrecognized dwarf higher part encoding: 0x%x", encoding);
+            return false;
+    }
+    return true;
+}
+
+/* Having PC find corresponding FDE by reading .eh_frame_hdr section data. */
+static uintptr_t find_fde(const memory_t* memory,
+                          const map_info_t* map_info_list, uintptr_t pc) {
+    if (!pc) {
+        ALOGV("find_fde: pc is zero, no eh_frame");
+        return 0;
+    }
+    const map_info_t* mi = find_map_info(map_info_list, pc);
+    if (!mi) {
+        ALOGV("find_fde: no map info for pc:0x%x", pc);
+        return 0;
+    }
+    const map_info_data_t* midata = mi->data;
+    if (!midata) {
+        ALOGV("find_fde: no eh_frame_hdr for map: start=0x%x, end=0x%x", mi->start, mi->end);
+        return 0;
+    }
+
+    eh_frame_hdr_info_t eh_hdr_info;
+    memset(&eh_hdr_info, 0, sizeof(eh_frame_hdr_info_t));
+
+    /* Getting the first word of eh_frame_hdr:
+        1st byte is version;
+        2nd byte is encoding of pointer to eh_frames;
+        3rd byte is encoding of count of FDEs in lookup table;
+        4th byte is encoding of lookup table entries.
+    */
+    uintptr_t eh_frame_hdr = midata->eh_frame_hdr;
+    uint32_t c = 0;
+    if (!try_get_byte(memory, eh_frame_hdr, &eh_hdr_info.version, &c)) return 0;
+    if (!try_get_byte(memory, eh_frame_hdr, &eh_hdr_info.eh_frame_ptr_enc, &c)) return 0;
+    if (!try_get_byte(memory, eh_frame_hdr, &eh_hdr_info.fde_count_enc, &c)) return 0;
+    if (!try_get_byte(memory, eh_frame_hdr, &eh_hdr_info.fde_table_enc, &c)) return 0;
+
+    /* TODO: 3rd byte can be DW_EH_PE_omit, that means no lookup table available and we should
+       try to parse eh_frame instead. Not sure how often it may occur, skipping now.
+    */
+    if (eh_hdr_info.version != 1) {
+        ALOGV("find_fde: eh_frame_hdr version %d is not supported", eh_hdr_info.version);
+        return 0;
+    }
+    /* Getting the data:
+        2nd word is eh_frame pointer (normally not used, because lookup table has all we need);
+        3rd word is count of FDEs in the lookup table;
+        starting from 4 word there is FDE lookup table (pairs of PC and FDE pointer) sorted by PC;
+    */
+    if (!read_dwarf(memory, eh_frame_hdr, &eh_hdr_info.eh_frame_ptr, eh_hdr_info.eh_frame_ptr_enc, &c)) return 0;
+    if (!read_dwarf(memory, eh_frame_hdr, &eh_hdr_info.fde_count, eh_hdr_info.fde_count_enc, &c)) return 0;
+    ALOGV("find_fde: found %d FDEs", eh_hdr_info.fde_count);
+
+    int32_t low = 0;
+    int32_t high = eh_hdr_info.fde_count;
+    uintptr_t start = 0;
+    uintptr_t fde = 0;
+    /* eh_frame_hdr + c points to lookup table at this point. */
+    while (low <= high) {
+        uint32_t mid = (high + low)/2;
+        uint32_t entry = c + mid * 8;
+        if (!read_dwarf(memory, eh_frame_hdr, &start, eh_hdr_info.fde_table_enc, &entry)) return 0;
+        if (pc <= start) {
+            high = mid - 1;
+        } else {
+            low = mid + 1;
+        }
+    }
+    /* Value found is at high. */
+    if (high < 0) {
+        ALOGV("find_fde: pc %x is out of FDE bounds: %x", pc, start);
+        return 0;
+    }
+    c += high * 8;
+    if (!read_dwarf(memory, eh_frame_hdr, &start, eh_hdr_info.fde_table_enc, &c)) return 0;
+    if (!read_dwarf(memory, eh_frame_hdr, &fde, eh_hdr_info.fde_table_enc, &c)) return 0;
+    ALOGV("pc 0x%x, ENTRY %d: start=0x%x, fde=0x%x", pc, high, start, fde);
+    return fde;
+}
+
+/* Execute single dwarf instruction and update dwarf state accordingly. */
+static bool execute_dwarf(const memory_t* memory, uintptr_t ptr, cie_info_t* cie_info,
+                          dwarf_state_t* dstate, uint32_t* cursor,
+                          dwarf_state_t* stack, uint8_t* stack_ptr) {
+    uint8_t inst;
+    uint8_t op = 0;
+
+    if (!try_get_byte(memory, ptr, &inst, cursor)) {
+        return false;
+    }
+    ALOGV("DW_CFA inst: 0x%x", inst);
+
+    /* For some instructions upper 2 bits is opcode and lower 6 bits is operand. See dwarf-2.0 7.23. */
+    if (inst & 0xc0) {
+        op = inst & 0x3f;
+        inst &= 0xc0;
+    }
+
+    switch ((dwarf_CFA)inst) {
+        uint32_t reg = 0;
+        uint32_t offset = 0;
+        case DW_CFA_advance_loc:
+            dstate->loc += op * cie_info->code_align;
+            ALOGV("DW_CFA_advance_loc: %d to 0x%x", op, dstate->loc);
+            break;
+        case DW_CFA_offset:
+            if (!try_get_uleb128(memory, ptr, &offset, cursor)) return false;
+            dstate->regs[op].rule = 'o';
+            dstate->regs[op].value = offset * cie_info->data_align;
+            ALOGV("DW_CFA_offset: r%d = o(%d)", op, dstate->regs[op].value);
+            break;
+        case DW_CFA_restore:
+            dstate->regs[op].rule = stack->regs[op].rule;
+            dstate->regs[op].value = stack->regs[op].value;
+            ALOGV("DW_CFA_restore: r%d = %c(%d)", op, dstate->regs[op].rule, dstate->regs[op].value);
+            break;
+        case DW_CFA_nop:
+            break;
+        case DW_CFA_set_loc: // probably we don't have it on x86.
+            if (!try_get_xbytes(memory, ptr, &offset, 4, cursor)) return false;
+            if (offset < dstate->loc) {
+                ALOGE("DW_CFA_set_loc: attempt to move location backward");
+                return false;
+            }
+            dstate->loc = offset * cie_info->code_align;
+            ALOGV("DW_CFA_set_loc: %d to 0x%x", offset * cie_info->code_align, dstate->loc);
+            break;
+        case DW_CFA_advance_loc1:
+            if (!try_get_byte(memory, ptr, (uint8_t*)&offset, cursor)) return false;
+            dstate->loc += (uint8_t)offset * cie_info->code_align;
+            ALOGV("DW_CFA_advance_loc1: %d to 0x%x", (uint8_t)offset * cie_info->code_align, dstate->loc);
+            break;
+        case DW_CFA_advance_loc2:
+            if (!try_get_xbytes(memory, ptr, &offset, 2, cursor)) return false;
+            dstate->loc += (uint16_t)offset * cie_info->code_align;
+            ALOGV("DW_CFA_advance_loc2: %d to 0x%x", (uint16_t)offset * cie_info->code_align, dstate->loc);
+            break;
+        case DW_CFA_advance_loc4:
+            if (!try_get_xbytes(memory, ptr, &offset, 4, cursor)) return false;
+            dstate->loc += offset * cie_info->code_align;
+            ALOGV("DW_CFA_advance_loc4: %d to 0x%x", offset * cie_info->code_align, dstate->loc);
+            break;
+        case DW_CFA_offset_extended: // probably we don't have it on x86.
+            if (!try_get_uleb128(memory, ptr, &reg, cursor)) return false;
+            if (!try_get_uleb128(memory, ptr, &offset, cursor)) return false;
+            if (reg >= DWARF_REGISTERS) {
+                ALOGE("DW_CFA_offset_extended: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
+                return false;
+            }
+            dstate->regs[reg].rule = 'o';
+            dstate->regs[reg].value = offset * cie_info->data_align;
+            ALOGV("DW_CFA_offset_extended: r%d = o(%d)", reg, dstate->regs[reg].value);
+            break;
+        case DW_CFA_restore_extended: // probably we don't have it on x86.
+            if (!try_get_uleb128(memory, ptr, &reg, cursor)) return false;
+            if (reg >= DWARF_REGISTERS) {
+                ALOGE("DW_CFA_restore_extended: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
+                return false;
+            }
+            dstate->regs[reg].rule = stack->regs[reg].rule;
+            dstate->regs[reg].value = stack->regs[reg].value;
+            ALOGV("DW_CFA_restore: r%d = %c(%d)", reg, dstate->regs[reg].rule, dstate->regs[reg].value);
+            break;
+        case DW_CFA_undefined: // probably we don't have it on x86.
+            if (!try_get_uleb128(memory, ptr, &reg, cursor)) return false;
+            if (reg >= DWARF_REGISTERS) {
+                ALOGE("DW_CFA_undefined: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
+                return false;
+            }
+            dstate->regs[reg].rule = 'u';
+            dstate->regs[reg].value = 0;
+            ALOGV("DW_CFA_undefined: r%d", reg);
+            break;
+        case DW_CFA_same_value: // probably we don't have it on x86.
+            if (!try_get_uleb128(memory, ptr, &reg, cursor)) return false;
+            if (reg >= DWARF_REGISTERS) {
+                ALOGE("DW_CFA_undefined: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
+                return false;
+            }
+            dstate->regs[reg].rule = 's';
+            dstate->regs[reg].value = 0;
+            ALOGV("DW_CFA_same_value: r%d", reg);
+            break;
+        case DW_CFA_register: // probably we don't have it on x86.
+            if (!try_get_uleb128(memory, ptr, &reg, cursor)) return false;
+            /* that's new register actually, not offset */
+            if (!try_get_uleb128(memory, ptr, &offset, cursor)) return false;
+            if (reg >= DWARF_REGISTERS || offset >= DWARF_REGISTERS) {
+                ALOGE("DW_CFA_register: r%d or r%d exceeds supported number of registers (%d)", reg, offset, DWARF_REGISTERS);
+                return false;
+            }
+            dstate->regs[reg].rule = 'r';
+            dstate->regs[reg].value = offset;
+            ALOGV("DW_CFA_register: r%d = r(%d)", reg, dstate->regs[reg].value);
+            break;
+        case DW_CFA_remember_state:
+            if (*stack_ptr == DWARF_STATES_STACK) {
+                ALOGE("DW_CFA_remember_state: states stack overflow %d", *stack_ptr);
+                return false;
+            }
+            stack[(*stack_ptr)++] = *dstate;
+            ALOGV("DW_CFA_remember_state: stacktop moves to %d", *stack_ptr);
+            break;
+        case DW_CFA_restore_state:
+            /* We have CIE state saved at 0 position. It's not supposed to be taken
+               by DW_CFA_restore_state. */
+            if (*stack_ptr == 1) {
+                ALOGE("DW_CFA_restore_state: states stack is empty");
+                return false;
+            }
+            /* Don't touch location on restore. */
+            uintptr_t saveloc = dstate->loc;
+            *dstate = stack[--*stack_ptr];
+            dstate->loc = saveloc;
+            ALOGV("DW_CFA_restore_state: stacktop moves to %d", *stack_ptr);
+            break;
+        case DW_CFA_def_cfa:
+            if (!try_get_uleb128(memory, ptr, &reg, cursor)) return false;
+            if (!try_get_uleb128(memory, ptr, &offset, cursor)) return false;
+            dstate->cfa_reg = reg;
+            dstate->cfa_off = offset;
+            ALOGV("DW_CFA_def_cfa: %x(r%d)", offset, reg);
+            break;
+        case DW_CFA_def_cfa_register:
+            if (!try_get_uleb128(memory, ptr, &reg, cursor)) {
+                return false;
+            }
+            dstate->cfa_reg = reg;
+            ALOGV("DW_CFA_def_cfa_register: r%d", reg);
+            break;
+        case DW_CFA_def_cfa_offset:
+            if (!try_get_uleb128(memory, ptr, &offset, cursor)) {
+                return false;
+            }
+            dstate->cfa_off = offset;
+            ALOGV("DW_CFA_def_cfa_offset: %x", offset);
+            break;
+        default:
+            ALOGE("unrecognized DW_CFA_* instruction: 0x%x", inst);
+            return false;
+    }
+    return true;
+}
+
+/* Restoring particular register value based on dwarf state. */
+static bool get_old_register_value(const memory_t* memory, uint32_t cfa,
+                                   dwarf_state_t* dstate, uint8_t reg,
+                                   unwind_state_t* state, unwind_state_t* newstate) {
+    uint32_t addr;
+    switch (dstate->regs[reg].rule) {
+        case 0:
+            /* We don't have dstate updated for this register, so assuming value kept the same.
+               Normally we should look into state and return current value as the old one
+               but we don't have all registers in state to handle this properly */
+            ALOGV("get_old_register_value: value of r%d is the same", reg);
+            // for ESP if it's not updated by dwarf rule we assume it's equal to CFA
+            if (reg == DWARF_ESP) {
+                ALOGV("get_old_register_value: adjusting esp to CFA: 0x%x", cfa);
+                newstate->reg[reg] = cfa;
+            } else {
+                newstate->reg[reg] = state->reg[reg];
+            }
+            break;
+        case 'o':
+            addr = cfa + (int32_t)dstate->regs[reg].value;
+            if (!try_get_word(memory, addr, &newstate->reg[reg])) {
+                ALOGE("get_old_register_value: can't read from 0x%x", addr);
+                return false;
+            }
+            ALOGV("get_old_register_value: r%d at 0x%x is 0x%x", reg, addr, newstate->reg[reg]);
+            break;
+        case 'r':
+            /* We don't have all registers in state so don't even try to look at 'r' */
+            ALOGE("get_old_register_value: register lookup not implemented yet");
+            break;
+        default:
+            ALOGE("get_old_register_value: unexpected rule:%c value:%d for register %d",
+                   dstate->regs[reg].rule, (int32_t)dstate->regs[reg].value, reg);
+            return false;
+    }
+    return true;
+}
+
+/* Updaing state based on dwarf state. */
+static bool update_state(const memory_t* memory, unwind_state_t* state,
+                         dwarf_state_t* dstate) {
+    unwind_state_t newstate;
+    /* We can restore more registers here if we need them. Meanwile doing minimal work here. */
+    /* Getting CFA. */
+    uintptr_t cfa = 0;
+    if (dstate->cfa_reg == DWARF_ESP) {
+        cfa = state->reg[DWARF_ESP] + dstate->cfa_off;
+    } else if (dstate->cfa_reg == DWARF_EBP) {
+        cfa = state->reg[DWARF_EBP] + dstate->cfa_off;
+    } else {
+        ALOGE("update_state: unexpected CFA register: %d", dstate->cfa_reg);
+        return false;
+    }
+    ALOGV("update_state: new CFA: 0x%x", cfa);
+    /* Getting EIP. */
+    if (!get_old_register_value(memory, cfa, dstate, DWARF_EIP, state, &newstate)) return false;
+    /* Getting EBP. */
+    if (!get_old_register_value(memory, cfa, dstate, DWARF_EBP, state, &newstate)) return false;
+    /* Getting ESP. */
+    if (!get_old_register_value(memory, cfa, dstate, DWARF_ESP, state, &newstate)) return false;
+
+    ALOGV("update_state: IP:  0x%x; restore IP:  0x%x", state->reg[DWARF_EIP], newstate.reg[DWARF_EIP]);
+    ALOGV("update_state: EBP: 0x%x; restore EBP: 0x%x", state->reg[DWARF_EBP], newstate.reg[DWARF_EBP]);
+    ALOGV("update_state: ESP: 0x%x; restore ESP: 0x%x", state->reg[DWARF_ESP], newstate.reg[DWARF_ESP]);
+    *state = newstate;
+    return true;
+}
+
+/* Execute CIE and FDE instructions for FDE found with find_fde. */
+static bool execute_fde(const memory_t* memory,
+                        uintptr_t fde,
+                        unwind_state_t* state) {
+    uint32_t fde_length = 0;
+    uint32_t cie_length = 0;
+    uintptr_t cie = 0;
+    uintptr_t cie_offset = 0;
+    cie_info_t cie_i;
+    cie_info_t* cie_info = &cie_i;
+    fde_info_t fde_i;
+    fde_info_t* fde_info = &fde_i;
+    dwarf_state_t dwarf_state;
+    dwarf_state_t* dstate = &dwarf_state;
+    dwarf_state_t stack[DWARF_STATES_STACK];
+    uint8_t stack_ptr = 0;
+
+    memset(dstate, 0, sizeof(dwarf_state_t));
+    memset(cie_info, 0, sizeof(cie_info_t));
+    memset(fde_info, 0, sizeof(fde_info_t));
+
+    /* Read common CIE or FDE area:
+        1st word is length;
+        2nd word is ID: 0 for CIE, CIE pointer for FDE.
+    */
+    if (!try_get_word(memory, fde, &fde_length)) {
+        return false;
+    }
+    if ((int32_t)fde_length == -1) {
+        ALOGV("execute_fde: 64-bit dwarf detected, not implemented yet");
+        return false;
+    }
+    if (!try_get_word(memory, fde + 4, &cie_offset)) {
+        return false;
+    }
+    if (cie_offset == 0) {
+        /* This is CIE. We shouldn't be here normally. */
+        cie = fde;
+        cie_length = fde_length;
+    } else {
+        /* Find CIE. */
+        /* Positive cie_offset goes backward from current field. */
+        cie = fde + 4 - cie_offset;
+        if (!try_get_word(memory, cie, &cie_length)) {
+           return false;
+        }
+        if ((int32_t)cie_length == -1) {
+           ALOGV("execute_fde: 64-bit dwarf detected, not implemented yet");
+           return false;
+        }
+        if (!try_get_word(memory, cie + 4, &cie_offset)) {
+           return false;
+        }
+        if (cie_offset != 0) {
+           ALOGV("execute_fde: can't find CIE");
+           return false;
+        }
+    }
+    ALOGV("execute_fde: FDE length: %d", fde_length);
+    ALOGV("execute_fde: CIE pointer: %x", cie);
+    ALOGV("execute_fde: CIE length: %d", cie_length);
+
+    /* Read CIE:
+       Augmentation independent:
+        1st byte is version;
+        next x bytes is /0 terminated augmentation string;
+        next x bytes is unsigned LEB128 encoded code alignment factor;
+        next x bytes is signed LEB128 encoded data alignment factor;
+        next 1 (CIE version 1) or x (CIE version 3 unsigned LEB128) bytes is return register column;
+       Augmentation dependent:
+        if 'z' next x bytes is unsigned LEB128 encoded augmentation data size;
+        if 'L' next 1 byte is LSDA encoding;
+        if 'R' next 1 byte is FDE encoding;
+        if 'S' CIE represents signal handler stack frame;
+        if 'P' next 1 byte is personality encoding folowed by personality function pointer;
+       Next x bytes is CIE program.
+    */
+
+    uint32_t c = 8;
+    if (!try_get_byte(memory, cie, &cie_info->version, &c)) {
+       return false;
+    }
+    ALOGV("execute_fde: CIE version: %d", cie_info->version);
+    uint8_t ch;
+    do {
+        if (!try_get_byte(memory, cie, &ch, &c)) {
+           return false;
+        }
+        switch (ch) {
+           case '\0': break;
+           case 'z': cie_info->aug_z = 1; break;
+           case 'L': cie_info->aug_L = 1; break;
+           case 'R': cie_info->aug_R = 1; break;
+           case 'S': cie_info->aug_S = 1; break;
+           case 'P': cie_info->aug_P = 1; break;
+           default:
+              ALOGV("execute_fde: Unrecognized CIE augmentation char: '%c'", ch);
+              return false;
+              break;
+        }
+    } while (ch);
+    if (!try_get_uleb128(memory, cie, &cie_info->code_align, &c)) {
+        return false;
+    }
+    if (!try_get_sleb128(memory, cie, &cie_info->data_align, &c)) {
+        return false;
+    }
+    if (cie_info->version >= 3) {
+        if (!try_get_uleb128(memory, cie, &cie_info->reg, &c)) {
+            return false;
+        }
+    } else {
+        if (!try_get_byte(memory, cie, (uint8_t*)&cie_info->reg, &c)) {
+            return false;
+        }
+    }
+    ALOGV("execute_fde: CIE code alignment factor: %d", cie_info->code_align);
+    ALOGV("execute_fde: CIE data alignment factor: %d", cie_info->data_align);
+    if (cie_info->aug_z) {
+        if (!try_get_uleb128(memory, cie, &cie_info->aug_z, &c)) {
+            return false;
+        }
+    }
+    if (cie_info->aug_L) {
+        if (!try_get_byte(memory, cie, &cie_info->aug_L, &c)) {
+            return false;
+        }
+    } else {
+        /* Default encoding. */
+        cie_info->aug_L = DW_EH_PE_absptr;
+    }
+    if (cie_info->aug_R) {
+        if (!try_get_byte(memory, cie, &cie_info->aug_R, &c)) {
+            return false;
+        }
+    } else {
+        /* Default encoding. */
+        cie_info->aug_R = DW_EH_PE_absptr;
+    }
+    if (cie_info->aug_P) {
+        /* Get encoding of personality routine pointer. We don't use it now. */
+        if (!try_get_byte(memory, cie, (uint8_t*)&cie_info->aug_P, &c)) {
+            return false;
+        }
+        /* Get routine pointer. */
+        if (!read_dwarf(memory, cie, &cie_info->aug_P, (uint8_t)cie_info->aug_P, &c)) {
+            return false;
+        }
+    }
+    /* CIE program. */
+    /* Length field itself (4 bytes) is not included into length. */
+    stack[0] = *dstate;
+    stack_ptr = 1;
+    while (c < cie_length + 4) {
+        if (!execute_dwarf(memory, cie, cie_info, dstate, &c, stack, &stack_ptr)) {
+           return false;
         }
     }
 
+    /* We went directly to CIE. Normally it shouldn't occur. */
+    if (cie == fde) return true;
+
+    /* Go back to FDE. */
+    c = 8;
+    /* Read FDE:
+       Augmentation independent:
+        next x bytes (encoded as specified in CIE) is FDE starting address;
+        next x bytes (encoded as specified in CIE) is FDE number of instructions covered;
+       Augmentation dependent:
+        if 'z' next x bytes is unsigned LEB128 encoded augmentation data size;
+        if 'L' next x bytes is LSDA pointer (encoded as specified in CIE);
+       Next x bytes is FDE program.
+     */
+    if (!read_dwarf(memory, fde, &fde_info->start, (uint8_t)cie_info->aug_R, &c)) {
+        return false;
+    }
+    dstate->loc = fde_info->start;
+    ALOGV("execute_fde: FDE start: %x", dstate->loc);
+    if (!read_dwarf(memory, fde, &fde_info->length, 0, &c)) {
+        return false;
+    }
+    ALOGV("execute_fde: FDE length: %x", fde_info->length);
+    if (cie_info->aug_z) {
+        if (!try_get_uleb128(memory, fde, &fde_info->aug_z, &c)) {
+            return false;
+        }
+    }
+    if (cie_info->aug_L && cie_info->aug_L != DW_EH_PE_omit) {
+        if (!read_dwarf(memory, fde, &fde_info->aug_L, cie_info->aug_L, &c)) {
+            return false;
+        }
+    }
+    /* FDE program. */
+    /* Length field itself (4 bytes) is not included into length. */
+    /* Save CIE state as 0 element of stack. Used by DW_CFA_restore. */
+    stack[0] = *dstate;
+    stack_ptr = 1;
+    while (c < fde_length + 4 && state->reg[DWARF_EIP] >= dstate->loc) {
+        if (!execute_dwarf(memory, fde, cie_info, dstate, &c, stack, &stack_ptr)) {
+           return false;
+        }
+        ALOGV("IP: %x, LOC: %x", state->reg[DWARF_EIP], dstate->loc);
+    }
+
+    return update_state(memory, state, dstate);
+}
+
+static ssize_t unwind_backtrace_common(const memory_t* memory,
+        const map_info_t* map_info_list,
+        unwind_state_t* state, backtrace_frame_t* backtrace,
+        size_t ignore_depth, size_t max_depth) {
+
+    size_t ignored_frames = 0;
+    size_t returned_frames = 0;
+
+    ALOGV("Unwinding tid: %d", memory->tid);
+    ALOGV("IP: %x", state->reg[DWARF_EIP]);
+    ALOGV("BP: %x", state->reg[DWARF_EBP]);
+    ALOGV("SP: %x", state->reg[DWARF_ESP]);
+
+    for (size_t index = 0; returned_frames < max_depth; index++) {
+        uintptr_t fde = find_fde(memory, map_info_list, state->reg[DWARF_EIP]);
+        /* FDE is not found, it may happen if stack is corrupted or calling wrong adress.
+           Getting return address from stack.
+        */
+        if (!fde) {
+            uint32_t ip;
+            ALOGV("trying to restore registers from stack");
+            if (!try_get_word(memory, state->reg[DWARF_EBP] + 4, &ip) ||
+                ip == state->reg[DWARF_EIP]) {
+                ALOGV("can't get IP from stack");
+                break;
+            }
+            /* We've been able to get IP from stack so recording the frame before continue. */
+            backtrace_frame_t* frame = add_backtrace_entry(
+                    index ? rewind_pc_arch(memory, state->reg[DWARF_EIP]) : state->reg[DWARF_EIP],
+                    backtrace, ignore_depth, max_depth,
+                    &ignored_frames, &returned_frames);
+            state->reg[DWARF_EIP] = ip;
+            state->reg[DWARF_ESP] = state->reg[DWARF_EBP] + 8;
+            if (!try_get_word(memory, state->reg[DWARF_EBP], &state->reg[DWARF_EBP])) {
+                ALOGV("can't get EBP from stack");
+                break;
+            }
+            ALOGV("restore IP: %x", state->reg[DWARF_EIP]);
+            ALOGV("restore BP: %x", state->reg[DWARF_EBP]);
+            ALOGV("restore SP: %x", state->reg[DWARF_ESP]);
+            continue;
+        }
+        backtrace_frame_t* frame = add_backtrace_entry(
+                index ? rewind_pc_arch(memory, state->reg[DWARF_EIP]) : state->reg[DWARF_EIP],
+                backtrace, ignore_depth, max_depth,
+                &ignored_frames, &returned_frames);
+
+        uint32_t stack_top = state->reg[DWARF_ESP];
+
+        if (!execute_fde(memory, fde, state)) break;
+
+        if (frame) {
+            frame->stack_top = stack_top;
+            if (stack_top < state->reg[DWARF_ESP]) {
+                frame->stack_size = state->reg[DWARF_ESP] - stack_top;
+            }
+        }
+        ALOGV("Stack: 0x%x ... 0x%x - %d bytes", frame->stack_top, state->reg[DWARF_ESP], frame->stack_size);
+    }
     return returned_frames;
 }
 
@@ -128,9 +823,15 @@
     const ucontext_t* uc = (const ucontext_t*)sigcontext;
 
     unwind_state_t state;
-    state.ebp = uc->uc_mcontext.gregs[REG_EBP];
-    state.esp = uc->uc_mcontext.gregs[REG_ESP];
-    state.eip = uc->uc_mcontext.gregs[REG_EIP];
+#if defined(__APPLE__)
+    state.reg[DWARF_EBP] = uc->uc_mcontext->__ss.__ebp;
+    state.reg[DWARF_ESP] = uc->uc_mcontext->__ss.__esp;
+    state.reg[DWARF_EIP] = uc->uc_mcontext->__ss.__eip;
+#else
+    state.reg[DWARF_EBP] = uc->uc_mcontext.gregs[REG_EBP];
+    state.reg[DWARF_ESP] = uc->uc_mcontext.gregs[REG_ESP];
+    state.reg[DWARF_EIP] = uc->uc_mcontext.gregs[REG_EIP];
+#endif
 
     memory_t memory;
     init_memory(&memory, map_info_list);
@@ -140,18 +841,22 @@
 
 ssize_t unwind_backtrace_ptrace_arch(pid_t tid, const ptrace_context_t* context,
         backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
+#if defined(__APPLE__)
+    return -1;
+#else
     pt_regs_x86_t regs;
     if (ptrace(PTRACE_GETREGS, tid, 0, &regs)) {
         return -1;
     }
 
     unwind_state_t state;
-    state.ebp = regs.ebp;
-    state.eip = regs.eip;
-    state.esp = regs.esp;
+    state.reg[DWARF_EBP] = regs.ebp;
+    state.reg[DWARF_EIP] = regs.eip;
+    state.reg[DWARF_ESP] = regs.esp;
 
     memory_t memory;
     init_memory_ptrace(&memory, tid);
     return unwind_backtrace_common(&memory, context->map_info_list,
             &state, backtrace, ignore_depth, max_depth);
+#endif
 }
diff --git a/libcorkscrew/arch-x86/dwarf.h b/libcorkscrew/arch-x86/dwarf.h
new file mode 100755
index 0000000..962fc55
--- /dev/null
+++ b/libcorkscrew/arch-x86/dwarf.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+/*
+ * Dwarf2 data encoding flags.
+ */
+
+#define DW_EH_PE_absptr         0x00
+#define DW_EH_PE_omit           0xff
+#define DW_EH_PE_uleb128        0x01
+#define DW_EH_PE_udata2         0x02
+#define DW_EH_PE_udata4         0x03
+#define DW_EH_PE_udata8         0x04
+#define DW_EH_PE_sleb128        0x09
+#define DW_EH_PE_sdata2         0x0A
+#define DW_EH_PE_sdata4         0x0B
+#define DW_EH_PE_sdata8         0x0C
+#define DW_EH_PE_signed         0x08
+#define DW_EH_PE_pcrel          0x10
+#define DW_EH_PE_textrel        0x20
+#define DW_EH_PE_datarel        0x30
+#define DW_EH_PE_funcrel        0x40
+#define DW_EH_PE_aligned        0x50
+#define DW_EH_PE_indirect       0x80
+
+/*
+ * Dwarf2 call frame instructions.
+ */
+
+typedef enum {
+    DW_CFA_advance_loc = 0x40,
+    DW_CFA_offset = 0x80,
+    DW_CFA_restore = 0xc0,
+    DW_CFA_nop = 0x00,
+    DW_CFA_set_loc = 0x01,
+    DW_CFA_advance_loc1 = 0x02,
+    DW_CFA_advance_loc2 = 0x03,
+    DW_CFA_advance_loc4 = 0x04,
+    DW_CFA_offset_extended = 0x05,
+    DW_CFA_restore_extended = 0x06,
+    DW_CFA_undefined = 0x07,
+    DW_CFA_same_value = 0x08,
+    DW_CFA_register = 0x09,
+    DW_CFA_remember_state = 0x0a,
+    DW_CFA_restore_state = 0x0b,
+    DW_CFA_def_cfa = 0x0c,
+    DW_CFA_def_cfa_register = 0x0d,
+    DW_CFA_def_cfa_offset = 0x0e
+} dwarf_CFA;
+
+/*
+ * eh_frame_hdr information.
+*/
+
+typedef struct {
+      uint8_t version;
+      uint8_t eh_frame_ptr_enc;
+      uint8_t fde_count_enc;
+      uint8_t fde_table_enc;
+      uintptr_t eh_frame_ptr;
+      uint32_t fde_count;
+} eh_frame_hdr_info_t;
+
+/*
+ * CIE information.
+*/
+
+typedef struct {
+      uint8_t version;
+      uint32_t code_align;
+      uint32_t data_align;
+      uint32_t reg;
+      uint32_t aug_z;
+      uint8_t aug_L;
+      uint8_t aug_R;
+      uint8_t aug_S;
+      uint32_t aug_P;
+} cie_info_t;
+
+/*
+ * FDE information.
+*/
+
+typedef struct {
+      uint32_t start;
+      uint32_t length; // number of instructions covered by FDE
+      uint32_t aug_z;
+      uint32_t aug_L;
+} fde_info_t;
+
+/*
+ * Dwarf state.
+*/
+
+/* Stack of states: required for DW_CFA_remember_state/DW_CFA_restore_state
+   30 should be enough */
+#define DWARF_STATES_STACK 30
+
+typedef struct {
+    char rule;         // rule: o - offset(value); r - register(value)
+    uint32_t value;    // value
+} reg_rule_t;
+
+/* Dwarf preserved number of registers for x86. */
+
+#define DWARF_REGISTERS 17
+
+typedef struct {
+    uintptr_t loc;     // location (ip)
+    uint8_t cfa_reg;   // index of register where CFA location stored
+    intptr_t cfa_off;  // offset
+    reg_rule_t regs[DWARF_REGISTERS]; // dwarf preserved registers for x86
+} dwarf_state_t;
+
+/* DWARF registers we are caring about. */
+
+#define DWARF_EAX     0
+#define DWARF_ECX     1
+#define DWARF_EDX     2
+#define DWARF_EBX     3
+#define DWARF_ESP     4
+#define DWARF_EBP     5
+#define DWARF_ESI     6
+#define DWARF_EDI     7
+#define DWARF_EIP     8
+
+
diff --git a/libcorkscrew/arch-x86/ptrace-x86.c b/libcorkscrew/arch-x86/ptrace-x86.c
old mode 100644
new mode 100755
index 07cfd3a..9c49b93
--- a/libcorkscrew/arch-x86/ptrace-x86.c
+++ b/libcorkscrew/arch-x86/ptrace-x86.c
@@ -19,11 +19,44 @@
 
 #include "../ptrace-arch.h"
 
+#include <stddef.h>
+#include <elf.h>
 #include <cutils/log.h>
 
-void load_ptrace_map_info_data_arch(pid_t pid __attribute__((unused)),
-                                    map_info_t* mi __attribute__((unused)),
-                                    map_info_data_t* data __attribute__((unused))) {
+static void load_eh_frame_hdr(pid_t pid, map_info_t* mi, uintptr_t *eh_frame_hdr) {
+    uint32_t elf_phoff;
+    uint32_t elf_phentsize_ehsize;
+    uint32_t elf_shentsize_phnum;
+    if (try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phoff), &elf_phoff)
+            && try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_ehsize),
+                    &elf_phentsize_ehsize)
+            && try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phnum),
+                    &elf_shentsize_phnum)) {
+        uint32_t elf_phentsize = elf_phentsize_ehsize >> 16;
+        uint32_t elf_phnum = elf_shentsize_phnum & 0xffff;
+        for (uint32_t i = 0; i < elf_phnum; i++) {
+            uintptr_t elf_phdr = mi->start + elf_phoff + i * elf_phentsize;
+            uint32_t elf_phdr_type;
+            if (!try_get_word_ptrace(pid, elf_phdr + offsetof(Elf32_Phdr, p_type), &elf_phdr_type)) {
+                break;
+            }
+            if (elf_phdr_type == PT_GNU_EH_FRAME) {
+                uint32_t elf_phdr_offset;
+                if (!try_get_word_ptrace(pid, elf_phdr + offsetof(Elf32_Phdr, p_offset),
+                        &elf_phdr_offset)) {
+                    break;
+                }
+                *eh_frame_hdr = mi->start + elf_phdr_offset;
+                ALOGV("Parsed .eh_frame_hdr info for %s: start=0x%08x", mi->name, *eh_frame_hdr);
+                return;
+            }
+        }
+    }
+    *eh_frame_hdr = 0;
+}
+
+void load_ptrace_map_info_data_arch(pid_t pid, map_info_t* mi, map_info_data_t* data) {
+    load_eh_frame_hdr(pid, mi, &data->eh_frame_hdr);
 }
 
 void free_ptrace_map_info_data_arch(map_info_t* mi __attribute__((unused)),
diff --git a/libcorkscrew/backtrace.c b/libcorkscrew/backtrace.c
index 3697d18..b365e5b 100644
--- a/libcorkscrew/backtrace.c
+++ b/libcorkscrew/backtrace.c
@@ -33,18 +33,24 @@
 #include <unwind.h>
 #include <cutils/log.h>
 #include <cutils/atomic.h>
-#include <elf.h>
 
-#if HAVE_DLADDR
 #define __USE_GNU // For dladdr(3) in glibc.
 #include <dlfcn.h>
-#endif
 
 #if defined(__BIONIC__)
 
 // Bionic implements and exports gettid but only implements tgkill.
 extern int tgkill(int tgid, int tid, int sig);
 
+#elif defined(__APPLE__)
+
+#include <sys/syscall.h>
+
+// Mac OS >= 10.6 has a system call equivalent to Linux's gettid().
+static pid_t gettid() {
+  return syscall(SYS_thread_selfid);
+}
+
 #else
 
 // glibc doesn't implement or export either gettid or tgkill.
@@ -99,7 +105,7 @@
     state.returned_frames = 0;
     init_memory(&state.memory, milist);
 
-    _Unwind_Reason_Code rc =_Unwind_Backtrace(unwind_backtrace_callback, &state);
+    _Unwind_Reason_Code rc = _Unwind_Backtrace(unwind_backtrace_callback, &state);
 
     release_my_map_info_list(milist);
 
@@ -148,7 +154,9 @@
 
     ALOGV("Unwinding thread %d from thread %d.", tid, gettid());
 
-#ifdef CORKSCREW_HAVE_ARCH
+    // TODO: there's no tgkill(2) on Mac OS, so we'd either need the
+    // mach_port_t or the pthread_t rather than the tid.
+#if defined(CORKSCREW_HAVE_ARCH) && !defined(__APPLE__)
     struct sigaction act;
     struct sigaction oact;
     memset(&act, 0, sizeof(act));
@@ -256,7 +264,6 @@
             if (mi->name[0]) {
                 symbol->map_name = strdup(mi->name);
             }
-#if HAVE_DLADDR
             Dl_info info;
             if (dladdr((const void*)frame->absolute_pc, &info) && info.dli_sname) {
                 symbol->relative_symbol_addr = (uintptr_t)info.dli_saddr
@@ -264,7 +271,6 @@
                 symbol->symbol_name = strdup(info.dli_sname);
                 symbol->demangled_name = demangle_symbol_name(symbol->symbol_name);
             }
-#endif
         }
     }
     release_my_map_info_list(milist);
@@ -309,20 +315,20 @@
         const backtrace_symbol_t* symbol, char* buffer, size_t bufferSize) {
     const char* mapName = symbol->map_name ? symbol->map_name : "<unknown>";
     const char* symbolName = symbol->demangled_name ? symbol->demangled_name : symbol->symbol_name;
-    size_t fieldWidth = (bufferSize - 80) / 2;
+    int fieldWidth = (bufferSize - 80) / 2;
     if (symbolName) {
         uint32_t pc_offset = symbol->relative_pc - symbol->relative_symbol_addr;
         if (pc_offset) {
-            snprintf(buffer, bufferSize, "#%02d  pc %08x  %.*s (%.*s+%u)",
-                    frameNumber, symbol->relative_pc, fieldWidth, mapName,
+            snprintf(buffer, bufferSize, "#%02u  pc %p  %.*s (%.*s+%u)",
+                    frameNumber, (void*) symbol->relative_pc, fieldWidth, mapName,
                     fieldWidth, symbolName, pc_offset);
         } else {
-            snprintf(buffer, bufferSize, "#%02d  pc %08x  %.*s (%.*s)",
-                    frameNumber, symbol->relative_pc, fieldWidth, mapName,
+            snprintf(buffer, bufferSize, "#%02u  pc %p  %.*s (%.*s)",
+                    frameNumber, (void*) symbol->relative_pc, fieldWidth, mapName,
                     fieldWidth, symbolName);
         }
     } else {
-        snprintf(buffer, bufferSize, "#%02d  pc %08x  %.*s",
-                frameNumber, symbol->relative_pc, fieldWidth, mapName);
+        snprintf(buffer, bufferSize, "#%02u  pc %p  %.*s",
+                frameNumber, (void*) symbol->relative_pc, fieldWidth, mapName);
     }
 }
diff --git a/libcorkscrew/demangle.c b/libcorkscrew/demangle.c
index 54247cb..30ab1b0 100644
--- a/libcorkscrew/demangle.c
+++ b/libcorkscrew/demangle.c
@@ -25,6 +25,12 @@
                              int *status);
 
 char* demangle_symbol_name(const char* name) {
+#if defined(__APPLE__)
+    // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7.
+    if (name != NULL && name[0] != '_') {
+        return NULL;
+    }
+#endif
     // __cxa_demangle handles NULL by returning NULL
     return __cxa_demangle(name, 0, 0, 0);
 }
diff --git a/libcorkscrew/map_info.c b/libcorkscrew/map_info.c
index 3c52854..93dffbf 100644
--- a/libcorkscrew/map_info.c
+++ b/libcorkscrew/map_info.c
@@ -29,6 +29,67 @@
 #include <cutils/log.h>
 #include <sys/time.h>
 
+#if defined(__APPLE__)
+
+// Mac OS vmmap(1) output:
+// __TEXT                 0009f000-000a1000 [    8K     8K] r-x/rwx SM=COW  /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n
+// 012345678901234567890123456789012345678901234567890123456789
+// 0         1         2         3         4         5
+static map_info_t* parse_vmmap_line(const char* line) {
+    unsigned long int start;
+    unsigned long int end;
+    char permissions[4];
+    int name_pos;
+    if (sscanf(line, "%*21c %lx-%lx [%*13c] %3c/%*3c SM=%*3c  %n",
+               &start, &end, permissions, &name_pos) != 3) {
+        return NULL;
+    }
+
+    const char* name = line + name_pos;
+    size_t name_len = strlen(name);
+
+    map_info_t* mi = calloc(1, sizeof(map_info_t) + name_len);
+    if (mi != NULL) {
+        mi->start = start;
+        mi->end = end;
+        mi->is_readable = permissions[0] == 'r';
+        mi->is_writable = permissions[1] == 'w';
+        mi->is_executable = permissions[2] == 'x';
+        mi->data = NULL;
+        memcpy(mi->name, name, name_len);
+        mi->name[name_len - 1] = '\0';
+        ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
+              "is_readable=%d, is_writable=%d is_executable=%d, name=%s",
+              mi->start, mi->end,
+              mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
+    }
+    return mi;
+}
+
+map_info_t* load_map_info_list(pid_t pid) {
+    char cmd[1024];
+    snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid);
+    FILE* fp = popen(cmd, "r");
+    if (fp == NULL) {
+        return NULL;
+    }
+
+    char line[1024];
+    map_info_t* milist = NULL;
+    while (fgets(line, sizeof(line), fp) != NULL) {
+        map_info_t* mi = parse_vmmap_line(line);
+        if (mi != NULL) {
+            mi->next = milist;
+            milist = mi;
+        }
+    }
+    pclose(fp);
+    return milist;
+}
+
+#else
+
+// Linux /proc/<pid>/maps lines:
 // 6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so\n
 // 012345678901234567890123456789012345678901234567890123456789
 // 0         1         2         3         4         5
@@ -57,13 +118,15 @@
         mi->start = start;
         mi->end = end;
         mi->is_readable = strlen(permissions) == 4 && permissions[0] == 'r';
+        mi->is_writable = strlen(permissions) == 4 && permissions[1] == 'w';
         mi->is_executable = strlen(permissions) == 4 && permissions[2] == 'x';
         mi->data = NULL;
         memcpy(mi->name, name, name_len);
         mi->name[name_len] = '\0';
         ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
-                "is_readable=%d, is_executable=%d, name=%s",
-                mi->start, mi->end, mi->is_readable, mi->is_executable, mi->name);
+              "is_readable=%d, is_writable=%d, is_executable=%d, name=%s",
+              mi->start, mi->end,
+              mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
     }
     return mi;
 }
@@ -89,6 +152,8 @@
     return milist;
 }
 
+#endif
+
 void free_map_info_list(map_info_t* milist) {
     while (milist) {
         map_info_t* next = milist->next;
@@ -110,6 +175,11 @@
     return mi && mi->is_readable;
 }
 
+bool is_writable_map(const map_info_t* milist, uintptr_t addr) {
+    const map_info_t* mi = find_map_info(milist, addr);
+    return mi && mi->is_writable;
+}
+
 bool is_executable_map(const map_info_t* milist, uintptr_t addr) {
     const map_info_t* mi = find_map_info(milist, addr);
     return mi && mi->is_executable;
@@ -125,11 +195,17 @@
     int64_t timestamp;
 } my_map_info_data_t;
 
-static int64_t now() {
+static int64_t now_ns() {
+#if defined(HAVE_POSIX_CLOCKS)
     struct timespec t;
     t.tv_sec = t.tv_nsec = 0;
     clock_gettime(CLOCK_MONOTONIC, &t);
     return t.tv_sec * 1000000000LL + t.tv_nsec;
+#else
+    struct timeval t;
+    gettimeofday(&t, NULL);
+    return t.tv_sec * 1000000000LL + t.tv_usec * 1000LL;
+#endif
 }
 
 static void dec_ref(map_info_t* milist, my_map_info_data_t* data) {
@@ -143,8 +219,8 @@
 map_info_t* acquire_my_map_info_list() {
     pthread_mutex_lock(&g_my_map_info_list_mutex);
 
-    int64_t time = now();
-    if (g_my_map_info_list) {
+    int64_t time = now_ns();
+    if (g_my_map_info_list != NULL) {
         my_map_info_data_t* data = (my_map_info_data_t*)g_my_map_info_list->data;
         int64_t age = time - data->timestamp;
         if (age >= MAX_CACHE_AGE) {
@@ -156,10 +232,10 @@
         }
     }
 
-    if (!g_my_map_info_list) {
+    if (g_my_map_info_list == NULL) {
         my_map_info_data_t* data = (my_map_info_data_t*)malloc(sizeof(my_map_info_data_t));
         g_my_map_info_list = load_map_info_list(getpid());
-        if (g_my_map_info_list) {
+        if (g_my_map_info_list != NULL) {
             ALOGV("Loaded my_map_info_list %p.", g_my_map_info_list);
             g_my_map_info_list->data = data;
             data->refs = 1;
@@ -189,3 +265,15 @@
         pthread_mutex_unlock(&g_my_map_info_list_mutex);
     }
 }
+
+void flush_my_map_info_list() {
+    pthread_mutex_lock(&g_my_map_info_list_mutex);
+
+    if (g_my_map_info_list != NULL) {
+        my_map_info_data_t* data = (my_map_info_data_t*) g_my_map_info_list->data;
+        dec_ref(g_my_map_info_list, data);
+        g_my_map_info_list = NULL;
+    }
+
+    pthread_mutex_unlock(&g_my_map_info_list_mutex);
+}
diff --git a/libcorkscrew/ptrace-arch.h b/libcorkscrew/ptrace-arch.h
old mode 100644
new mode 100755
index c02df52..4451c29
--- a/libcorkscrew/ptrace-arch.h
+++ b/libcorkscrew/ptrace-arch.h
@@ -33,6 +33,8 @@
 #ifdef __arm__
     uintptr_t exidx_start;
     size_t exidx_size;
+#elif __i386__
+    uintptr_t eh_frame_hdr;
 #endif
     symbol_table_t* symbol_table;
 } map_info_data_t;
diff --git a/libcorkscrew/ptrace.c b/libcorkscrew/ptrace.c
index 6496d5e..be58f7f 100644
--- a/libcorkscrew/ptrace.c
+++ b/libcorkscrew/ptrace.c
@@ -46,21 +46,25 @@
 }
 
 bool try_get_word(const memory_t* memory, uintptr_t ptr, uint32_t* out_value) {
-    ALOGV("try_get_word: reading word at 0x%08x", ptr);
+    ALOGV("try_get_word: reading word at %p", (void*) ptr);
     if (ptr & 3) {
-        ALOGV("try_get_word: invalid pointer 0x%08x", ptr);
+        ALOGV("try_get_word: invalid pointer %p", (void*) ptr);
         *out_value = 0xffffffffL;
         return false;
     }
     if (memory->tid < 0) {
         if (!is_readable_map(memory->map_info_list, ptr)) {
-            ALOGV("try_get_word: pointer 0x%08x not in a readable map", ptr);
+            ALOGV("try_get_word: pointer %p not in a readable map", (void*) ptr);
             *out_value = 0xffffffffL;
             return false;
         }
         *out_value = *(uint32_t*)ptr;
         return true;
     } else {
+#if defined(__APPLE__)
+        ALOGV("no ptrace on Mac OS");
+        return false;
+#else
         // ptrace() returns -1 and sets errno when the operation fails.
         // To disambiguate -1 from a valid result, we clear errno beforehand.
         errno = 0;
@@ -71,6 +75,7 @@
             return false;
         }
         return true;
+#endif
     }
 }
 
@@ -129,6 +134,7 @@
         free_ptrace_map_info_data(mi);
     }
     free_map_info_list(context->map_info_list);
+    free(context);
 }
 
 void find_symbol_ptrace(const ptrace_context_t* context,
diff --git a/libcorkscrew/symbol_table.c b/libcorkscrew/symbol_table.c
index 29e4a79..982ccc8 100644
--- a/libcorkscrew/symbol_table.c
+++ b/libcorkscrew/symbol_table.c
@@ -21,13 +21,17 @@
 
 #include <stdbool.h>
 #include <stdlib.h>
-#include <elf.h>
 #include <fcntl.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/mman.h>
 #include <cutils/log.h>
 
+#if defined(__APPLE__)
+#else
+
+#include <elf.h>
+
 static bool is_elf(Elf32_Ehdr* e) {
     return (e->e_ident[EI_MAG0] == ELFMAG0 &&
             e->e_ident[EI_MAG1] == ELFMAG1 &&
@@ -35,6 +39,8 @@
             e->e_ident[EI_MAG3] == ELFMAG3);
 }
 
+#endif
+
 // Compare function for qsort
 static int qcompar(const void *a, const void *b) {
     const symbol_t* asym = (const symbol_t*)a;
@@ -55,6 +61,7 @@
 
 symbol_table_t* load_symbol_table(const char *filename) {
     symbol_table_t* table = NULL;
+#if !defined(__APPLE__)
     ALOGV("Loading symbol table from '%s'.", filename);
 
     int fd = open(filename, O_RDONLY);
@@ -197,6 +204,7 @@
 
 out_close:
     close(fd);
+#endif
 
 out:
     return table;
diff --git a/libcorkscrew/test.c b/libcorkscrew/test.cpp
similarity index 77%
rename from libcorkscrew/test.c
rename to libcorkscrew/test.cpp
index af34c03..22dfa7d 100644
--- a/libcorkscrew/test.c
+++ b/libcorkscrew/test.cpp
@@ -3,11 +3,14 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-void do_backtrace() {
+int do_backtrace(float /* just to test demangling */) {
   const size_t MAX_DEPTH = 32;
   backtrace_frame_t* frames = (backtrace_frame_t*) malloc(sizeof(backtrace_frame_t) * MAX_DEPTH);
   ssize_t frame_count = unwind_backtrace(frames, 0, MAX_DEPTH);
   fprintf(stderr, "frame_count=%d\n", (int) frame_count);
+  if (frame_count <= 0) {
+    return frame_count;
+  }
 
   backtrace_symbol_t* backtrace_symbols = (backtrace_symbol_t*) malloc(sizeof(backtrace_symbol_t) * frame_count);
   get_backtrace_symbols(frames, frame_count, backtrace_symbols);
@@ -31,7 +34,7 @@
         symbol = find_symbol(symbols, frames[i].absolute_pc);
       }
       if (symbol != NULL) {
-        uintptr_t offset = frames[i].absolute_pc - symbol->start;
+        int offset = frames[i].absolute_pc - symbol->start;
         fprintf(stderr, "  %s (%s%+d)\n", line, symbol->name, offset);
       } else {
         fprintf(stderr, "  %s (\?\?\?)\n", line);
@@ -43,22 +46,31 @@
   free_backtrace_symbols(backtrace_symbols, frame_count);
   free(backtrace_symbols);
   free(frames);
+  return frame_count;
 }
 
-__attribute__ ((noinline)) void g() {
-  fprintf(stderr, "g()\n");
-  do_backtrace();
-}
+struct C {
+  int g(int i);
+};
 
-__attribute__ ((noinline)) int f(int i) {
-  fprintf(stderr, "f(%i)\n", i);
+__attribute__ ((noinline)) int C::g(int i) {
   if (i == 0) {
-    g();
-    return 0;
+    return do_backtrace(0.1);
   }
-  return f(i - 1);
+  return g(i - 1);
+}
+
+extern "C" __attribute__ ((noinline)) int f() {
+  C c;
+  return c.g(5);
 }
 
 int main() {
-  return f(5);
+  flush_my_map_info_list();
+  f();
+
+  flush_my_map_info_list();
+  f();
+
+  return 0;
 }
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index d9bd8d8..5037705 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -77,12 +77,8 @@
         abort_socket.c \
         fs.c \
         selector.c \
-        tztime.c \
         multiuser.c \
         zygote.c
-
-    commonHostSources += \
-        tzstrftime.c
 endif
 
 
@@ -125,6 +121,7 @@
         mq.c \
         partition_utils.c \
         qtaguid.c \
+        trace.c \
         uevent.c
 
 ifeq ($(TARGET_ARCH),arm)
@@ -134,7 +131,11 @@
 LOCAL_CFLAGS += -DHAVE_MEMSET16 -DHAVE_MEMSET32
 LOCAL_SRC_FILES += arch-x86/android_memset16.S arch-x86/android_memset32.S memory.c
 else # !x86-atom
+ifeq ($(TARGET_ARCH),mips)
+LOCAL_SRC_FILES += arch-mips/android_memset.c
+else # !mips
 LOCAL_SRC_FILES += memory.c
+endif # !mips
 endif # !x86-atom
 endif # !arm
 
@@ -145,7 +146,9 @@
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := libcutils
-LOCAL_WHOLE_STATIC_LIBRARIES := libcutils
+# TODO: remove liblog as whole static library, once we don't have prebuilt that requires
+# liblog symbols present in libcutils.
+LOCAL_WHOLE_STATIC_LIBRARIES := libcutils liblog
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_CFLAGS += $(targetSmpFlag)
 LOCAL_C_INCLUDES := $(libcutils_c_includes)
@@ -158,3 +161,5 @@
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_MODULE_TAGS := optional
 include $(BUILD_EXECUTABLE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libcutils/arch-mips/android_memset.c b/libcutils/arch-mips/android_memset.c
new file mode 100644
index 0000000..bbc99fe
--- /dev/null
+++ b/libcutils/arch-mips/android_memset.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2012 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/memory.h>
+
+/* Use mips-assembler versions supplied by bionic/libc/arch-mips/string/memset.S: */
+void _memset16(uint16_t* dst, uint16_t value, size_t size);
+void _memset32(uint32_t* dst, uint32_t value, size_t size);
+
+void android_memset16(uint16_t* dst, uint16_t value, size_t size)
+{
+    _memset16(dst, value, size);
+}
+
+void android_memset32(uint32_t* dst, uint32_t value, size_t size)
+{
+    _memset32(dst, value, size);
+}
diff --git a/libcutils/ashmem-dev.c b/libcutils/ashmem-dev.c
index 8b71f87..3089a94 100644
--- a/libcutils/ashmem-dev.c
+++ b/libcutils/ashmem-dev.c
@@ -48,7 +48,7 @@
 		return fd;
 
 	if (name) {
-		char buf[ASHMEM_NAME_LEN];
+		char buf[ASHMEM_NAME_LEN] = {0};
 
 		strlcpy(buf, name, sizeof(buf));
 		ret = ioctl(fd, ASHMEM_SET_NAME, buf);
diff --git a/libcutils/fs.c b/libcutils/fs.c
index 1226d44..116526d 100644
--- a/libcutils/fs.c
+++ b/libcutils/fs.c
@@ -26,6 +26,7 @@
 #include <errno.h>
 #include <string.h>
 #include <limits.h>
+#include <stdlib.h>
 
 #define ALL_PERMS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
 #define BUF_SIZE 64
diff --git a/libcutils/klog.c b/libcutils/klog.c
index b586a57..812af3b 100644
--- a/libcutils/klog.c
+++ b/libcutils/klog.c
@@ -35,6 +35,9 @@
 void klog_init(void)
 {
     static const char *name = "/dev/__kmsg__";
+
+    if (klog_fd >= 0) return; /* Already initialized */
+
     if (mknod(name, S_IFCHR | 0600, (1 << 8) | 11) == 0) {
         klog_fd = open(name, O_WRONLY);
         fcntl(klog_fd, F_SETFD, FD_CLOEXEC);
@@ -50,7 +53,7 @@
     va_list ap;
 
     if (level > klog_level) return;
-    if (klog_fd < 0) return;
+    if (klog_fd < 0) klog_init();
 
     va_start(ap, fmt);
     vsnprintf(buf, LOG_BUF_MAX, fmt, ap);
diff --git a/libcutils/private.h b/libcutils/private.h
deleted file mode 100644
index 2837b70..0000000
--- a/libcutils/private.h
+++ /dev/null
@@ -1,368 +0,0 @@
-#ifndef PRIVATE_H
-
-#define PRIVATE_H
-
-/*
-** This file is in the public domain, so clarified as of
-** 1996-06-05 by Arthur David Olson.
-*/
-
-/*
-** This header is for use ONLY with the time conversion code.
-** There is no guarantee that it will remain unchanged,
-** or that it will remain at all.
-** Do NOT copy it to any system include directory.
-** Thank you!
-*/
-
-/*
-** ID
-*/
-
-#ifndef lint
-#ifndef NOID
-static char	privatehid[] = "@(#)private.h	8.2";
-#endif /* !defined NOID */
-#endif /* !defined lint */
-
-#define GRANDPARENTED	"Local time zone must be set--see zic manual page"
-
-/*
-** Defaults for preprocessor symbols.
-** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'.
-*/
-
-#ifndef HAVE_ADJTIME
-#define HAVE_ADJTIME		1
-#endif /* !defined HAVE_ADJTIME */
-
-#ifndef HAVE_GETTEXT
-#define HAVE_GETTEXT		0
-#endif /* !defined HAVE_GETTEXT */
-
-#ifndef HAVE_INCOMPATIBLE_CTIME_R
-#define HAVE_INCOMPATIBLE_CTIME_R	0
-#endif /* !defined INCOMPATIBLE_CTIME_R */
-
-#ifndef HAVE_SETTIMEOFDAY
-#define HAVE_SETTIMEOFDAY	3
-#endif /* !defined HAVE_SETTIMEOFDAY */
-
-#ifndef HAVE_STRERROR
-#define HAVE_STRERROR		1
-#endif /* !defined HAVE_STRERROR */
-
-#ifndef HAVE_SYMLINK
-#define HAVE_SYMLINK		1
-#endif /* !defined HAVE_SYMLINK */
-
-#ifndef HAVE_SYS_STAT_H
-#define HAVE_SYS_STAT_H		1
-#endif /* !defined HAVE_SYS_STAT_H */
-
-#ifndef HAVE_SYS_WAIT_H
-#define HAVE_SYS_WAIT_H		1
-#endif /* !defined HAVE_SYS_WAIT_H */
-
-#ifndef HAVE_UNISTD_H
-#define HAVE_UNISTD_H		1
-#endif /* !defined HAVE_UNISTD_H */
-
-#ifndef HAVE_UTMPX_H
-#define HAVE_UTMPX_H		0
-#endif /* !defined HAVE_UTMPX_H */
-
-#ifndef LOCALE_HOME
-#define LOCALE_HOME		"/usr/lib/locale"
-#endif /* !defined LOCALE_HOME */
-
-#if HAVE_INCOMPATIBLE_CTIME_R
-#define asctime_r _incompatible_asctime_r
-#define ctime_r _incompatible_ctime_r
-#endif /* HAVE_INCOMPATIBLE_CTIME_R */
-
-/*
-** Nested includes
-*/
-
-#include "sys/types.h"	/* for time_t */
-#include "stdio.h"
-#include "errno.h"
-#include "string.h"
-#include "limits.h"	/* for CHAR_BIT et al. */
-#include "time.h"
-#include "stdlib.h"
-
-#if HAVE_GETTEXT
-#include "libintl.h"
-#endif /* HAVE_GETTEXT */
-
-#if HAVE_SYS_WAIT_H
-#include <sys/wait.h>	/* for WIFEXITED and WEXITSTATUS */
-#endif /* HAVE_SYS_WAIT_H */
-
-#ifndef WIFEXITED
-#define WIFEXITED(status)	(((status) & 0xff) == 0)
-#endif /* !defined WIFEXITED */
-#ifndef WEXITSTATUS
-#define WEXITSTATUS(status)	(((status) >> 8) & 0xff)
-#endif /* !defined WEXITSTATUS */
-
-#if HAVE_UNISTD_H
-#include "unistd.h"	/* for F_OK and R_OK */
-#endif /* HAVE_UNISTD_H */
-
-#if !HAVE_UNISTD_H
-#ifndef F_OK
-#define F_OK	0
-#endif /* !defined F_OK */
-#ifndef R_OK
-#define R_OK	4
-#endif /* !defined R_OK */
-#endif /* !HAVE_UNISTD_H */
-
-/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
-#define is_digit(c) ((unsigned)(c) - '0' <= 9)
-
-/*
-** Define HAVE_STDINT_H's default value here, rather than at the
-** start, since __GLIBC__'s value depends on previously-included
-** files.
-** (glibc 2.1 and later have stdint.h, even with pre-C99 compilers.)
-*/
-#ifndef HAVE_STDINT_H
-#define HAVE_STDINT_H \
-	(199901 <= __STDC_VERSION__ || \
-	2 < (__GLIBC__ + (0 < __GLIBC_MINOR__)))
-#endif /* !defined HAVE_STDINT_H */
-
-#if HAVE_STDINT_H
-#include "stdint.h"
-#endif /* !HAVE_STDINT_H */
-
-#ifndef INT_FAST64_MAX
-/* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX.  */
-#if defined LLONG_MAX || defined __LONG_LONG_MAX__
-typedef long long	int_fast64_t;
-#else /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
-#if (LONG_MAX >> 31) < 0xffffffff
-Please use a compiler that supports a 64-bit integer type (or wider);
-you may need to compile with "-DHAVE_STDINT_H".
-#endif /* (LONG_MAX >> 31) < 0xffffffff */
-typedef long		int_fast64_t;
-#endif /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
-#endif /* !defined INT_FAST64_MAX */
-
-#ifndef INT32_MAX
-#define INT32_MAX 0x7fffffff
-#endif /* !defined INT32_MAX */
-#ifndef INT32_MIN
-#define INT32_MIN (-1 - INT32_MAX)
-#endif /* !defined INT32_MIN */
-
-/*
-** Workarounds for compilers/systems.
-*/
-
-/*
-** If your compiler lacks prototypes, "#define P(x) ()".
-*/
-
-#ifndef P
-#define P(x)	x
-#endif /* !defined P */
-
-/*
-** SunOS 4.1.1 headers lack EXIT_SUCCESS.
-*/
-
-#ifndef EXIT_SUCCESS
-#define EXIT_SUCCESS	0
-#endif /* !defined EXIT_SUCCESS */
-
-/*
-** SunOS 4.1.1 headers lack EXIT_FAILURE.
-*/
-
-#ifndef EXIT_FAILURE
-#define EXIT_FAILURE	1
-#endif /* !defined EXIT_FAILURE */
-
-/*
-** SunOS 4.1.1 headers lack FILENAME_MAX.
-*/
-
-#ifndef FILENAME_MAX
-
-#ifndef MAXPATHLEN
-#ifdef unix
-#include "sys/param.h"
-#endif /* defined unix */
-#endif /* !defined MAXPATHLEN */
-
-#ifdef MAXPATHLEN
-#define FILENAME_MAX	MAXPATHLEN
-#endif /* defined MAXPATHLEN */
-#ifndef MAXPATHLEN
-#define FILENAME_MAX	1024		/* Pure guesswork */
-#endif /* !defined MAXPATHLEN */
-
-#endif /* !defined FILENAME_MAX */
-
-/*
-** SunOS 4.1.1 libraries lack remove.
-*/
-
-#ifndef remove
-extern int	unlink P((const char * filename));
-#define remove	unlink
-#endif /* !defined remove */
-
-/*
-** Some ancient errno.h implementations don't declare errno.
-** But some newer errno.h implementations define it as a macro.
-** Fix the former without affecting the latter.
-*/
-
-#ifndef errno
-extern int errno;
-#endif /* !defined errno */
-
-/*
-** Some time.h implementations don't declare asctime_r.
-** Others might define it as a macro.
-** Fix the former without affecting the latter.
-*/
-
-#ifndef asctime_r
-extern char *	asctime_r();
-#endif
-
-/*
-** Private function declarations.
-*/
-
-char *		icalloc P((int nelem, int elsize));
-char *		icatalloc P((char * old, const char * new));
-char *		icpyalloc P((const char * string));
-char *		imalloc P((int n));
-void *		irealloc P((void * pointer, int size));
-void		icfree P((char * pointer));
-void		ifree P((char * pointer));
-const char *	scheck P((const char * string, const char * format));
-
-/*
-** Finally, some convenience items.
-*/
-
-#ifndef TRUE
-#define TRUE	1
-#endif /* !defined TRUE */
-
-#ifndef FALSE
-#define FALSE	0
-#endif /* !defined FALSE */
-
-#ifndef TYPE_BIT
-#define TYPE_BIT(type)	(sizeof (type) * CHAR_BIT)
-#endif /* !defined TYPE_BIT */
-
-#ifndef TYPE_SIGNED
-#define TYPE_SIGNED(type) (((type) -1) < 0)
-#endif /* !defined TYPE_SIGNED */
-
-/*
-** Since the definition of TYPE_INTEGRAL contains floating point numbers,
-** it cannot be used in preprocessor directives.
-*/
-
-#ifndef TYPE_INTEGRAL
-#define TYPE_INTEGRAL(type) (((type) 0.5) != 0.5)
-#endif /* !defined TYPE_INTEGRAL */
-
-#ifndef INT_STRLEN_MAXIMUM
-/*
-** 302 / 1000 is log10(2.0) rounded up.
-** Subtract one for the sign bit if the type is signed;
-** add one for integer division truncation;
-** add one more for a minus sign if the type is signed.
-*/
-#define INT_STRLEN_MAXIMUM(type) \
-	((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \
-	1 + TYPE_SIGNED(type))
-#endif /* !defined INT_STRLEN_MAXIMUM */
-
-/*
-** INITIALIZE(x)
-*/
-
-#ifndef GNUC_or_lint
-#ifdef lint
-#define GNUC_or_lint
-#endif /* defined lint */
-#ifndef lint
-#ifdef __GNUC__
-#define GNUC_or_lint
-#endif /* defined __GNUC__ */
-#endif /* !defined lint */
-#endif /* !defined GNUC_or_lint */
-
-#ifndef INITIALIZE
-#ifdef GNUC_or_lint
-#define INITIALIZE(x)	((x) = 0)
-#endif /* defined GNUC_or_lint */
-#ifndef GNUC_or_lint
-#define INITIALIZE(x)
-#endif /* !defined GNUC_or_lint */
-#endif /* !defined INITIALIZE */
-
-/*
-** For the benefit of GNU folk...
-** `_(MSGID)' uses the current locale's message library string for MSGID.
-** The default is to use gettext if available, and use MSGID otherwise.
-*/
-
-#ifndef _
-#if HAVE_GETTEXT
-#define _(msgid) gettext(msgid)
-#else /* !HAVE_GETTEXT */
-#define _(msgid) msgid
-#endif /* !HAVE_GETTEXT */
-#endif /* !defined _ */
-
-#ifndef TZ_DOMAIN
-#define TZ_DOMAIN "tz"
-#endif /* !defined TZ_DOMAIN */
-
-#if HAVE_INCOMPATIBLE_CTIME_R
-#undef asctime_r
-#undef ctime_r
-char *asctime_r P((struct tm const *, char *));
-char *ctime_r P((time_t const *, char *));
-#endif /* HAVE_INCOMPATIBLE_CTIME_R */
-
-#ifndef YEARSPERREPEAT
-#define YEARSPERREPEAT		400	/* years before a Gregorian repeat */
-#endif /* !defined YEARSPERREPEAT */
-
-/*
-** The Gregorian year averages 365.2425 days, which is 31556952 seconds.
-*/
-
-#ifndef AVGSECSPERYEAR
-#define AVGSECSPERYEAR		31556952L
-#endif /* !defined AVGSECSPERYEAR */
-
-#ifndef SECSPERREPEAT
-#define SECSPERREPEAT		((int_fast64_t) YEARSPERREPEAT * (int_fast64_t) AVGSECSPERYEAR)
-#endif /* !defined SECSPERREPEAT */
- 
-#ifndef SECSPERREPEAT_BITS
-#define SECSPERREPEAT_BITS	34	/* ceil(log2(SECSPERREPEAT)) */
-#endif /* !defined SECSPERREPEAT_BITS */
-
-/*
-** UNIX was a registered trademark of The Open Group in 2003.
-*/
-
-#endif /* !defined PRIVATE_H */
diff --git a/libcutils/properties.c b/libcutils/properties.c
index f732ec0..28d8b2f 100644
--- a/libcutils/properties.c
+++ b/libcutils/properties.c
@@ -52,19 +52,28 @@
     return len;
 }
 
-int property_list(void (*propfn)(const char *key, const char *value, void *cookie), 
-                  void *cookie)
+struct property_list_callback_data
+{
+    void (*propfn)(const char *key, const char *value, void *cookie);
+    void *cookie;
+};
+
+static void property_list_callback(const prop_info *pi, void *cookie)
 {
     char name[PROP_NAME_MAX];
     char value[PROP_VALUE_MAX];
-    const prop_info *pi;
-    unsigned n;
-    
-    for(n = 0; (pi = __system_property_find_nth(n)); n++) {
-        __system_property_read(pi, name, value);
-        propfn(name, value, cookie);
-    }
-    return 0;
+    struct property_list_callback_data *data = cookie;
+
+    __system_property_read(pi, name, value);
+    data->propfn(name, value, data->cookie);
+}
+
+int property_list(
+        void (*propfn)(const char *key, const char *value, void *cookie),
+        void *cookie)
+{
+    struct property_list_callback_data data = { propfn, cookie };
+    return __system_property_foreach(property_list_callback, &data);
 }
 
 #elif defined(HAVE_SYSTEM_PROPERTY_SERVER)
diff --git a/libcutils/tests/Android.mk b/libcutils/tests/Android.mk
new file mode 100644
index 0000000..6571161
--- /dev/null
+++ b/libcutils/tests/Android.mk
@@ -0,0 +1 @@
+include $(all-subdir-makefiles)
diff --git a/libcutils/tests/memset_mips/Android.mk b/libcutils/tests/memset_mips/Android.mk
new file mode 100644
index 0000000..c22fca9
--- /dev/null
+++ b/libcutils/tests/memset_mips/Android.mk
@@ -0,0 +1,23 @@
+# Copyright 2012 The Android Open Source Project
+
+ifeq ($(TARGET_ARCH),mips)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	test_memset.c \
+	android_memset_dumb.S \
+	android_memset_test.S \
+	memset_cmips.S \
+	memset_omips.S
+
+LOCAL_MODULE:= test_memset
+
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_STATIC_LIBRARIES := libcutils libc
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
+
+endif
diff --git a/libcutils/tests/memset_mips/android_memset_dumb.S b/libcutils/tests/memset_mips/android_memset_dumb.S
new file mode 100644
index 0000000..c8a1a37
--- /dev/null
+++ b/libcutils/tests/memset_mips/android_memset_dumb.S
@@ -0,0 +1,36 @@
+	.global	android_memset16_dumb
+	.type   android_memset16_dumb, @function
+android_memset16_dumb:
+        .ent	android_memset16_dumb
+
+	.set	noreorder
+	beqz	$a2,9f
+	 srl	$a2,1
+
+1:	sh	$a1,($a0)
+	subu	$a2,1
+	bnez	$a2,1b
+	 addu	$a0,2
+	.set reorder
+
+9:	j	$ra
+        .end	android_memset16_dumb
+	.size	android_memset16_dumb,.-android_memset16_dumb
+
+	.global android_memset32_dumb
+	.type	android_memset32_dumb, @function
+android_memset32_dumb:
+        .ent	android_memset32_dumb
+	.set	noreorder
+	beqz	$a2,9f
+	 srl	$a2,2
+
+1:	sw	$a1,($a0)
+	subu	$a2,1
+	bnez	$a2,1b
+	 addu	$a0,4
+	.set reorder
+
+9:	j	$ra
+        .end	android_memset32_dumb
+	.size	android_memset32_dumb,.-android_memset32_dumb
diff --git a/libcutils/tests/memset_mips/android_memset_test.S b/libcutils/tests/memset_mips/android_memset_test.S
new file mode 100644
index 0000000..e918843
--- /dev/null
+++ b/libcutils/tests/memset_mips/android_memset_test.S
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+#ifdef NDEBUG
+#define DBG #
+#else
+#define DBG
+#endif
+
+	.text
+	.align
+
+        /*
+         * Optimized memset16 for MIPS
+         *
+         * void android_memset16_test(uint16_t* dst, uint16_t value, size_t size);
+         *
+         */
+
+	.global	android_memset16_test
+	.type   android_memset16_test, @function
+android_memset16_test:
+        .ent	android_memset16_test
+	.set	noreorder
+
+	/* Check parameters */
+DBG	andi	$t0,$a0,1	/* $a0 must be halfword aligned */
+DBG	tne	$t0
+DBG	lui	$t1,0xffff	/* $a1 must be 16bits */
+DBG	and	$t1,$a1
+DBG	tne	$t1
+DBG	andi	$t2,$a2,1	/* $a2 must be even */
+DBG	tne	$t2
+
+#if (__mips==32) && (__mips_isa_rev>=2)
+	ins	$a2,$0,0,1
+#else
+	li	$t0,~1
+	and	$a2,$t0
+#endif
+
+	move	$t8,$ra
+	blez	$a2,9f		/* Anything to do? */
+	 andi	$t0,$a0,2	/* Check dst alignment */
+	/* Expand value to 32 bits and check destination alignment */
+#if (__mips==32) && (__mips_isa_rev>=2)
+	beqz	$t0,.Laligned32	/* dst is 32 bit aligned */
+	 ins	$a1,$a1,16,16
+#else
+	sll	$t2,$a1,16
+	beqz	$t0,.Laligned32	/* dst is 32 bit aligned */
+	 or	$a1,$t2
+#endif
+	sh	$a1,($a0)	/* do one halfword to get aligned */
+	subu	$a2,2
+	addu	$a0,2
+
+.Laligned32:
+	and	$t1,$a2,63	/* is there enough left to do a full 64 byte loop? */
+	beq	$a2,$t1,1f
+	 subu	$t2,$a2,$t1	/* $t2 is the number of bytes to do in loop64 */
+	addu	$t3,$a0,$t2	/* $t3 is the end marker for loop64 */
+	subu	$a2,$t2
+.Lloop64:
+	addu	$a0,64
+	sw	$a1,-64($a0)
+	sw	$a1,-60($a0)
+	sw	$a1,-56($a0)
+	sw	$a1,-52($a0)
+	sw	$a1,-48($a0)
+	sw	$a1,-44($a0)
+	sw	$a1,-40($a0)
+	sw	$a1,-36($a0)
+	sw	$a1,-32($a0)
+	sw	$a1,-28($a0)
+	sw	$a1,-24($a0)
+	sw	$a1,-20($a0)
+	sw	$a1,-16($a0)
+	sw	$a1,-12($a0)
+	sw	$a1,-8($a0)
+	bne	$a0,$t3,.Lloop64
+	sw	$a1,-4($a0)
+
+	/* Do the last 0..62 bytes */
+1:	li	$t0,64+12
+	andi	$t1,$a2,0x3c	/* $t1 how many bytes to store using sw */
+	bal	1f
+	 subu	$t0,$t1		/* 64+12-$t0 is offset to jump from 1f */
+1:	addu	$ra,$t0
+	j	$ra
+	 subu	$a2,$t1
+2:	sw	$a1,60($a0)
+	sw	$a1,56($a0)
+	sw	$a1,52($a0)
+	sw	$a1,48($a0)
+	sw	$a1,44($a0)
+	sw	$a1,40($a0)
+	sw	$a1,36($a0)
+	sw	$a1,32($a0)
+	sw	$a1,28($a0)
+	sw	$a1,24($a0)
+	sw	$a1,20($a0)
+	sw	$a1,16($a0)
+	sw	$a1,12($a0)
+	sw	$a1,8($a0)
+	sw	$a1,4($a0)
+	sw	$a1,0($a0)
+
+	beqz	$a2,9f
+	 addu	$a0,$t1
+	sh	$a1,($a0)
+
+9:	j	$t8
+	 nop
+        .end	android_memset16_test
+	.size	android_memset16_test,.-android_memset16_test
+
+        /*
+         * Optimized memset32 for MIPS
+         *
+         * void android_memset32_test(uint32_t* dst, uint32_t value, size_t size);
+         *
+         */
+	.global android_memset32_test
+	.type	android_memset32_test, @function
+android_memset32_test:
+        .ent	android_memset32_test
+	.set	noreorder
+
+	/* Check parameters */
+DBG	andi	$t0,$a0,3	/* $a0 must be word aligned */
+DBG	tne	$t0
+DBG	andi	$t2,$a2,3	/* $a2 must be a multiple of 4 bytes */
+DBG	tne	$t2
+
+	b	.Laligned32
+	 move	$t8,$ra
+        .end	android_memset32_test
+	.size	android_memset32_test,.-android_memset32_test
diff --git a/libcutils/tests/memset_mips/memset_cmips.S b/libcutils/tests/memset_mips/memset_cmips.S
new file mode 100644
index 0000000..f8f3a91
--- /dev/null
+++ b/libcutils/tests/memset_mips/memset_cmips.S
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2009
+ *      MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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 distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. 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 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
+ * SUCH DAMAGE.
+ */
+
+/************************************************************************
+ *
+ *  memset.S, version "64h" with 1 cache line horizon for "pref 30" and 14 nops
+ *  Version: "043009"
+ *
+ ************************************************************************/
+
+
+/************************************************************************
+ *  Include files
+ ************************************************************************/
+
+#include "machine/asm.h"
+
+/*
+ * This routine could be optimized for MIPS64. The current code only
+ * uses MIPS32 instructions.
+ */
+
+#if defined(__MIPSEB__)
+#  define SWHI	swl		/* high part is left in big-endian	*/
+#endif
+
+#if defined(__MIPSEL__)
+#  define SWHI	swr		/* high part is right in little-endian	*/
+#endif
+
+#if !(defined(XGPROF) || defined(XPROF))
+#undef SETUP_GP
+#define SETUP_GP
+#endif
+
+LEAF(memset_cmips,0)
+
+	.set	noreorder
+	.set	noat
+
+	addu	t0,a0,a2		# t0 is the "past the end" address
+	slti	AT,a2,4			# is a2 less than 4?
+	bne	AT,zero,.Llast4		# if yes, go to last4
+	move	v0,a0			# memset returns the dst pointer
+
+	beq	a1,zero,.Lset0
+	subu	v1,zero,a0
+
+	# smear byte into 32 bit word
+#if (__mips==32) && (__mips_isa_rev>=2)
+	ins     a1, a1, 8, 8        # Replicate fill byte into half-word.
+	ins     a1, a1, 16, 16      # Replicate fill byte into word.
+#else
+	and	a1,0xff
+	sll	AT,a1,8
+	or	a1,AT
+	sll	AT,a1,16
+	or	a1,AT
+#endif
+
+.Lset0:	andi	v1,v1,0x3		# word-unaligned address?
+	beq	v1,zero,.Laligned	# v1 is the unalignment count
+	subu	a2,a2,v1
+	SWHI	a1,0(a0)
+	addu	a0,a0,v1
+
+# Here we have the "word-aligned" a0 (until the "last4")
+.Laligned:
+	andi	t8,a2,0x3f	# any 64-byte chunks?
+				# t8 is the byte count past 64-byte chunks
+	beq	a2,t8,.Lchk8w	# when a2==t8, no 64-byte chunks
+				# There will be at most 1 32-byte chunk then
+	subu	a3,a2,t8	# subtract from a2 the reminder
+				# Here a3 counts bytes in 16w chunks
+	addu	a3,a0,a3	# Now a3 is the final dst after 64-byte chunks
+
+# Find out, if there are any 64-byte chunks after which will be still at least
+# 96 bytes left. The value "96" is calculated as needed buffer for
+# "pref 30,64(a0)" prefetch, which can be used as "pref 30,0(a0)" after
+# incrementing "a0" by 64.
+# For "a2" below 160 there will be no such "pref 30 safe" 64-byte chunk.
+#
+	sltiu	v1,a2,160
+	bgtz	v1,.Lloop16w_nopref30	# skip "pref 30,0(a0)"
+	subu	t7,a2,96	# subtract "pref 30 unsafe" region
+		# below we have at least 1 64-byte chunk which is "pref 30 safe"
+	andi	t6,t7,0x3f	# t6 is past "64-byte safe chunks" reminder
+	subu	t5,t7,t6	# subtract from t7 the reminder
+				# Here t5 counts bytes in 16w "safe" chunks
+	addu	t4,a0,t5	# Now t4 is the dst after 64-byte "safe" chunks
+
+# Don't use "pref 30,0(a0)" for a0 in a "middle" of a cache line
+#	pref	30,0(a0)
+# Here we are in the region, where it is safe to use "pref 30,64(a0)"
+.Lloop16w:
+	addiu	a0,a0,64
+	pref	30,-32(a0)	# continue setting up the dest, addr 64-32
+	sw	a1,-64(a0)
+	sw	a1,-60(a0)
+	sw	a1,-56(a0)
+	sw	a1,-52(a0)
+	sw	a1,-48(a0)
+	sw	a1,-44(a0)
+	sw	a1,-40(a0)
+	sw	a1,-36(a0)
+	nop
+	nop			# the extra nop instructions help to balance
+	nop			# cycles needed for "store" + "fill" + "evict"
+	nop			# For 64byte store there are needed 8 fill
+	nop			# and 8 evict cycles, i.e. at least 32 instr.
+	nop
+	nop
+	pref	30,0(a0)	# continue setting up the dest, addr 64-0
+	sw	a1,-32(a0)
+	sw	a1,-28(a0)
+	sw	a1,-24(a0)
+	sw	a1,-20(a0)
+	sw	a1,-16(a0)
+	sw	a1,-12(a0)
+	sw	a1,-8(a0)
+	sw	a1,-4(a0)
+	nop
+	nop
+	nop
+	nop			# NOTE: adding 14 nop-s instead of 12 nop-s
+	nop			# gives better results for "fast" memory
+	nop
+	bne	a0,t4,.Lloop16w
+	nop
+
+	beq	a0,a3,.Lchk8w	# maybe no more 64-byte chunks?
+	nop			# this "delayed slot" is useless ...
+
+.Lloop16w_nopref30:	# there could be up to 3 "64-byte nopref30" chunks
+	addiu	a0,a0,64
+	sw	a1,-64(a0)
+	sw	a1,-60(a0)
+	sw	a1,-56(a0)
+	sw	a1,-52(a0)
+	sw	a1,-48(a0)
+	sw	a1,-44(a0)
+	sw	a1,-40(a0)
+	sw	a1,-36(a0)
+	sw	a1,-32(a0)
+	sw	a1,-28(a0)
+	sw	a1,-24(a0)
+	sw	a1,-20(a0)
+	sw	a1,-16(a0)
+	sw	a1,-12(a0)
+	sw	a1,-8(a0)
+	bne	a0,a3,.Lloop16w_nopref30
+	sw	a1,-4(a0)
+
+.Lchk8w:		# t8 here is the byte count past 64-byte chunks
+
+	andi	t7,t8,0x1f	# is there a 32-byte chunk?
+				# the t7 is the reminder count past 32-bytes
+	beq	t8,t7,.Lchk1w	# when t8==t7, no 32-byte chunk
+	move	a2,t7
+
+	sw	a1,0(a0)
+	sw	a1,4(a0)
+	sw	a1,8(a0)
+	sw	a1,12(a0)
+	sw	a1,16(a0)
+	sw	a1,20(a0)
+	sw	a1,24(a0)
+	sw	a1,28(a0)
+	addiu	a0,a0,32
+
+.Lchk1w:
+	andi	t8,a2,0x3	# now t8 is the reminder past 1w chunks
+	beq	a2,t8,.Llast4
+	subu	a3,a2,t8	# a3 is the count of bytes in 1w chunks
+	addu	a3,a0,a3	# now a3 is the dst address past the 1w chunks
+
+# copying in words (4-byte chunks)
+.LwordCopy_loop:
+	addiu	a0,a0,4
+	bne	a0,a3,.LwordCopy_loop
+	sw	a1,-4(a0)
+
+.Llast4:beq	a0,t0,.Llast4e
+.Llast4l:addiu	a0,a0,1
+	bne	a0,t0,.Llast4l
+	sb	a1,-1(a0)
+
+.Llast4e:
+	j	ra
+	nop
+
+	.set	at
+	.set	reorder
+
+END(memset_cmips)
+
+
+/************************************************************************
+ *  Implementation : Static functions
+ ************************************************************************/
+
diff --git a/libcutils/tests/memset_mips/memset_omips.S b/libcutils/tests/memset_mips/memset_omips.S
new file mode 100644
index 0000000..4c47001
--- /dev/null
+++ b/libcutils/tests/memset_mips/memset_omips.S
@@ -0,0 +1,90 @@
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Hartvig Ekner <hartvige@mips.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* void *memset_omips(void *s, int c, size_t n).  */
+
+#include "machine/asm.h"
+
+#ifdef __mips64
+#error mips32 code being compiled for mips64!
+#endif
+
+#if defined(__MIPSEB__)
+#error big-endian is not supported in Broadcom MIPS Android platform
+# define SWHI	swl		/* high part is left in big-endian	*/
+#else
+# define SWHI	swr		/* high part is right in little-endian	*/
+#endif
+
+LEAF (memset_omips,0)
+	.set	noreorder
+
+	slti	t1, a2, 8		# Less than 8?
+	bne	t1, zero, .Llast8
+	move	v0, a0			# Setup exit value before too late
+
+	beq	a1, zero, .Lueven	# If zero pattern, no need to extend
+	andi	a1, 0xff		# Avoid problems with bogus arguments
+	sll	t0, a1, 8
+	or	a1, t0
+	sll	t0, a1, 16
+	or	a1, t0			# a1 is now pattern in full word
+
+.Lueven:
+	subu	t0, zero, a0		# Unaligned address?
+	andi	t0, 0x3
+	beq	t0, zero, .Lchkw
+	subu	a2, t0
+	SWHI	a1, 0(a0)		# Yes, handle first unaligned part
+	addu	a0, t0			# Now both a0 and a2 are updated
+
+.Lchkw:
+	andi	t0, a2, 0x7		# Enough left for one loop iteration?
+	beq	t0, a2, .Lchkl
+	subu	a3, a2, t0
+	addu	a3, a0			# a3 is last loop address +1
+	move	a2, t0			# a2 is now # of bytes left after loop
+.Lloopw:
+	addiu	a0, 8			# Handle 2 words pr. iteration
+	sw	a1, -8(a0)
+	bne	a0, a3, .Lloopw
+	sw	a1, -4(a0)
+
+.Lchkl:
+	andi	t0, a2, 0x4		# Check if there is at least a full
+	beq	t0, zero, .Llast8	#  word remaining after the loop
+	subu	a2, t0
+	sw	a1, 0(a0)		# Yes...
+	addiu	a0, 4
+
+.Llast8:
+	blez	a2, .Lexit		# Handle last 8 bytes (if cnt>0)
+	addu	a3, a2, a0		# a3 is last address +1
+.Llst8l:
+	addiu	a0, 1
+	bne	a0, a3, .Llst8l
+	sb	a1, -1(a0)
+.Lexit:
+	j	ra			# Bye, bye
+	nop
+
+	.set	reorder
+END (memset_omips)
+
+
diff --git a/libcutils/tests/memset_mips/test_memset.c b/libcutils/tests/memset_mips/test_memset.c
new file mode 100644
index 0000000..9705c65
--- /dev/null
+++ b/libcutils/tests/memset_mips/test_memset.c
@@ -0,0 +1,235 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <cutils/memory.h>
+#include <time.h>
+
+/*
+ * All systems must implement or emulate the rdhwr instruction to read
+ * the userlocal register. Systems that emulate also return teh count register
+ * when accessing register $2 so this should work on most systems
+ */
+#define USE_RDHWR
+
+#ifdef USE_RDHWR
+#define UNITS "cycles"
+#define SCALE 2			/* Most CPU's */
+static inline uint32_t
+get_count(void)
+{
+  uint32_t res;
+  asm volatile (".set push; .set mips32r2; rdhwr %[res],$2; .set pop" : [res] "=r" (res) : : "memory");
+  return res;
+}
+#else
+#define UNITS "ns"
+#define SCALE 1
+static inline uint32_t
+get_count(void)
+{
+  struct timespec now;
+  uint32_t res;
+  clock_gettime(CLOCK_REALTIME, &now);
+  res = (uint32_t)(now.tv_sec * 1000000000LL + now.tv_nsec);
+  // printf ("now=%d.%09d res=%d\n", (int)now.tv_sec, (int)now.tv_nsec, res);
+  return res;
+}
+#endif
+
+uint32_t overhead;
+void
+measure_overhead(void)
+{
+  int i;
+  uint32_t start, stop, delta;
+  for (i = 0; i < 32; i++) {
+    start = get_count();
+    stop = get_count();
+    delta = stop - start;
+    if (overhead == 0 || delta < overhead)
+      overhead = delta;
+  }
+  printf("overhead is %d"UNITS"\n", overhead);
+}
+
+uint32_t
+timeone(void (*fn)(), void *d, uint32_t val, uint32_t bytes)
+{
+  uint32_t start, stop, delta;
+  start = get_count();
+  (*fn)(d, val, bytes);
+  stop = get_count();
+  delta = stop - start - overhead;
+  // printf ("start=0x%08x stop=0x%08x delta=0x%08x\n", start, stop, delta);
+  return delta * SCALE;
+}
+
+/* define VERIFY to check that memset only touches the bytes it's supposed to */
+/*#define VERIFY*/
+
+/*
+ * Using a big arena means that memset will most likely miss in the cache
+ * NB Enabling verification effectively warms up the cache...
+ */
+#define ARENASIZE 0x1000000
+#ifdef VERIFY
+char arena[ARENASIZE+8];	/* Allow space for guard words */
+#else
+char arena[ARENASIZE];
+#endif
+
+void
+testone(char *tag, void (*fn)(), int trials, int minbytes, int maxbytes, int size, int threshold)
+{
+  int offset;
+  void *d;
+  void *p;
+  uint32_t v, notv = 0;
+  uint32_t n;
+  int i, units;
+  int totalunits = 0, totalbytes = 0, samples = 0;
+
+  /* Reset RNG to ensure each test uses same random values */
+  srand(0);			/* FIXME should be able to use some other seed than 0 */
+
+  for (i = 0; i < trials; i++) {
+    n = minbytes + (rand() % (maxbytes-minbytes));	/* How many bytes to do */
+    offset = ((rand() % (ARENASIZE-n)));		/* Where to start */
+
+#ifdef VERIFY
+    offset += 4;		/* Allow space for guard word at beginning */
+#endif
+    v = rand();
+
+    /* Adjust alignment and sizes based on transfer size */
+    switch (size) {
+    case 1:
+      v &= 0xff;
+      notv = ~v & 0xff;
+      break;
+    case 2:
+      v &= 0xffff;
+      notv = ~v & 0xffff;
+      offset &= ~1;
+      n &= ~1;
+      break;
+    case 4:
+      notv = ~v;
+      offset &= ~3;
+      n &= ~3;
+      break;
+    }
+
+    d = &arena[offset];
+
+#ifdef VERIFY
+    /* Initialise the area and guard words */
+    for (p = &arena[offset-4]; p < (void *)&arena[offset+n+4]; p = (void *)((uint32_t)p + size)) {
+      if (size == 1)
+	*(uint8_t *)p = notv;
+      else if (size == 2)
+	*(uint16_t *)p = notv;
+      else if (size == 4)
+	*(uint32_t *)p = notv;
+    }
+#endif
+    units = timeone(fn, d, v, n);
+#ifdef VERIFY
+    /* Check the area and guard words */
+    for (p = &arena[offset-4]; p < (void *)&arena[offset+n+4]; p = (void *)((uint32_t)p + size)) {
+      uint32_t got = 0;
+      if (size == 1)
+	got = *(uint8_t *)p;
+      else if (size == 2)
+	got = *(uint16_t *)p;
+      else if (size == 4)
+	got = *(uint32_t *)p;
+      if (p < (void *)&arena[offset]) {
+	if (got != notv)
+	  printf ("%s: verify failure: preguard:%p d=%p v=%08x got=%08x n=%d\n", tag, p, d, v, got, n);
+      }
+      else if (p < (void *)&arena[offset+n]) {
+	if (got != v)
+	  printf ("%s: verify failure: arena:%p d=%p v=%08x got=%08x n=%d\n", tag, p, d, v, n);
+      }
+      else {
+	if (got != notv)
+	  printf ("%s: verify failure: postguard:%p d=%p v=%08x got=%08x n=%d\n", tag, p, d, v, n);
+      }
+    }
+#endif
+
+    /* If the cycle count looks reasonable include it in the statistics */
+    if (units < threshold) {
+      totalbytes += n;
+      totalunits += units;
+      samples++;
+    }
+  }
+
+  printf("%s: samples=%d avglen=%d avg" UNITS "=%d bp"UNITS"=%g\n",
+	 tag, samples, totalbytes/samples, totalunits/samples, (double)totalbytes/(double)totalunits);
+}
+
+extern void android_memset32_dumb(uint32_t* dst, uint32_t value, size_t size);
+extern void android_memset16_dumb(uint32_t* dst, uint16_t value, size_t size);
+extern void android_memset32_test(uint32_t* dst, uint32_t value, size_t size);
+extern void android_memset16_test(uint32_t* dst, uint16_t value, size_t size);
+extern void memset_cmips(void* dst, int value, size_t size);
+extern void memset_omips(void* dst, int value, size_t size);
+
+int
+main(int argc, char **argv)
+{
+  int i;
+  struct {
+    char *type;
+    int trials;
+    int minbytes, maxbytes;
+  } *pp, params[] = {
+    {"small",  10000,   0,   64},
+    {"medium", 10000,  64,  512},
+    {"large",  10000, 512, 1280},
+    {"varied", 10000,   0, 1280},
+  };
+#define NPARAMS (sizeof(params)/sizeof(params[0]))
+  struct {
+    char *name;
+    void (*fn)();
+    int size;
+  } *fp, functions[] = {
+    {"dmemset16", (void (*)())android_memset16_dumb, 2},
+    {"tmemset16", (void (*)())android_memset16_test, 2},
+    {"lmemset16", (void (*)())android_memset16,      2},
+
+    {"dmemset32", (void (*)())android_memset32_dumb, 4},
+    {"tmemset32", (void (*)())android_memset32_test, 4},
+    {"lmemset32", (void (*)())android_memset32,      4},
+
+    {"cmemset",    (void (*)())memset_cmips,         1},
+    {"omemset",    (void (*)())memset_omips,         1},
+    {"lmemset",    (void (*)())memset,               1},
+  };
+#define NFUNCTIONS (sizeof(functions)/sizeof(functions[0]))
+  char tag[40];
+  int threshold;
+
+  measure_overhead();
+
+  /* Warm up the page cache */
+  memset(arena, 0xff, ARENASIZE); /* use 0xff now to avoid COW later */
+
+  for (fp = functions; fp < &functions[NFUNCTIONS]; fp++) {
+    (fp->fn)(arena, 0xffffffff, ARENASIZE);	/* one call to get the code into Icache */
+    for (pp = params; pp < &params[NPARAMS]; pp++) {
+      sprintf(tag, "%10s: %7s %4d-%4d", fp->name, pp->type, pp->minbytes, pp->maxbytes);
+
+      /* Set the cycle threshold */
+      threshold = pp->maxbytes * 4 * 10;	/* reasonable for cycles and ns */
+      testone(tag, fp->fn, pp->trials, pp->minbytes, pp->maxbytes, fp->size, threshold);
+    }
+    printf ("\n");
+  }
+
+  return 0;
+}
diff --git a/libcutils/trace.c b/libcutils/trace.c
new file mode 100644
index 0000000..9754a44
--- /dev/null
+++ b/libcutils/trace.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <cutils/atomic.h>
+#include <cutils/compiler.h>
+#include <cutils/properties.h>
+#include <cutils/trace.h>
+
+#define LOG_TAG "cutils-trace"
+#include <cutils/log.h>
+
+volatile int32_t        atrace_is_ready      = 0;
+int                     atrace_marker_fd     = -1;
+uint64_t                atrace_enabled_tags  = ATRACE_TAG_NOT_READY;
+static bool             atrace_is_debuggable = false;
+static volatile int32_t atrace_is_enabled    = 1;
+static pthread_once_t   atrace_once_control  = PTHREAD_ONCE_INIT;
+static pthread_mutex_t  atrace_tags_mutex    = PTHREAD_MUTEX_INITIALIZER;
+
+// Set whether this process is debuggable, which determines whether
+// application-level tracing is allowed when the ro.debuggable system property
+// is not set to '1'.
+void atrace_set_debuggable(bool debuggable)
+{
+    atrace_is_debuggable = debuggable;
+    atrace_update_tags();
+}
+
+// Set whether tracing is enabled in this process.  This is used to prevent
+// the Zygote process from tracing.
+void atrace_set_tracing_enabled(bool enabled)
+{
+    android_atomic_release_store(enabled ? 1 : 0, &atrace_is_enabled);
+    atrace_update_tags();
+}
+
+// Check whether the given command line matches one of the comma-separated
+// values listed in the app_cmdlines property.
+static bool atrace_is_cmdline_match(const char* cmdline)
+{
+    char value[PROPERTY_VALUE_MAX];
+    char* start = value;
+
+    property_get("debug.atrace.app_cmdlines", value, "");
+
+    while (start != NULL) {
+        char* end = strchr(start, ',');
+
+        if (end != NULL) {
+            *end = '\0';
+            end++;
+        }
+
+        if (strcmp(cmdline, start) == 0) {
+            return true;
+        }
+
+        start = end;
+    }
+
+    return false;
+}
+
+// Determine whether application-level tracing is enabled for this process.
+static bool atrace_is_app_tracing_enabled()
+{
+    bool sys_debuggable = false;
+    bool proc_debuggable = false;
+    char value[PROPERTY_VALUE_MAX];
+    bool result = false;
+
+    // Check whether the system is debuggable.
+    property_get("ro.debuggable", value, "0");
+    if (value[0] == '1') {
+        sys_debuggable = true;
+    }
+
+    if (sys_debuggable || atrace_is_debuggable) {
+        // Check whether tracing is enabled for this process.
+        FILE * file = fopen("/proc/self/cmdline", "r");
+        if (file) {
+            char cmdline[4096];
+            if (fgets(cmdline, sizeof(cmdline), file)) {
+                result = atrace_is_cmdline_match(cmdline);
+            } else {
+                ALOGE("Error reading cmdline: %s (%d)", strerror(errno), errno);
+            }
+            fclose(file);
+        } else {
+            ALOGE("Error opening /proc/self/cmdline: %s (%d)", strerror(errno),
+                    errno);
+        }
+    }
+
+    return result;
+}
+
+// Read the sysprop and return the value tags should be set to
+static uint64_t atrace_get_property()
+{
+    char value[PROPERTY_VALUE_MAX];
+    char *endptr;
+    uint64_t tags;
+
+    property_get("debug.atrace.tags.enableflags", value, "0");
+    errno = 0;
+    tags = strtoull(value, &endptr, 0);
+    if (value[0] == '\0' || *endptr != '\0') {
+        ALOGE("Error parsing trace property: Not a number: %s", value);
+        return 0;
+    } else if (errno == ERANGE || tags == ULLONG_MAX) {
+        ALOGE("Error parsing trace property: Number too large: %s", value);
+        return 0;
+    }
+
+    // Only set the "app" tag if this process was selected for app-level debug
+    // tracing.
+    if (atrace_is_app_tracing_enabled()) {
+        tags |= ATRACE_TAG_APP;
+    } else {
+        tags &= ~ATRACE_TAG_APP;
+    }
+
+    return (tags | ATRACE_TAG_ALWAYS) & ATRACE_TAG_VALID_MASK;
+}
+
+// Update tags if tracing is ready. Useful as a sysprop change callback.
+void atrace_update_tags()
+{
+    uint64_t tags;
+    if (CC_UNLIKELY(android_atomic_acquire_load(&atrace_is_ready))) {
+        if (android_atomic_acquire_load(&atrace_is_enabled)) {
+            tags = atrace_get_property();
+            pthread_mutex_lock(&atrace_tags_mutex);
+            atrace_enabled_tags = tags;
+            pthread_mutex_unlock(&atrace_tags_mutex);
+        } else {
+            // Tracing is disabled for this process, so we simply don't
+            // initialize the tags.
+            pthread_mutex_lock(&atrace_tags_mutex);
+            atrace_enabled_tags = ATRACE_TAG_NOT_READY;
+            pthread_mutex_unlock(&atrace_tags_mutex);
+        }
+    }
+}
+
+static void atrace_init_once()
+{
+    atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY);
+    if (atrace_marker_fd == -1) {
+        ALOGE("Error opening trace file: %s (%d)", strerror(errno), errno);
+        atrace_enabled_tags = 0;
+        goto done;
+    }
+
+    atrace_enabled_tags = atrace_get_property();
+
+done:
+    android_atomic_release_store(1, &atrace_is_ready);
+}
+
+void atrace_setup()
+{
+    pthread_once(&atrace_once_control, atrace_init_once);
+}
diff --git a/libcutils/tzfile.h b/libcutils/tzfile.h
deleted file mode 100644
index 8c70375..0000000
--- a/libcutils/tzfile.h
+++ /dev/null
@@ -1,180 +0,0 @@
-#ifndef TZFILE_H
-
-#define TZFILE_H
-
-/*
-** This file is in the public domain, so clarified as of
-** 1996-06-05 by Arthur David Olson.
-*/
-
-/*
-** This header is for use ONLY with the time conversion code.
-** There is no guarantee that it will remain unchanged,
-** or that it will remain at all.
-** Do NOT copy it to any system include directory.
-** Thank you!
-*/
-
-/*
-** ID
-*/
-
-#ifndef lint
-#ifndef NOID
-static char	tzfilehid[] = "@(#)tzfile.h	8.1";
-#endif /* !defined NOID */
-#endif /* !defined lint */
-
-/*
-** Information about time zone files.
-*/
-
-#ifndef TZDIR
-#define TZDIR "/usr/share/zoneinfo" /* "/android/usr/share/zoneinfo" */ /* Time zone object file directory */
-#endif /* !defined TZDIR */
-
-#ifndef TZDEFAULT
-#define TZDEFAULT	"localtime"
-#endif /* !defined TZDEFAULT */
-
-#ifndef TZDEFRULES
-#define TZDEFRULES	"posixrules"
-#endif /* !defined TZDEFRULES */
-
-/*
-** Each file begins with. . .
-*/
-
-#define	TZ_MAGIC	"TZif"
-
-struct tzhead {
-	char	tzh_magic[4];		/* TZ_MAGIC */
-	char	tzh_version[1];		/* '\0' or '2' as of 2005 */
-	char	tzh_reserved[15];	/* reserved--must be zero */
-	char	tzh_ttisgmtcnt[4];	/* coded number of trans. time flags */
-	char	tzh_ttisstdcnt[4];	/* coded number of trans. time flags */
-	char	tzh_leapcnt[4];		/* coded number of leap seconds */
-	char	tzh_timecnt[4];		/* coded number of transition times */
-	char	tzh_typecnt[4];		/* coded number of local time types */
-	char	tzh_charcnt[4];		/* coded number of abbr. chars */
-};
-
-/*
-** . . .followed by. . .
-**
-**	tzh_timecnt (char [4])s		coded transition times a la time(2)
-**	tzh_timecnt (unsigned char)s	types of local time starting at above
-**	tzh_typecnt repetitions of
-**		one (char [4])		coded UTC offset in seconds
-**		one (unsigned char)	used to set tm_isdst
-**		one (unsigned char)	that's an abbreviation list index
-**	tzh_charcnt (char)s		'\0'-terminated zone abbreviations
-**	tzh_leapcnt repetitions of
-**		one (char [4])		coded leap second transition times
-**		one (char [4])		total correction after above
-**	tzh_ttisstdcnt (char)s		indexed by type; if TRUE, transition
-**					time is standard time, if FALSE,
-**					transition time is wall clock time
-**					if absent, transition times are
-**					assumed to be wall clock time
-**	tzh_ttisgmtcnt (char)s		indexed by type; if TRUE, transition
-**					time is UTC, if FALSE,
-**					transition time is local time
-**					if absent, transition times are
-**					assumed to be local time
-*/
-
-/*
-** If tzh_version is '2' or greater, the above is followed by a second instance
-** of tzhead and a second instance of the data in which each coded transition
-** time uses 8 rather than 4 chars,
-** then a POSIX-TZ-environment-variable-style string for use in handling
-** instants after the last transition time stored in the file
-** (with nothing between the newlines if there is no POSIX representation for
-** such instants).
-*/
-
-/*
-** In the current implementation, "tzset()" refuses to deal with files that
-** exceed any of the limits below.
-*/
-
-#ifndef TZ_MAX_TIMES
-#define TZ_MAX_TIMES	1200
-#endif /* !defined TZ_MAX_TIMES */
-
-#ifndef TZ_MAX_TYPES
-#ifndef NOSOLAR
-#define TZ_MAX_TYPES	256 /* Limited by what (unsigned char)'s can hold */
-#endif /* !defined NOSOLAR */
-#ifdef NOSOLAR
-/*
-** Must be at least 14 for Europe/Riga as of Jan 12 1995,
-** as noted by Earl Chew.
-*/
-#define TZ_MAX_TYPES	20	/* Maximum number of local time types */
-#endif /* !defined NOSOLAR */
-#endif /* !defined TZ_MAX_TYPES */
-
-#ifndef TZ_MAX_CHARS
-#define TZ_MAX_CHARS	50	/* Maximum number of abbreviation characters */
-				/* (limited by what unsigned chars can hold) */
-#endif /* !defined TZ_MAX_CHARS */
-
-#ifndef TZ_MAX_LEAPS
-#define TZ_MAX_LEAPS	50	/* Maximum number of leap second corrections */
-#endif /* !defined TZ_MAX_LEAPS */
-
-#define SECSPERMIN	60
-#define MINSPERHOUR	60
-#define HOURSPERDAY	24
-#define DAYSPERWEEK	7
-#define DAYSPERNYEAR	365
-#define DAYSPERLYEAR	366
-#define SECSPERHOUR	(SECSPERMIN * MINSPERHOUR)
-#define SECSPERDAY	((long) SECSPERHOUR * HOURSPERDAY)
-#define MONSPERYEAR	12
-
-#define TM_SUNDAY	0
-#define TM_MONDAY	1
-#define TM_TUESDAY	2
-#define TM_WEDNESDAY	3
-#define TM_THURSDAY	4
-#define TM_FRIDAY	5
-#define TM_SATURDAY	6
-
-#define TM_JANUARY	0
-#define TM_FEBRUARY	1
-#define TM_MARCH	2
-#define TM_APRIL	3
-#define TM_MAY		4
-#define TM_JUNE		5
-#define TM_JULY		6
-#define TM_AUGUST	7
-#define TM_SEPTEMBER	8
-#define TM_OCTOBER	9
-#define TM_NOVEMBER	10
-#define TM_DECEMBER	11
-
-#define TM_YEAR_BASE	1900
-
-#define EPOCH_YEAR	1970
-#define EPOCH_WDAY	TM_THURSDAY
-
-#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
-
-/*
-** Since everything in isleap is modulo 400 (or a factor of 400), we know that
-**	isleap(y) == isleap(y % 400)
-** and so
-**	isleap(a + b) == isleap((a + b) % 400)
-** or
-**	isleap(a + b) == isleap(a % 400 + b % 400)
-** This is true even if % means modulo rather than Fortran remainder
-** (which is allowed by C89 but not C99).
-** We use this to avoid addition overflow problems.
-*/
-
-#define isleap_sum(a, b)	isleap((a) % 400 + (b) % 400)
-
-#endif /* !defined TZFILE_H */
diff --git a/libcutils/tzstrftime.c b/libcutils/tzstrftime.c
deleted file mode 100644
index e4f54df..0000000
--- a/libcutils/tzstrftime.c
+++ /dev/null
@@ -1,842 +0,0 @@
-#ifndef lint
-#ifndef NOID
-static char	elsieid[] = "@(#)strftime.c	8.1";
-/*
-** Based on the UCB version with the ID appearing below.
-** This is ANSIish only when "multibyte character == plain character".
-*/
-#endif /* !defined NOID */
-#endif /* !defined lint */
-
-#include <stdio.h>
-#include <time.h>
-#include <tzfile.h>
-#include <limits.h>
-#include <cutils/tztime.h>
-
-/*
-** Copyright (c) 1989 The Regents of the University of California.
-** All rights reserved.
-**
-** Redistribution and use in source and binary forms are permitted
-** provided that the above copyright notice and this paragraph are
-** duplicated in all such forms and that any documentation,
-** advertising materials, and other materials related to such
-** distribution and use acknowledge that the software was developed
-** by the University of California, Berkeley. The name of the
-** University may not be used to endorse or promote products derived
-** from this software without specific prior written permission.
-** THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-** IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
-*/
-
-#ifndef LIBC_SCCS
-#ifndef lint
-static const char	sccsid[] = "@(#)strftime.c	5.4 (Berkeley) 3/14/89";
-#endif /* !defined lint */
-#endif /* !defined LIBC_SCCS */
-
-#include <ctype.h>
-
-#define P(x) x
-
-static char *	_add P((const char *, char *, const char *, int));
-static char *	_conv P((int, const char *, char *, const char *));
-static char *	_fmt P((const char *, const struct tm *, char *, const char *,
-			int *, const struct strftime_locale *Locale));
-static char *	_yconv P((int, int, int, int, char *, const char *, int));
-static char *	getformat P((int, char *, char *, char *, char *));
-
-extern char *	tzname[];
-
-
-
-
-
-/* from private.h */
-
-#ifndef TYPE_BIT
-#define TYPE_BIT(type)  (sizeof (type) * CHAR_BIT)
-#endif /* !defined TYPE_BIT */
-
-#ifndef TYPE_SIGNED
-#define TYPE_SIGNED(type) (((type) -1) < 0)
-#endif /* !defined TYPE_SIGNED */
-
-#ifndef INT_STRLEN_MAXIMUM
-/*
- * ** 302 / 1000 is log10(2.0) rounded up.
- * ** Subtract one for the sign bit if the type is signed;
- * ** add one for integer division truncation;
- * ** add one more for a minus sign if the type is signed.
- * */
-#define INT_STRLEN_MAXIMUM(type) \
-    ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \
-    1 + TYPE_SIGNED(type))
-#endif /* !defined INT_STRLEN_MAXIMUM */
-
-/* end of part from private.h */
-
-
-
-
-#ifndef YEAR_2000_NAME
-#define YEAR_2000_NAME	"CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS"
-#endif /* !defined YEAR_2000_NAME */
-
-#define IN_NONE	0
-#define IN_SOME	1
-#define IN_THIS	2
-#define IN_ALL	3
-
-#define FORCE_LOWER_CASE 0x100
-
-size_t
-strftime_tz(s, maxsize, format, t, Locale)
-char * const		s;
-const size_t		maxsize;
-const char * const	format;
-const struct tm * const	t;
-const struct strftime_locale *Locale;
-{
-	char *	p;
-	int	warn;
-
-	warn = IN_NONE;
-	p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn, Locale);
-#if 0
-	if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
-		(void) fprintf(stderr, "\n");
-		if (format == NULL)
-			(void) fprintf(stderr, "NULL strftime format ");
-		else	(void) fprintf(stderr, "strftime format \"%s\" ",
-				format);
-		(void) fprintf(stderr, "yields only two digits of years in ");
-		if (warn == IN_SOME)
-			(void) fprintf(stderr, "some locales");
-		else if (warn == IN_THIS)
-			(void) fprintf(stderr, "the current locale");
-		else	(void) fprintf(stderr, "all locales");
-		(void) fprintf(stderr, "\n");
-	}
-#endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */
-	if (p == s + maxsize)
-		return 0;
-	*p = '\0';
-	return p - s;
-}
-
-static char *getformat(int modifier, char *normal, char *underscore,
-                       char *dash, char *zero) {
-    switch (modifier) {
-    case '_':
-        return underscore;
-
-    case '-':
-        return dash;
-
-    case '0':
-        return zero;
-    }
-
-    return normal;
-}
-
-static char *
-_fmt(format, t, pt, ptlim, warnp, Locale)
-const char *		format;
-const struct tm * const	t;
-char *			pt;
-const char * const	ptlim;
-int *			warnp;
-const struct strftime_locale *Locale;
-{
-	for ( ; *format; ++format) {
-		if (*format == '%') {
-            int modifier = 0;
-label:
-			switch (*++format) {
-			case '\0':
-				--format;
-				break;
-			case 'A':
-				pt = _add((t->tm_wday < 0 ||
-					t->tm_wday >= DAYSPERWEEK) ?
-					"?" : Locale->weekday[t->tm_wday],
-					pt, ptlim, modifier);
-				continue;
-			case 'a':
-				pt = _add((t->tm_wday < 0 ||
-					t->tm_wday >= DAYSPERWEEK) ?
-					"?" : Locale->wday[t->tm_wday],
-					pt, ptlim, modifier);
-				continue;
-			case 'B':
-				if (modifier == '-') {
-					pt = _add((t->tm_mon < 0 ||
-						t->tm_mon >= MONSPERYEAR) ?
-						"?" : Locale->standalone_month[t->tm_mon],
-						pt, ptlim, modifier);
-				} else {
-					pt = _add((t->tm_mon < 0 ||
-						t->tm_mon >= MONSPERYEAR) ?
-						"?" : Locale->month[t->tm_mon],
-						pt, ptlim, modifier);
-				}
-				continue;
-			case 'b':
-			case 'h':
-				pt = _add((t->tm_mon < 0 ||
-					t->tm_mon >= MONSPERYEAR) ?
-					"?" : Locale->mon[t->tm_mon],
-					pt, ptlim, modifier);
-				continue;
-			case 'C':
-				/*
-				** %C used to do a...
-				**	_fmt("%a %b %e %X %Y", t);
-				** ...whereas now POSIX 1003.2 calls for
-				** something completely different.
-				** (ado, 1993-05-24)
-				*/
-				pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 0,
-					pt, ptlim, modifier);
-				continue;
-			case 'c':
-				{
-				int warn2 = IN_SOME;
-
-				pt = _fmt(Locale->c_fmt, t, pt, ptlim, warnp, Locale);
-				if (warn2 == IN_ALL)
-					warn2 = IN_THIS;
-				if (warn2 > *warnp)
-					*warnp = warn2;
-				}
-				continue;
-			case 'D':
-                                pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp, Locale);
-				continue;
-			case 'd':
-                                pt = _conv(t->tm_mday,
-                                           getformat(modifier, "%02d",
-                                                     "%2d", "%d", "%02d"),
-                                           pt, ptlim);
-				continue;
-			case 'E':
-			case 'O':
-				/*
-				** C99 locale modifiers.
-				** The sequences
-				**	%Ec %EC %Ex %EX %Ey %EY
-				**	%Od %oe %OH %OI %Om %OM
-				**	%OS %Ou %OU %OV %Ow %OW %Oy
-				** are supposed to provide alternate
-				** representations.
-				*/
-				goto label;
-            case '_':
-            case '-':
-            case '0':
-            case '^':
-            case '#':
-                modifier = *format;
-                goto label;
-			case 'e':
-				pt = _conv(t->tm_mday,
-                                           getformat(modifier, "%2d",
-                                                     "%2d", "%d", "%02d"),
-                                           pt, ptlim);
-				continue;
-			case 'F':
-				pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp, Locale);
-				continue;
-			case 'H':
-				pt = _conv(t->tm_hour,
-                                           getformat(modifier, "%02d",
-                                                     "%2d", "%d", "%02d"),
-                                           pt, ptlim);
-				continue;
-			case 'I':
-				pt = _conv((t->tm_hour % 12) ?
-					(t->tm_hour % 12) : 12,
-					getformat(modifier, "%02d",
-                                                  "%2d", "%d", "%02d"),
-                                        pt, ptlim);
-				continue;
-			case 'j':
-				pt = _conv(t->tm_yday + 1,
-                           getformat(modifier, "%03d", "%3d", "%d", "%03d"),
-                           pt, ptlim);
-				continue;
-			case 'k':
-				/*
-				** This used to be...
-				**	_conv(t->tm_hour % 12 ?
-				**		t->tm_hour % 12 : 12, 2, ' ');
-				** ...and has been changed to the below to
-				** match SunOS 4.1.1 and Arnold Robbins'
-				** strftime version 3.0. That is, "%k" and
-				** "%l" have been swapped.
-				** (ado, 1993-05-24)
-				*/
-				pt = _conv(t->tm_hour,
-                                           getformat(modifier, "%2d",
-                                                     "%2d", "%d", "%02d"),
-                                           pt, ptlim);
-				continue;
-#ifdef KITCHEN_SINK
-			case 'K':
-				/*
-				** After all this time, still unclaimed!
-				*/
-				pt = _add("kitchen sink", pt, ptlim, modifier);
-				continue;
-#endif /* defined KITCHEN_SINK */
-			case 'l':
-				/*
-				** This used to be...
-				**	_conv(t->tm_hour, 2, ' ');
-				** ...and has been changed to the below to
-				** match SunOS 4.1.1 and Arnold Robbin's
-				** strftime version 3.0. That is, "%k" and
-				** "%l" have been swapped.
-				** (ado, 1993-05-24)
-				*/
-				pt = _conv((t->tm_hour % 12) ?
-					(t->tm_hour % 12) : 12,
-					getformat(modifier, "%2d",
-                                                  "%2d", "%d", "%02d"),
-                                        pt, ptlim);
-				continue;
-			case 'M':
-				pt = _conv(t->tm_min,
-                                           getformat(modifier, "%02d",
-                                                     "%2d", "%d", "%02d"),
-                                           pt, ptlim);
-				continue;
-			case 'm':
-				pt = _conv(t->tm_mon + 1,
-                                           getformat(modifier, "%02d",
-                                                     "%2d", "%d", "%02d"),
-                                           pt, ptlim);
-				continue;
-			case 'n':
-				pt = _add("\n", pt, ptlim, modifier);
-				continue;
-			case 'p':
-				pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
-					Locale->pm :
-					Locale->am,
-					pt, ptlim, modifier);
-				continue;
-			case 'P':
-				pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
-					Locale->pm :
-					Locale->am,
-					pt, ptlim, FORCE_LOWER_CASE);
-				continue;
-			case 'R':
-				pt = _fmt("%H:%M", t, pt, ptlim, warnp, Locale);
-				continue;
-			case 'r':
-				pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp, Locale);
-				continue;
-			case 'S':
-				pt = _conv(t->tm_sec,
-                                           getformat(modifier, "%02d",
-                                                     "%2d", "%d", "%02d"),
-                                           pt, ptlim);
-				continue;
-			case 's':
-				{
-					struct tm	tm;
-					char		buf[INT_STRLEN_MAXIMUM(
-								time_t) + 1];
-					time_t		mkt;
-
-					tm = *t;
-					mkt = mktime(&tm);
-					if (TYPE_SIGNED(time_t))
-						(void) sprintf(buf, "%ld",
-							(long) mkt);
-					else	(void) sprintf(buf, "%lu",
-							(unsigned long) mkt);
-					pt = _add(buf, pt, ptlim, modifier);
-				}
-				continue;
-			case 'T':
-				pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp, Locale);
-				continue;
-			case 't':
-				pt = _add("\t", pt, ptlim, modifier);
-				continue;
-			case 'U':
-				pt = _conv((t->tm_yday + DAYSPERWEEK -
-					t->tm_wday) / DAYSPERWEEK,
-					getformat(modifier, "%02d",
-                                                  "%2d", "%d", "%02d"),
-                                        pt, ptlim);
-				continue;
-			case 'u':
-				/*
-				** From Arnold Robbins' strftime version 3.0:
-				** "ISO 8601: Weekday as a decimal number
-				** [1 (Monday) - 7]"
-				** (ado, 1993-05-24)
-				*/
-				pt = _conv((t->tm_wday == 0) ?
-					DAYSPERWEEK : t->tm_wday, "%d", pt, ptlim);
-				continue;
-			case 'V':	/* ISO 8601 week number */
-			case 'G':	/* ISO 8601 year (four digits) */
-			case 'g':	/* ISO 8601 year (two digits) */
-/*
-** From Arnold Robbins' strftime version 3.0: "the week number of the
-** year (the first Monday as the first day of week 1) as a decimal number
-** (01-53)."
-** (ado, 1993-05-24)
-**
-** From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:
-** "Week 01 of a year is per definition the first week which has the
-** Thursday in this year, which is equivalent to the week which contains
-** the fourth day of January. In other words, the first week of a new year
-** is the week which has the majority of its days in the new year. Week 01
-** might also contain days from the previous year and the week before week
-** 01 of a year is the last week (52 or 53) of the previous year even if
-** it contains days from the new year. A week starts with Monday (day 1)
-** and ends with Sunday (day 7). For example, the first week of the year
-** 1997 lasts from 1996-12-30 to 1997-01-05..."
-** (ado, 1996-01-02)
-*/
-				{
-					int	year;
-					int	base;
-					int	yday;
-					int	wday;
-					int	w;
-
-					year = t->tm_year;
-					base = TM_YEAR_BASE;
-					yday = t->tm_yday;
-					wday = t->tm_wday;
-					for ( ; ; ) {
-						int	len;
-						int	bot;
-						int	top;
-
-						len = isleap_sum(year, base) ?
-							DAYSPERLYEAR :
-							DAYSPERNYEAR;
-						/*
-						** What yday (-3 ... 3) does
-						** the ISO year begin on?
-						*/
-						bot = ((yday + 11 - wday) %
-							DAYSPERWEEK) - 3;
-						/*
-						** What yday does the NEXT
-						** ISO year begin on?
-						*/
-						top = bot -
-							(len % DAYSPERWEEK);
-						if (top < -3)
-							top += DAYSPERWEEK;
-						top += len;
-						if (yday >= top) {
-							++base;
-							w = 1;
-							break;
-						}
-						if (yday >= bot) {
-							w = 1 + ((yday - bot) /
-								DAYSPERWEEK);
-							break;
-						}
-						--base;
-						yday += isleap_sum(year, base) ?
-							DAYSPERLYEAR :
-							DAYSPERNYEAR;
-					}
-#ifdef XPG4_1994_04_09
-					if ((w == 52 &&
-						t->tm_mon == TM_JANUARY) ||
-						(w == 1 &&
-						t->tm_mon == TM_DECEMBER))
-							w = 53;
-#endif /* defined XPG4_1994_04_09 */
-					if (*format == 'V')
-						pt = _conv(w,
-                                                           getformat(modifier,
-                                                                     "%02d",
-                                                                     "%2d",
-                                                                     "%d",
-                                                                     "%02d"),
-							   pt, ptlim);
-					else if (*format == 'g') {
-						*warnp = IN_ALL;
-						pt = _yconv(year, base, 0, 1,
-							pt, ptlim, modifier);
-					} else	pt = _yconv(year, base, 1, 1,
-							pt, ptlim, modifier);
-				}
-				continue;
-			case 'v':
-				/*
-				** From Arnold Robbins' strftime version 3.0:
-				** "date as dd-bbb-YYYY"
-				** (ado, 1993-05-24)
-				*/
-				pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp, Locale);
-				continue;
-			case 'W':
-				pt = _conv((t->tm_yday + DAYSPERWEEK -
-					(t->tm_wday ?
-					(t->tm_wday - 1) :
-					(DAYSPERWEEK - 1))) / DAYSPERWEEK,
-					getformat(modifier, "%02d",
-                                                  "%2d", "%d", "%02d"),
-                                        pt, ptlim);
-				continue;
-			case 'w':
-				pt = _conv(t->tm_wday, "%d", pt, ptlim);
-				continue;
-			case 'X':
-				pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp, Locale);
-				continue;
-			case 'x':
-				{
-				int	warn2 = IN_SOME;
-
-				pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2, Locale);
-				if (warn2 == IN_ALL)
-					warn2 = IN_THIS;
-				if (warn2 > *warnp)
-					*warnp = warn2;
-				}
-				continue;
-			case 'y':
-				*warnp = IN_ALL;
-				pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1,
-					pt, ptlim, modifier);
-				continue;
-			case 'Y':
-				pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 1,
-					pt, ptlim, modifier);
-				continue;
-			case 'Z':
-#ifdef TM_ZONE
-				if (t->TM_ZONE != NULL)
-					pt = _add(t->TM_ZONE, pt, ptlim,
-                                                  modifier);
-				else
-#endif /* defined TM_ZONE */
-				if (t->tm_isdst >= 0)
-					pt = _add(tzname[t->tm_isdst != 0],
-						pt, ptlim, modifier);
-				/*
-				** C99 says that %Z must be replaced by the
-				** empty string if the time zone is not
-				** determinable.
-				*/
-				continue;
-			case 'z':
-				{
-				int		diff;
-				char const *	sign;
-
-				if (t->tm_isdst < 0)
-					continue;
-#ifdef TM_GMTOFF
-				diff = t->TM_GMTOFF;
-#else /* !defined TM_GMTOFF */
-				/*
-				** C99 says that the UTC offset must
-				** be computed by looking only at
-				** tm_isdst. This requirement is
-				** incorrect, since it means the code
-				** must rely on magic (in this case
-				** altzone and timezone), and the
-				** magic might not have the correct
-				** offset. Doing things correctly is
-				** tricky and requires disobeying C99;
-				** see GNU C strftime for details.
-				** For now, punt and conform to the
-				** standard, even though it's incorrect.
-				**
-				** C99 says that %z must be replaced by the
-				** empty string if the time zone is not
-				** determinable, so output nothing if the
-				** appropriate variables are not available.
-				*/
-				if (t->tm_isdst == 0)
-#ifdef USG_COMPAT
-					diff = -timezone;
-#else /* !defined USG_COMPAT */
-					continue;
-#endif /* !defined USG_COMPAT */
-				else
-#ifdef ALTZONE
-					diff = -altzone;
-#else /* !defined ALTZONE */
-					continue;
-#endif /* !defined ALTZONE */
-#endif /* !defined TM_GMTOFF */
-				if (diff < 0) {
-					sign = "-";
-					diff = -diff;
-				} else	sign = "+";
-				pt = _add(sign, pt, ptlim, modifier);
-				diff /= SECSPERMIN;
-				diff = (diff / MINSPERHOUR) * 100 +
-					(diff % MINSPERHOUR);
-				pt = _conv(diff,
-                                           getformat(modifier, "%04d",
-                                                     "%4d", "%d", "%04d"),
-                                           pt, ptlim);
-				}
-				continue;
-			case '+':
-				pt = _fmt(Locale->date_fmt, t, pt, ptlim,
-					warnp, Locale);
-				continue;
-			case '%':
-			/*
-			** X311J/88-090 (4.12.3.5): if conversion char is
-			** undefined, behavior is undefined. Print out the
-			** character itself as printf(3) also does.
-			*/
-			default:
-				break;
-			}
-		}
-		if (pt == ptlim)
-			break;
-		*pt++ = *format;
-	}
-	return pt;
-}
-
-static char *
-_conv(n, format, pt, ptlim)
-const int		n;
-const char * const	format;
-char * const		pt;
-const char * const	ptlim;
-{
-	char	buf[INT_STRLEN_MAXIMUM(int) + 1];
-
-	(void) sprintf(buf, format, n);
-	return _add(buf, pt, ptlim, 0);
-}
-
-static char *
-_add(str, pt, ptlim, modifier)
-const char *		str;
-char *			pt;
-const char * const	ptlim;
-int                     modifier;
-{
-        int c;
-
-        switch (modifier) {
-        case FORCE_LOWER_CASE:
-                while (pt < ptlim && (*pt = tolower(*str++)) != '\0') {
-                        ++pt;
-                }
-                break;
-
-        case '^':
-                while (pt < ptlim && (*pt = toupper(*str++)) != '\0') {
-                        ++pt;
-                }
-                break;
-
-        case '#':
-                while (pt < ptlim && (c = *str++) != '\0') {
-                        if (isupper(c)) {
-                                c = tolower(c);
-                        } else if (islower(c)) {
-                                c = toupper(c);
-                        }
-                        *pt = c;
-                        ++pt;
-                }
-
-                break;
-
-        default:
-                while (pt < ptlim && (*pt = *str++) != '\0') {
-                        ++pt;
-                }
-        }
-
-	return pt;
-}
-
-/*
-** POSIX and the C Standard are unclear or inconsistent about
-** what %C and %y do if the year is negative or exceeds 9999.
-** Use the convention that %C concatenated with %y yields the
-** same output as %Y, and that %Y contains at least 4 bytes,
-** with more only if necessary.
-*/
-
-static char *
-_yconv(a, b, convert_top, convert_yy, pt, ptlim, modifier)
-const int		a;
-const int		b;
-const int		convert_top;
-const int		convert_yy;
-char *			pt;
-const char * const	ptlim;
-int                     modifier;
-{
-	register int	lead;
-	register int	trail;
-
-#define DIVISOR	100
-	trail = a % DIVISOR + b % DIVISOR;
-	lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR;
-	trail %= DIVISOR;
-	if (trail < 0 && lead > 0) {
-		trail += DIVISOR;
-		--lead;
-	} else if (lead < 0 && trail > 0) {
-		trail -= DIVISOR;
-		++lead;
-	}
-	if (convert_top) {
-		if (lead == 0 && trail < 0)
-			pt = _add("-0", pt, ptlim, modifier);
-		else	pt = _conv(lead, getformat(modifier, "%02d",
-                                                   "%2d", "%d", "%02d"),
-                                   pt, ptlim);
-	}
-	if (convert_yy)
-		pt = _conv(((trail < 0) ? -trail : trail),
-                           getformat(modifier, "%02d", "%2d", "%d", "%02d"),
-                           pt, ptlim);
-	return pt;
-}
-
-#ifdef LOCALE_HOME
-static struct lc_time_T *
-_loc P((void))
-{
-	static const char	locale_home[] = LOCALE_HOME;
-	static const char	lc_time[] = "LC_TIME";
-	static char *		locale_buf;
-
-	int			fd;
-	int			oldsun;	/* "...ain't got nothin' to do..." */
-	char *			lbuf;
-	char *			name;
-	char *			p;
-	const char **		ap;
-	const char *		plim;
-	char			filename[FILENAME_MAX];
-	struct stat		st;
-	size_t			namesize;
-	size_t			bufsize;
-
-	/*
-	** Use localebuf.mon[0] to signal whether locale is already set up.
-	*/
-	if (localebuf.mon[0])
-		return &localebuf;
-	name = setlocale(LC_TIME, (char *) NULL);
-	if (name == NULL || *name == '\0')
-		goto no_locale;
-	/*
-	** If the locale name is the same as our cache, use the cache.
-	*/
-	lbuf = locale_buf;
-	if (lbuf != NULL && strcmp(name, lbuf) == 0) {
-		p = lbuf;
-		for (ap = (const char **) &localebuf;
-			ap < (const char **) (&localebuf + 1);
-				++ap)
-					*ap = p += strlen(p) + 1;
-		return &localebuf;
-	}
-	/*
-	** Slurp the locale file into the cache.
-	*/
-	namesize = strlen(name) + 1;
-	if (sizeof filename <
-		((sizeof locale_home) + namesize + (sizeof lc_time)))
-			goto no_locale;
-	oldsun = 0;
-	(void) sprintf(filename, "%s/%s/%s", locale_home, name, lc_time);
-	fd = open(filename, O_RDONLY);
-	if (fd < 0) {
-		/*
-		** Old Sun systems have a different naming and data convention.
-		*/
-		oldsun = 1;
-		(void) sprintf(filename, "%s/%s/%s", locale_home,
-			lc_time, name);
-		fd = open(filename, O_RDONLY);
-		if (fd < 0)
-			goto no_locale;
-	}
-	if (fstat(fd, &st) != 0)
-		goto bad_locale;
-	if (st.st_size <= 0)
-		goto bad_locale;
-	bufsize = namesize + st.st_size;
-	locale_buf = NULL;
-	lbuf = (lbuf == NULL) ? malloc(bufsize) : realloc(lbuf, bufsize);
-	if (lbuf == NULL)
-		goto bad_locale;
-	(void) strcpy(lbuf, name);
-	p = lbuf + namesize;
-	plim = p + st.st_size;
-	if (read(fd, p, (size_t) st.st_size) != st.st_size)
-		goto bad_lbuf;
-	if (close(fd) != 0)
-		goto bad_lbuf;
-	/*
-	** Parse the locale file into localebuf.
-	*/
-	if (plim[-1] != '\n')
-		goto bad_lbuf;
-	for (ap = (const char **) &localebuf;
-		ap < (const char **) (&localebuf + 1);
-			++ap) {
-				if (p == plim)
-					goto bad_lbuf;
-				*ap = p;
-				while (*p != '\n')
-					++p;
-				*p++ = '\0';
-	}
-	if (oldsun) {
-		/*
-		** SunOS 4 used an obsolescent format; see localdtconv(3).
-		** c_fmt had the ``short format for dates and times together''
-		** (SunOS 4 date, "%a %b %e %T %Z %Y" in the C locale);
-		** date_fmt had the ``long format for dates''
-		** (SunOS 4 strftime %C, "%A, %B %e, %Y" in the C locale).
-		** Discard the latter in favor of the former.
-		*/
-		localebuf.date_fmt = localebuf.c_fmt;
-	}
-	/*
-	** Record the successful parse in the cache.
-	*/
-	locale_buf = lbuf;
-
-	return &localebuf;
-
-bad_lbuf:
-	free(lbuf);
-bad_locale:
-	(void) close(fd);
-no_locale:
-	localebuf = C_time_locale;
-	locale_buf = NULL;
-	return &localebuf;
-}
-#endif /* defined LOCALE_HOME */
diff --git a/libcutils/tztime.c b/libcutils/tztime.c
deleted file mode 100644
index d6448a1..0000000
--- a/libcutils/tztime.c
+++ /dev/null
@@ -1,1950 +0,0 @@
-/*
-** This file is in the public domain, so clarified as of
-** 1996-06-05 by Arthur David Olson.
-*/
-
-#include <stdio.h>
-
-#ifndef lint
-#ifndef NOID
-static char	elsieid[] = "@(#)localtime.c	8.3";
-#endif /* !defined NOID */
-#endif /* !defined lint */
-
-/*
-** Leap second handling from Bradley White.
-** POSIX-style TZ environment variable handling from Guy Harris.
-*/
-
-/*LINTLIBRARY*/
-
-#include "private.h"
-#include "tzfile.h"
-#include "fcntl.h"
-#include "float.h"	/* for FLT_MAX and DBL_MAX */
-
-#ifndef TZ_ABBR_MAX_LEN
-#define TZ_ABBR_MAX_LEN	16
-#endif /* !defined TZ_ABBR_MAX_LEN */
-
-#ifndef TZ_ABBR_CHAR_SET
-#define TZ_ABBR_CHAR_SET \
-	"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
-#endif /* !defined TZ_ABBR_CHAR_SET */
-
-#ifndef TZ_ABBR_ERR_CHAR
-#define TZ_ABBR_ERR_CHAR	'_'
-#endif /* !defined TZ_ABBR_ERR_CHAR */
-
-#define INDEXFILE "/system/usr/share/zoneinfo/zoneinfo.idx"
-#define DATAFILE "/system/usr/share/zoneinfo/zoneinfo.dat"
-#define NAMELEN 40
-#define INTLEN 4
-#define READLEN (NAMELEN + 3 * INTLEN)
-
-/*
-** SunOS 4.1.1 headers lack O_BINARY.
-*/
-
-#ifdef O_BINARY
-#define OPEN_MODE	(O_RDONLY | O_BINARY)
-#endif /* defined O_BINARY */
-#ifndef O_BINARY
-#define OPEN_MODE	O_RDONLY
-#endif /* !defined O_BINARY */
-
-/* Complex computations to determine the min/max of time_t depending
- * on TYPE_BIT / TYPE_SIGNED / TYPE_INTEGRAL.
- * These macros cannot be used in pre-processor directives, so we
- * let the C compiler do the work, which makes things a bit funky.
- */
-static const time_t TIME_T_MAX =
-    TYPE_INTEGRAL(time_t) ?
-        ( TYPE_SIGNED(time_t) ?
-            ~((time_t)1 << (TYPE_BIT(time_t)-1))
-        :
-            ~(time_t)0
-        )
-    : /* if time_t is a floating point number */
-        ( sizeof(time_t) > sizeof(float) ? (time_t)DBL_MAX : (time_t)FLT_MAX );
-
-static const time_t TIME_T_MIN =
-    TYPE_INTEGRAL(time_t) ?
-        ( TYPE_SIGNED(time_t) ?
-            ((time_t)1 << (TYPE_BIT(time_t)-1))
-        :
-            0
-        )
-    :
-        ( sizeof(time_t) > sizeof(float) ? (time_t)DBL_MIN : (time_t)FLT_MIN );
-
-#ifndef WILDABBR
-/*
-** Someone might make incorrect use of a time zone abbreviation:
-**	1.	They might reference tzname[0] before calling tzset (explicitly
-**		or implicitly).
-**	2.	They might reference tzname[1] before calling tzset (explicitly
-**		or implicitly).
-**	3.	They might reference tzname[1] after setting to a time zone
-**		in which Daylight Saving Time is never observed.
-**	4.	They might reference tzname[0] after setting to a time zone
-**		in which Standard Time is never observed.
-**	5.	They might reference tm.TM_ZONE after calling offtime.
-** What's best to do in the above cases is open to debate;
-** for now, we just set things up so that in any of the five cases
-** WILDABBR is used. Another possibility: initialize tzname[0] to the
-** string "tzname[0] used before set", and similarly for the other cases.
-** And another: initialize tzname[0] to "ERA", with an explanation in the
-** manual page of what this "time zone abbreviation" means (doing this so
-** that tzname[0] has the "normal" length of three characters).
-*/
-#define WILDABBR	"   "
-#endif /* !defined WILDABBR */
-
-static char		wildabbr[] = WILDABBR;
-
-static const char	gmt[] = "GMT";
-
-/*
-** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
-** We default to US rules as of 1999-08-17.
-** POSIX 1003.1 section 8.1.1 says that the default DST rules are
-** implementation dependent; for historical reasons, US rules are a
-** common default.
-*/
-#ifndef TZDEFRULESTRING
-#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
-#endif /* !defined TZDEFDST */
-
-struct ttinfo {				/* time type information */
-	long		tt_gmtoff;	/* UTC offset in seconds */
-	int		tt_isdst;	/* used to set tm_isdst */
-	int		tt_abbrind;	/* abbreviation list index */
-	int		tt_ttisstd;	/* TRUE if transition is std time */
-	int		tt_ttisgmt;	/* TRUE if transition is UTC */
-};
-
-struct lsinfo {				/* leap second information */
-	time_t		ls_trans;	/* transition time */
-	long		ls_corr;	/* correction to apply */
-};
-
-#define BIGGEST(a, b)	(((a) > (b)) ? (a) : (b))
-
-#ifdef TZNAME_MAX
-#define MY_TZNAME_MAX	TZNAME_MAX
-#endif /* defined TZNAME_MAX */
-#ifndef TZNAME_MAX
-#define MY_TZNAME_MAX	255
-#endif /* !defined TZNAME_MAX */
-
-struct state {
-	int		leapcnt;
-	int		timecnt;
-	int		typecnt;
-	int		charcnt;
-	int		goback;
-	int		goahead;
-	time_t		ats[TZ_MAX_TIMES];
-	unsigned char	types[TZ_MAX_TIMES];
-	struct ttinfo	ttis[TZ_MAX_TYPES];
-	char		chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
-				(2 * (MY_TZNAME_MAX + 1)))];
-	struct lsinfo	lsis[TZ_MAX_LEAPS];
-};
-
-struct rule {
-	int		r_type;		/* type of rule--see below */
-	int		r_day;		/* day number of rule */
-	int		r_week;		/* week number of rule */
-	int		r_mon;		/* month number of rule */
-	long		r_time;		/* transition time of rule */
-};
-
-#define JULIAN_DAY		0	/* Jn - Julian day */
-#define DAY_OF_YEAR		1	/* n - day of year */
-#define MONTH_NTH_DAY_OF_WEEK	2	/* Mm.n.d - month, week, day of week */
-
-/*
-** Prototypes for static functions.
-*/
-
-static long		detzcode P((const char * codep));
-static time_t		detzcode64 P((const char * codep));
-static int		differ_by_repeat P((time_t t1, time_t t0));
-static const char *	getzname P((const char * strp));
-static const char *	getqzname P((const char * strp, const int delim));
-static const char *	getnum P((const char * strp, int * nump, int min,
-				int max));
-static const char *	getsecs P((const char * strp, long * secsp));
-static const char *	getoffset P((const char * strp, long * offsetp));
-static const char *	getrule P((const char * strp, struct rule * rulep));
-static void		gmtload P((struct state * sp));
-static struct tm *	gmtsub P((const time_t * timep, long offset,
-				struct tm * tmp));
-static struct tm *	localsub P((const time_t * timep, long offset,
-				struct tm * tmp, const struct state *sp));
-static int		increment_overflow P((int * number, int delta));
-static int		leaps_thru_end_of P((int y));
-static int		long_increment_overflow P((long * number, int delta));
-static int		long_normalize_overflow P((long * tensptr,
-				int * unitsptr, int base));
-static int		normalize_overflow P((int * tensptr, int * unitsptr,
-				int base));
-static void		settzname P((void));
-static time_t		time1 P((struct tm * tmp,
-				struct tm * (*funcp) P((const time_t *,
-				long, struct tm *, const struct state* sp)),
-				long offset, const struct state *	sp));
-static time_t		time2 P((struct tm *tmp,
-				struct tm * (*funcp) P((const time_t *,
-				long, struct tm*, const struct state* sp)),
-				long offset, int * okayp, const struct state *	sp));
-static time_t		time2sub P((struct tm *tmp,
-				struct tm * (*funcp) P((const time_t*, long, struct tm*,const struct state *sp)),
-				long offset, int * okayp, int do_norm_secs,
-                const struct state *sp));
-static struct tm *	timesub P((const time_t * timep, long offset,
-				const struct state * sp, struct tm * tmp));
-static int		tmcomp P((const struct tm * atmp,
-				const struct tm * btmp));
-static time_t		transtime P((time_t janfirst, int year,
-				const struct rule * rulep, long offset));
-static int		tzload P((const char * name, struct state * sp,
-				int doextend));
-static int		tzload_uncached P((const char * name, struct state * sp,
-				int doextend));
-static int		tzparse P((const char * name, struct state * sp,
-				int lastditch));
-
-#ifdef ALL_STATE
-static struct state *	gmtptr;
-#endif /* defined ALL_STATE */
-
-#ifndef ALL_STATE
-static struct state	gmtmem;
-#define gmtptr		(&gmtmem)
-#endif /* State Farm */
-
-#define CACHE_COUNT 4
-static char * g_cacheNames[CACHE_COUNT] = {0,0};
-static struct state	g_cacheStates[CACHE_COUNT];
-static int g_lastCache = 0;
-static struct state g_utc;
-unsigned char g_utcSet = 0;
-
-
-#ifndef TZ_STRLEN_MAX
-#define TZ_STRLEN_MAX 255
-#endif /* !defined TZ_STRLEN_MAX */
-
-static char		lcl_TZname[TZ_STRLEN_MAX + 1];
-static int		lcl_is_set;
-static int		gmt_is_set;
-
-char *			tzname[2] = {
-	wildabbr,
-	wildabbr
-};
-
-/*
-** Section 4.12.3 of X3.159-1989 requires that
-**	Except for the strftime function, these functions [asctime,
-**	ctime, gmtime, localtime] return values in one of two static
-**	objects: a broken-down time structure and an array of char.
-** Thanks to Paul Eggert for noting this.
-*/
-
-static struct tm	tm;
-
-#ifdef USG_COMPAT
-time_t			timezone = 0;
-int			daylight = 0;
-#endif /* defined USG_COMPAT */
-
-#ifdef ALTZONE
-time_t			altzone = 0;
-#endif /* defined ALTZONE */
-
-static long
-detzcode(codep)
-const char * const	codep;
-{
-	register long	result;
-	register int	i;
-
-	result = (codep[0] & 0x80) ? ~0L : 0;
-	for (i = 0; i < 4; ++i)
-		result = (result << 8) | (codep[i] & 0xff);
-	return result;
-}
-
-static time_t
-detzcode64(codep)
-const char * const	codep;
-{
-	register time_t	result;
-	register int	i;
-
-	result = (codep[0] & 0x80) ?  (~(int_fast64_t) 0) : 0;
-	for (i = 0; i < 8; ++i)
-		result = result * 256 + (codep[i] & 0xff);
-	return result;
-}
-
-static int
-differ_by_repeat(t1, t0)
-const time_t	t1;
-const time_t	t0;
-{
-	if (TYPE_INTEGRAL(time_t) &&
-		TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
-			return 0;
-	return t1 - t0 == SECSPERREPEAT;
-}
-
-static int toint(unsigned char *s) {
-    return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
-}
-
-static int
-tzload(const char *name, struct state * const sp, const int doextend)
-{
-    if (name) {
-        int i, err;
-        if (0 == strcmp(name, "UTC")) {
-            if (!g_utcSet) {
-                tzload_uncached(name, &g_utc, 1);
-                g_utcSet = 1;
-            }
-            //printf("tzload: utc\n");
-            *sp = g_utc;
-            return 0;
-        }
-        for (i=0; i<CACHE_COUNT; i++) {
-            if (g_cacheNames[i] && 0 == strcmp(name, g_cacheNames[i])) {
-                *sp = g_cacheStates[i];
-                //printf("tzload: hit: %s\n", name);
-                return 0;
-            }
-        }
-        //printf("tzload: miss: %s\n", name);
-        g_lastCache++;
-        if (g_lastCache >= CACHE_COUNT) {
-            g_lastCache = 0;
-        }
-        i = g_lastCache;
-        if (g_cacheNames[i]) {
-            free(g_cacheNames[i]);
-        }
-        err = tzload_uncached(name, &(g_cacheStates[i]), 1);
-        if (err == 0) {
-            g_cacheNames[i] = strdup(name);
-            *sp = g_cacheStates[i];
-            return 0;
-        } else {
-            g_cacheNames[i] = NULL;
-            return err;
-        }
-    }
-    return tzload_uncached(name, sp, doextend);
-}
-
-static int
-tzload_uncached(name, sp, doextend)
-register const char *		name;
-register struct state * const	sp;
-register const int		doextend;
-{
-	register const char *		p;
-	register int			i;
-	register int			fid;
-	register int			stored;
-	register int			nread;
-	union {
-		struct tzhead	tzhead;
-		char		buf[2 * sizeof(struct tzhead) +
-					2 * sizeof *sp +
-					4 * TZ_MAX_TIMES];
-	} u;
-    int                     toread = sizeof u.buf;
-
-	if (name == NULL && (name = TZDEFAULT) == NULL)
-		return -1;
-	{
-		register int	doaccess;
-		/*
-		** Section 4.9.1 of the C standard says that
-		** "FILENAME_MAX expands to an integral constant expression
-		** that is the size needed for an array of char large enough
-		** to hold the longest file name string that the implementation
-		** guarantees can be opened."
-		*/
-		char		fullname[FILENAME_MAX + 1];
-		const char	*origname = name;
-
-		if (name[0] == ':')
-			++name;
-		doaccess = name[0] == '/';
-		if (!doaccess) {
-			if ((p = TZDIR) == NULL)
-				return -1;
-			if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
-				return -1;
-			(void) strcpy(fullname, p);
-			(void) strcat(fullname, "/");
-			(void) strcat(fullname, name);
-			/*
-			** Set doaccess if '.' (as in "../") shows up in name.
-			*/
-			if (strchr(name, '.') != NULL)
-				doaccess = TRUE;
-			name = fullname;
-		}
-		if (doaccess && access(name, R_OK) != 0)
-			return -1;
-		if ((fid = open(name, OPEN_MODE)) == -1) {
-            char buf[READLEN];
-            char name[NAMELEN + 1];
-            int fidix = open(INDEXFILE, OPEN_MODE);
-            int off = -1;
-
-            if (fidix < 0) {
-                return -1;
-            }
-
-            while (read(fidix, buf, sizeof(buf)) == sizeof(buf)) {
-                memcpy(name, buf, NAMELEN);
-                name[NAMELEN] = '\0';
-
-                if (strcmp(name, origname) == 0) {
-                    off = toint((unsigned char *) buf + NAMELEN);
-                    toread = toint((unsigned char *) buf + NAMELEN + INTLEN);
-                    break;
-                }
-            }
-
-            close(fidix);
-
-            if (off < 0)
-                return -1;
-
-            fid = open(DATAFILE, OPEN_MODE);
-
-            if (fid < 0) {
-                return -1;
-            }
-
-            if (lseek(fid, off, SEEK_SET) < 0) {
-                return -1;
-            }
-        }
-	}
-	nread = read(fid, u.buf, toread);
-	if (close(fid) < 0 || nread <= 0)
-		return -1;
-	for (stored = 4; stored <= 8; stored *= 2) {
-		int		ttisstdcnt;
-		int		ttisgmtcnt;
-
-		ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
-		ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
-		sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
-		sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
-		sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
-		sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
-		p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
-		if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
-			sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
-			sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
-			sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
-			(ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
-			(ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
-				return -1;
-		if (nread - (p - u.buf) <
-			sp->timecnt * stored +		/* ats */
-			sp->timecnt +			/* types */
-			sp->typecnt * 6 +		/* ttinfos */
-			sp->charcnt +			/* chars */
-			sp->leapcnt * (stored + 4) +	/* lsinfos */
-			ttisstdcnt +			/* ttisstds */
-			ttisgmtcnt)			/* ttisgmts */
-				return -1;
-		for (i = 0; i < sp->timecnt; ++i) {
-			sp->ats[i] = (stored == 4) ?
-				detzcode(p) : detzcode64(p);
-			p += stored;
-		}
-		for (i = 0; i < sp->timecnt; ++i) {
-			sp->types[i] = (unsigned char) *p++;
-			if (sp->types[i] >= sp->typecnt)
-				return -1;
-		}
-		for (i = 0; i < sp->typecnt; ++i) {
-			register struct ttinfo *	ttisp;
-
-			ttisp = &sp->ttis[i];
-			ttisp->tt_gmtoff = detzcode(p);
-			p += 4;
-			ttisp->tt_isdst = (unsigned char) *p++;
-			if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
-				return -1;
-			ttisp->tt_abbrind = (unsigned char) *p++;
-			if (ttisp->tt_abbrind < 0 ||
-				ttisp->tt_abbrind > sp->charcnt)
-					return -1;
-		}
-		for (i = 0; i < sp->charcnt; ++i)
-			sp->chars[i] = *p++;
-		sp->chars[i] = '\0';	/* ensure '\0' at end */
-		for (i = 0; i < sp->leapcnt; ++i) {
-			register struct lsinfo *	lsisp;
-
-			lsisp = &sp->lsis[i];
-			lsisp->ls_trans = (stored == 4) ?
-				detzcode(p) : detzcode64(p);
-			p += stored;
-			lsisp->ls_corr = detzcode(p);
-			p += 4;
-		}
-		for (i = 0; i < sp->typecnt; ++i) {
-			register struct ttinfo *	ttisp;
-
-			ttisp = &sp->ttis[i];
-			if (ttisstdcnt == 0)
-				ttisp->tt_ttisstd = FALSE;
-			else {
-				ttisp->tt_ttisstd = *p++;
-				if (ttisp->tt_ttisstd != TRUE &&
-					ttisp->tt_ttisstd != FALSE)
-						return -1;
-			}
-		}
-		for (i = 0; i < sp->typecnt; ++i) {
-			register struct ttinfo *	ttisp;
-
-			ttisp = &sp->ttis[i];
-			if (ttisgmtcnt == 0)
-				ttisp->tt_ttisgmt = FALSE;
-			else {
-				ttisp->tt_ttisgmt = *p++;
-				if (ttisp->tt_ttisgmt != TRUE &&
-					ttisp->tt_ttisgmt != FALSE)
-						return -1;
-			}
-		}
-		/*
-		** Out-of-sort ats should mean we're running on a
-		** signed time_t system but using a data file with
-		** unsigned values (or vice versa).
-		*/
-		for (i = 0; i < sp->timecnt - 2; ++i)
-			if (sp->ats[i] > sp->ats[i + 1]) {
-				++i;
-				if (TYPE_SIGNED(time_t)) {
-					/*
-					** Ignore the end (easy).
-					*/
-					sp->timecnt = i;
-				} else {
-					/*
-					** Ignore the beginning (harder).
-					*/
-					register int	j;
-
-					for (j = 0; j + i < sp->timecnt; ++j) {
-						sp->ats[j] = sp->ats[j + i];
-						sp->types[j] = sp->types[j + i];
-					}
-					sp->timecnt = j;
-				}
-				break;
-			}
-		/*
-		** If this is an old file, we're done.
-		*/
-		if (u.tzhead.tzh_version[0] == '\0')
-			break;
-		nread -= p - u.buf;
-		for (i = 0; i < nread; ++i)
-			u.buf[i] = p[i];
-		/*
-		** If this is a narrow integer time_t system, we're done.
-		*/
-		if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
-			break;
-	}
-	if (doextend && nread > 2 &&
-		u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
-		sp->typecnt + 2 <= TZ_MAX_TYPES) {
-			struct state	ts;
-			register int	result;
-
-			u.buf[nread - 1] = '\0';
-			result = tzparse(&u.buf[1], &ts, FALSE);
-			if (result == 0 && ts.typecnt == 2 &&
-				sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
-					for (i = 0; i < 2; ++i)
-						ts.ttis[i].tt_abbrind +=
-							sp->charcnt;
-					for (i = 0; i < ts.charcnt; ++i)
-						sp->chars[sp->charcnt++] =
-							ts.chars[i];
-					i = 0;
-					while (i < ts.timecnt &&
-						ts.ats[i] <=
-						sp->ats[sp->timecnt - 1])
-							++i;
-					while (i < ts.timecnt &&
-					    sp->timecnt < TZ_MAX_TIMES) {
-						sp->ats[sp->timecnt] =
-							ts.ats[i];
-						sp->types[sp->timecnt] =
-							sp->typecnt +
-							ts.types[i];
-						++sp->timecnt;
-						++i;
-					}
-					sp->ttis[sp->typecnt++] = ts.ttis[0];
-					sp->ttis[sp->typecnt++] = ts.ttis[1];
-			}
-	}
-	i = 2 * YEARSPERREPEAT;
-	sp->goback = sp->goahead = sp->timecnt > i;
-	sp->goback &= sp->types[i] == sp->types[0] &&
-		differ_by_repeat(sp->ats[i], sp->ats[0]);
-	sp->goahead &=
-		sp->types[sp->timecnt - 1] == sp->types[sp->timecnt - 1 - i] &&
-		differ_by_repeat(sp->ats[sp->timecnt - 1],
-			 sp->ats[sp->timecnt - 1 - i]);
-	return 0;
-}
-
-static const int	mon_lengths[2][MONSPERYEAR] = {
-	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
-	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
-};
-
-static const int	year_lengths[2] = {
-	DAYSPERNYEAR, DAYSPERLYEAR
-};
-
-/*
-** Given a pointer into a time zone string, scan until a character that is not
-** a valid character in a zone name is found. Return a pointer to that
-** character.
-*/
-
-static const char *
-getzname(strp)
-register const char *	strp;
-{
-	register char	c;
-
-	while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
-		c != '+')
-			++strp;
-	return strp;
-}
-
-/*
-** Given a pointer into an extended time zone string, scan until the ending
-** delimiter of the zone name is located. Return a pointer to the delimiter.
-**
-** As with getzname above, the legal character set is actually quite
-** restricted, with other characters producing undefined results.
-** We don't do any checking here; checking is done later in common-case code.
-*/
-
-static const char *
-getqzname(register const char *strp, const int delim)
-{
-	register int	c;
-
-	while ((c = *strp) != '\0' && c != delim)
-		++strp;
-	return strp;
-}
-
-/*
-** Given a pointer into a time zone string, extract a number from that string.
-** Check that the number is within a specified range; if it is not, return
-** NULL.
-** Otherwise, return a pointer to the first character not part of the number.
-*/
-
-static const char *
-getnum(strp, nump, min, max)
-register const char *	strp;
-int * const		nump;
-const int		min;
-const int		max;
-{
-	register char	c;
-	register int	num;
-
-	if (strp == NULL || !is_digit(c = *strp))
-		return NULL;
-	num = 0;
-	do {
-		num = num * 10 + (c - '0');
-		if (num > max)
-			return NULL;	/* illegal value */
-		c = *++strp;
-	} while (is_digit(c));
-	if (num < min)
-		return NULL;		/* illegal value */
-	*nump = num;
-	return strp;
-}
-
-/*
-** Given a pointer into a time zone string, extract a number of seconds,
-** in hh[:mm[:ss]] form, from the string.
-** If any error occurs, return NULL.
-** Otherwise, return a pointer to the first character not part of the number
-** of seconds.
-*/
-
-static const char *
-getsecs(strp, secsp)
-register const char *	strp;
-long * const		secsp;
-{
-	int	num;
-
-	/*
-	** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
-	** "M10.4.6/26", which does not conform to Posix,
-	** but which specifies the equivalent of
-	** ``02:00 on the first Sunday on or after 23 Oct''.
-	*/
-	strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
-	if (strp == NULL)
-		return NULL;
-	*secsp = num * (long) SECSPERHOUR;
-	if (*strp == ':') {
-		++strp;
-		strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
-		if (strp == NULL)
-			return NULL;
-		*secsp += num * SECSPERMIN;
-		if (*strp == ':') {
-			++strp;
-			/* `SECSPERMIN' allows for leap seconds. */
-			strp = getnum(strp, &num, 0, SECSPERMIN);
-			if (strp == NULL)
-				return NULL;
-			*secsp += num;
-		}
-	}
-	return strp;
-}
-
-/*
-** Given a pointer into a time zone string, extract an offset, in
-** [+-]hh[:mm[:ss]] form, from the string.
-** If any error occurs, return NULL.
-** Otherwise, return a pointer to the first character not part of the time.
-*/
-
-static const char *
-getoffset(strp, offsetp)
-register const char *	strp;
-long * const		offsetp;
-{
-	register int	neg = 0;
-
-	if (*strp == '-') {
-		neg = 1;
-		++strp;
-	} else if (*strp == '+')
-		++strp;
-	strp = getsecs(strp, offsetp);
-	if (strp == NULL)
-		return NULL;		/* illegal time */
-	if (neg)
-		*offsetp = -*offsetp;
-	return strp;
-}
-
-/*
-** Given a pointer into a time zone string, extract a rule in the form
-** date[/time]. See POSIX section 8 for the format of "date" and "time".
-** If a valid rule is not found, return NULL.
-** Otherwise, return a pointer to the first character not part of the rule.
-*/
-
-static const char *
-getrule(strp, rulep)
-const char *			strp;
-register struct rule * const	rulep;
-{
-	if (*strp == 'J') {
-		/*
-		** Julian day.
-		*/
-		rulep->r_type = JULIAN_DAY;
-		++strp;
-		strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
-	} else if (*strp == 'M') {
-		/*
-		** Month, week, day.
-		*/
-		rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
-		++strp;
-		strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
-		if (strp == NULL)
-			return NULL;
-		if (*strp++ != '.')
-			return NULL;
-		strp = getnum(strp, &rulep->r_week, 1, 5);
-		if (strp == NULL)
-			return NULL;
-		if (*strp++ != '.')
-			return NULL;
-		strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
-	} else if (is_digit(*strp)) {
-		/*
-		** Day of year.
-		*/
-		rulep->r_type = DAY_OF_YEAR;
-		strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
-	} else	return NULL;		/* invalid format */
-	if (strp == NULL)
-		return NULL;
-	if (*strp == '/') {
-		/*
-		** Time specified.
-		*/
-		++strp;
-		strp = getsecs(strp, &rulep->r_time);
-	} else	rulep->r_time = 2 * SECSPERHOUR;	/* default = 2:00:00 */
-	return strp;
-}
-
-/*
-** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
-** year, a rule, and the offset from UTC at the time that rule takes effect,
-** calculate the Epoch-relative time that rule takes effect.
-*/
-
-static time_t
-transtime(janfirst, year, rulep, offset)
-const time_t				janfirst;
-const int				year;
-register const struct rule * const	rulep;
-const long				offset;
-{
-	register int	leapyear;
-	register time_t	value;
-	register int	i;
-	int		d, m1, yy0, yy1, yy2, dow;
-
-	INITIALIZE(value);
-	leapyear = isleap(year);
-	switch (rulep->r_type) {
-
-	case JULIAN_DAY:
-		/*
-		** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
-		** years.
-		** In non-leap years, or if the day number is 59 or less, just
-		** add SECSPERDAY times the day number-1 to the time of
-		** January 1, midnight, to get the day.
-		*/
-		value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
-		if (leapyear && rulep->r_day >= 60)
-			value += SECSPERDAY;
-		break;
-
-	case DAY_OF_YEAR:
-		/*
-		** n - day of year.
-		** Just add SECSPERDAY times the day number to the time of
-		** January 1, midnight, to get the day.
-		*/
-		value = janfirst + rulep->r_day * SECSPERDAY;
-		break;
-
-	case MONTH_NTH_DAY_OF_WEEK:
-		/*
-		** Mm.n.d - nth "dth day" of month m.
-		*/
-		value = janfirst;
-		for (i = 0; i < rulep->r_mon - 1; ++i)
-			value += mon_lengths[leapyear][i] * SECSPERDAY;
-
-		/*
-		** Use Zeller's Congruence to get day-of-week of first day of
-		** month.
-		*/
-		m1 = (rulep->r_mon + 9) % 12 + 1;
-		yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
-		yy1 = yy0 / 100;
-		yy2 = yy0 % 100;
-		dow = ((26 * m1 - 2) / 10 +
-			1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
-		if (dow < 0)
-			dow += DAYSPERWEEK;
-
-		/*
-		** "dow" is the day-of-week of the first day of the month. Get
-		** the day-of-month (zero-origin) of the first "dow" day of the
-		** month.
-		*/
-		d = rulep->r_day - dow;
-		if (d < 0)
-			d += DAYSPERWEEK;
-		for (i = 1; i < rulep->r_week; ++i) {
-			if (d + DAYSPERWEEK >=
-				mon_lengths[leapyear][rulep->r_mon - 1])
-					break;
-			d += DAYSPERWEEK;
-		}
-
-		/*
-		** "d" is the day-of-month (zero-origin) of the day we want.
-		*/
-		value += d * SECSPERDAY;
-		break;
-	}
-
-	/*
-	** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
-	** question. To get the Epoch-relative time of the specified local
-	** time on that day, add the transition time and the current offset
-	** from UTC.
-	*/
-	return value + rulep->r_time + offset;
-}
-
-/*
-** Given a POSIX section 8-style TZ string, fill in the rule tables as
-** appropriate.
-*/
-
-static int
-tzparse(name, sp, lastditch)
-const char *			name;
-register struct state * const	sp;
-const int			lastditch;
-{
-	const char *			stdname;
-	const char *			dstname;
-	size_t				stdlen;
-	size_t				dstlen;
-	long				stdoffset;
-	long				dstoffset;
-	register time_t *		atp;
-	register unsigned char *	typep;
-	register char *			cp;
-	register int			load_result;
-
-	INITIALIZE(dstname);
-	stdname = name;
-	if (lastditch) {
-		stdlen = strlen(name);	/* length of standard zone name */
-		name += stdlen;
-		if (stdlen >= sizeof sp->chars)
-			stdlen = (sizeof sp->chars) - 1;
-		stdoffset = 0;
-	} else {
-		if (*name == '<') {
-			name++;
-			stdname = name;
-			name = getqzname(name, '>');
-			if (*name != '>')
-				return (-1);
-			stdlen = name - stdname;
-			name++;
-		} else {
-			name = getzname(name);
-			stdlen = name - stdname;
-		}
-		if (*name == '\0')
-			return -1;
-		name = getoffset(name, &stdoffset);
-		if (name == NULL)
-			return -1;
-	}
-	load_result = tzload(TZDEFRULES, sp, FALSE);
-	if (load_result != 0)
-		sp->leapcnt = 0;		/* so, we're off a little */
-	sp->timecnt = 0;
-	if (*name != '\0') {
-		if (*name == '<') {
-			dstname = ++name;
-			name = getqzname(name, '>');
-			if (*name != '>')
-				return -1;
-			dstlen = name - dstname;
-			name++;
-		} else {
-			dstname = name;
-			name = getzname(name);
-			dstlen = name - dstname; /* length of DST zone name */
-		}
-		if (*name != '\0' && *name != ',' && *name != ';') {
-			name = getoffset(name, &dstoffset);
-			if (name == NULL)
-				return -1;
-		} else	dstoffset = stdoffset - SECSPERHOUR;
-		if (*name == '\0' && load_result != 0)
-			name = TZDEFRULESTRING;
-		if (*name == ',' || *name == ';') {
-			struct rule	start;
-			struct rule	end;
-			register int	year;
-			register time_t	janfirst;
-			time_t		starttime;
-			time_t		endtime;
-
-			++name;
-			if ((name = getrule(name, &start)) == NULL)
-				return -1;
-			if (*name++ != ',')
-				return -1;
-			if ((name = getrule(name, &end)) == NULL)
-				return -1;
-			if (*name != '\0')
-				return -1;
-			sp->typecnt = 2;	/* standard time and DST */
-			/*
-			** Two transitions per year, from EPOCH_YEAR forward.
-			*/
-			sp->ttis[0].tt_gmtoff = -dstoffset;
-			sp->ttis[0].tt_isdst = 1;
-			sp->ttis[0].tt_abbrind = stdlen + 1;
-			sp->ttis[1].tt_gmtoff = -stdoffset;
-			sp->ttis[1].tt_isdst = 0;
-			sp->ttis[1].tt_abbrind = 0;
-			atp = sp->ats;
-			typep = sp->types;
-			janfirst = 0;
-			for (year = EPOCH_YEAR;
-			    sp->timecnt + 2 <= TZ_MAX_TIMES;
-			    ++year) {
-			    	time_t	newfirst;
-
-				starttime = transtime(janfirst, year, &start,
-					stdoffset);
-				endtime = transtime(janfirst, year, &end,
-					dstoffset);
-				if (starttime > endtime) {
-					*atp++ = endtime;
-					*typep++ = 1;	/* DST ends */
-					*atp++ = starttime;
-					*typep++ = 0;	/* DST begins */
-				} else {
-					*atp++ = starttime;
-					*typep++ = 0;	/* DST begins */
-					*atp++ = endtime;
-					*typep++ = 1;	/* DST ends */
-				}
-				sp->timecnt += 2;
-				newfirst = janfirst;
-				newfirst += year_lengths[isleap(year)] *
-					SECSPERDAY;
-				if (newfirst <= janfirst)
-					break;
-				janfirst = newfirst;
-			}
-		} else {
-			register long	theirstdoffset;
-			register long	theirdstoffset;
-			register long	theiroffset;
-			register int	isdst;
-			register int	i;
-			register int	j;
-
-			if (*name != '\0')
-				return -1;
-			/*
-			** Initial values of theirstdoffset and theirdstoffset.
-			*/
-			theirstdoffset = 0;
-			for (i = 0; i < sp->timecnt; ++i) {
-				j = sp->types[i];
-				if (!sp->ttis[j].tt_isdst) {
-					theirstdoffset =
-						-sp->ttis[j].tt_gmtoff;
-					break;
-				}
-			}
-			theirdstoffset = 0;
-			for (i = 0; i < sp->timecnt; ++i) {
-				j = sp->types[i];
-				if (sp->ttis[j].tt_isdst) {
-					theirdstoffset =
-						-sp->ttis[j].tt_gmtoff;
-					break;
-				}
-			}
-			/*
-			** Initially we're assumed to be in standard time.
-			*/
-			isdst = FALSE;
-			theiroffset = theirstdoffset;
-			/*
-			** Now juggle transition times and types
-			** tracking offsets as you do.
-			*/
-			for (i = 0; i < sp->timecnt; ++i) {
-				j = sp->types[i];
-				sp->types[i] = sp->ttis[j].tt_isdst;
-				if (sp->ttis[j].tt_ttisgmt) {
-					/* No adjustment to transition time */
-				} else {
-					/*
-					** If summer time is in effect, and the
-					** transition time was not specified as
-					** standard time, add the summer time
-					** offset to the transition time;
-					** otherwise, add the standard time
-					** offset to the transition time.
-					*/
-					/*
-					** Transitions from DST to DDST
-					** will effectively disappear since
-					** POSIX provides for only one DST
-					** offset.
-					*/
-					if (isdst && !sp->ttis[j].tt_ttisstd) {
-						sp->ats[i] += dstoffset -
-							theirdstoffset;
-					} else {
-						sp->ats[i] += stdoffset -
-							theirstdoffset;
-					}
-				}
-				theiroffset = -sp->ttis[j].tt_gmtoff;
-				if (sp->ttis[j].tt_isdst)
-					theirdstoffset = theiroffset;
-				else	theirstdoffset = theiroffset;
-			}
-			/*
-			** Finally, fill in ttis.
-			** ttisstd and ttisgmt need not be handled.
-			*/
-			sp->ttis[0].tt_gmtoff = -stdoffset;
-			sp->ttis[0].tt_isdst = FALSE;
-			sp->ttis[0].tt_abbrind = 0;
-			sp->ttis[1].tt_gmtoff = -dstoffset;
-			sp->ttis[1].tt_isdst = TRUE;
-			sp->ttis[1].tt_abbrind = stdlen + 1;
-			sp->typecnt = 2;
-		}
-	} else {
-		dstlen = 0;
-		sp->typecnt = 1;		/* only standard time */
-		sp->timecnt = 0;
-		sp->ttis[0].tt_gmtoff = -stdoffset;
-		sp->ttis[0].tt_isdst = 0;
-		sp->ttis[0].tt_abbrind = 0;
-	}
-	sp->charcnt = stdlen + 1;
-	if (dstlen != 0)
-		sp->charcnt += dstlen + 1;
-	if ((size_t) sp->charcnt > sizeof sp->chars)
-		return -1;
-	cp = sp->chars;
-	(void) strncpy(cp, stdname, stdlen);
-	cp += stdlen;
-	*cp++ = '\0';
-	if (dstlen != 0) {
-		(void) strncpy(cp, dstname, dstlen);
-		*(cp + dstlen) = '\0';
-	}
-	return 0;
-}
-
-static void
-gmtload(sp)
-struct state * const	sp;
-{
-	if (tzload(gmt, sp, TRUE) != 0)
-		(void) tzparse(gmt, sp, TRUE);
-}
-
-/*
-** The easy way to behave "as if no library function calls" localtime
-** is to not call it--so we drop its guts into "localsub", which can be
-** freely called. (And no, the PANS doesn't require the above behavior--
-** but it *is* desirable.)
-**
-** The unused offset argument is for the benefit of mktime variants.
-*/
-
-/*ARGSUSED*/
-static struct tm *
-localsub(timep, offset, tmp, sp)
-const time_t * const	timep;
-const long		offset;
-struct tm * const	tmp;
-const struct state *		sp;
-{
-	register const struct ttinfo *	ttisp;
-	register int			i;
-	register struct tm *		result;
-	const time_t			t = *timep;
-
-#ifdef ALL_STATE
-	if (sp == NULL)
-		return gmtsub(timep, offset, tmp);
-#endif /* defined ALL_STATE */
-	if ((sp->goback && t < sp->ats[0]) ||
-		(sp->goahead && t > sp->ats[sp->timecnt - 1])) {
-			time_t			newt = t;
-			register time_t		seconds;
-			register time_t		tcycles;
-			register int_fast64_t	icycles;
-
-			if (t < sp->ats[0])
-				seconds = sp->ats[0] - t;
-			else	seconds = t - sp->ats[sp->timecnt - 1];
-			--seconds;
-			tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
-			++tcycles;
-			icycles = tcycles;
-			if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
-				return NULL;
-			seconds = icycles;
-			seconds *= YEARSPERREPEAT;
-			seconds *= AVGSECSPERYEAR;
-			if (t < sp->ats[0])
-				newt += seconds;
-			else	newt -= seconds;
-			if (newt < sp->ats[0] ||
-				newt > sp->ats[sp->timecnt - 1])
-					return NULL;	/* "cannot happen" */
-			result = localsub(&newt, offset, tmp, sp);
-			if (result == tmp) {
-				register time_t	newy;
-
-				newy = tmp->tm_year;
-				if (t < sp->ats[0])
-					newy -= icycles * YEARSPERREPEAT;
-				else	newy += icycles * YEARSPERREPEAT;
-				tmp->tm_year = newy;
-				if (tmp->tm_year != newy)
-					return NULL;
-			}
-			return result;
-	}
-	if (sp->timecnt == 0 || t < sp->ats[0]) {
-		i = 0;
-		while (sp->ttis[i].tt_isdst)
-			if (++i >= sp->typecnt) {
-				i = 0;
-				break;
-			}
-	} else {
-		register int	lo = 1;
-		register int	hi = sp->timecnt;
-
-		while (lo < hi) {
-			register int	mid = (lo + hi) >> 1;
-
-			if (t < sp->ats[mid])
-				hi = mid;
-			else	lo = mid + 1;
-		}
-		i = (int) sp->types[lo - 1];
-	}
-	ttisp = &sp->ttis[i];
-	/*
-	** To get (wrong) behavior that's compatible with System V Release 2.0
-	** you'd replace the statement below with
-	**	t += ttisp->tt_gmtoff;
-	**	timesub(&t, 0L, sp, tmp);
-	*/
-	result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
-	tmp->tm_isdst = ttisp->tt_isdst;
-#ifdef HAVE_TM_GMTOFF
-	tmp->tm_gmtoff = ttisp->tt_gmtoff;
-#endif
-	tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
-#ifdef TM_ZONE
-	tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
-#endif /* defined TM_ZONE */
-	return result;
-}
-
-
-// ============================================================================
-#if 0
-struct tm *
-localtime(timep)
-const time_t * const	timep;
-{
-	tzset();
-	return localsub(timep, 0L, &tm);
-}
-#endif
-
-/*
-** Re-entrant version of localtime.
-*/
-
-// ============================================================================
-void
-localtime_tz(const time_t * const timep, struct tm * tmp, const char* tz)
-{
-    struct state st;
-    if (tzload(tz, &st, TRUE) != 0) {
-        // not sure what's best here, but for now, we fall back to gmt
-        gmtload(&st);
-    }
-
-	localsub(timep, 0L, tmp, &st);
-}
-
-/*
-** gmtsub is to gmtime as localsub is to localtime.
-*/
-
-static struct tm *
-gmtsub(timep, offset, tmp)
-const time_t * const	timep;
-const long		offset;
-struct tm * const	tmp;
-{
-	register struct tm *	result;
-
-	if (!gmt_is_set) {
-		gmt_is_set = TRUE;
-#ifdef ALL_STATE
-		gmtptr = (struct state *) malloc(sizeof *gmtptr);
-		if (gmtptr != NULL)
-#endif /* defined ALL_STATE */
-			gmtload(gmtptr);
-	}
-	result = timesub(timep, offset, gmtptr, tmp);
-#ifdef TM_ZONE
-	/*
-	** Could get fancy here and deliver something such as
-	** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
-	** but this is no time for a treasure hunt.
-	*/
-	if (offset != 0)
-		tmp->TM_ZONE = wildabbr;
-	else {
-#ifdef ALL_STATE
-		if (gmtptr == NULL)
-			tmp->TM_ZONE = gmt;
-		else	tmp->TM_ZONE = gmtptr->chars;
-#endif /* defined ALL_STATE */
-#ifndef ALL_STATE
-		tmp->TM_ZONE = gmtptr->chars;
-#endif /* State Farm */
-	}
-#endif /* defined TM_ZONE */
-	return result;
-}
-
-// ============================================================================
-#if 0
-struct tm *
-gmtime(timep)
-const time_t * const	timep;
-{
-	return gmtsub(timep, 0L, &tm);
-}
-#endif
-
-/*
-* Re-entrant version of gmtime.
-*/
-
-// ============================================================================
-#if 0
-struct tm *
-gmtime_r(timep, tmp)
-const time_t * const	timep;
-struct tm *		tmp;
-{
-	return gmtsub(timep, 0L, tmp);
-}
-#endif
-
-#ifdef STD_INSPIRED
-
-// ============================================================================
-#if 0
-struct tm *
-offtime(timep, offset)
-const time_t * const	timep;
-const long		offset;
-{
-	return gmtsub(timep, offset, &tm);
-}
-#endif
-
-#endif /* defined STD_INSPIRED */
-
-/*
-** Return the number of leap years through the end of the given year
-** where, to make the math easy, the answer for year zero is defined as zero.
-*/
-
-static int
-leaps_thru_end_of(y)
-register const int	y;
-{
-	return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
-		-(leaps_thru_end_of(-(y + 1)) + 1);
-}
-
-static struct tm *
-timesub(timep, offset, sp, tmp)
-const time_t * const			timep;
-const long				offset;
-register const struct state * const	sp;
-register struct tm * const		tmp;
-{
-	register const struct lsinfo *	lp;
-	register time_t			tdays;
-	register int			idays;	/* unsigned would be so 2003 */
-	register long			rem;
-	int				y;
-	register const int *		ip;
-	register long			corr;
-	register int			hit;
-	register int			i;
-
-	corr = 0;
-	hit = 0;
-#ifdef ALL_STATE
-	i = (sp == NULL) ? 0 : sp->leapcnt;
-#endif /* defined ALL_STATE */
-#ifndef ALL_STATE
-	i = sp->leapcnt;
-#endif /* State Farm */
-	while (--i >= 0) {
-		lp = &sp->lsis[i];
-		if (*timep >= lp->ls_trans) {
-			if (*timep == lp->ls_trans) {
-				hit = ((i == 0 && lp->ls_corr > 0) ||
-					lp->ls_corr > sp->lsis[i - 1].ls_corr);
-				if (hit)
-					while (i > 0 &&
-						sp->lsis[i].ls_trans ==
-						sp->lsis[i - 1].ls_trans + 1 &&
-						sp->lsis[i].ls_corr ==
-						sp->lsis[i - 1].ls_corr + 1) {
-							++hit;
-							--i;
-					}
-			}
-			corr = lp->ls_corr;
-			break;
-		}
-	}
-	y = EPOCH_YEAR;
-	tdays = *timep / SECSPERDAY;
-	rem = *timep - tdays * SECSPERDAY;
-	while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
-		int		newy;
-		register time_t	tdelta;
-		register int	idelta;
-		register int	leapdays;
-
-		tdelta = tdays / DAYSPERLYEAR;
-		idelta = tdelta;
-		if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
-			return NULL;
-		if (idelta == 0)
-			idelta = (tdays < 0) ? -1 : 1;
-		newy = y;
-		if (increment_overflow(&newy, idelta))
-			return NULL;
-		leapdays = leaps_thru_end_of(newy - 1) -
-			leaps_thru_end_of(y - 1);
-		tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
-		tdays -= leapdays;
-		y = newy;
-	}
-	{
-		register long	seconds;
-
-		seconds = tdays * SECSPERDAY + 0.5;
-		tdays = seconds / SECSPERDAY;
-		rem += seconds - tdays * SECSPERDAY;
-	}
-	/*
-	** Given the range, we can now fearlessly cast...
-	*/
-	idays = tdays;
-	rem += offset - corr;
-	while (rem < 0) {
-		rem += SECSPERDAY;
-		--idays;
-	}
-	while (rem >= SECSPERDAY) {
-		rem -= SECSPERDAY;
-		++idays;
-	}
-	while (idays < 0) {
-		if (increment_overflow(&y, -1))
-			return NULL;
-		idays += year_lengths[isleap(y)];
-	}
-	while (idays >= year_lengths[isleap(y)]) {
-		idays -= year_lengths[isleap(y)];
-		if (increment_overflow(&y, 1))
-			return NULL;
-	}
-	tmp->tm_year = y;
-	if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
-		return NULL;
-	tmp->tm_yday = idays;
-	/*
-	** The "extra" mods below avoid overflow problems.
-	*/
-	tmp->tm_wday = EPOCH_WDAY +
-		((y - EPOCH_YEAR) % DAYSPERWEEK) *
-		(DAYSPERNYEAR % DAYSPERWEEK) +
-		leaps_thru_end_of(y - 1) -
-		leaps_thru_end_of(EPOCH_YEAR - 1) +
-		idays;
-	tmp->tm_wday %= DAYSPERWEEK;
-	if (tmp->tm_wday < 0)
-		tmp->tm_wday += DAYSPERWEEK;
-	tmp->tm_hour = (int) (rem / SECSPERHOUR);
-	rem %= SECSPERHOUR;
-	tmp->tm_min = (int) (rem / SECSPERMIN);
-	/*
-	** A positive leap second requires a special
-	** representation. This uses "... ??:59:60" et seq.
-	*/
-	tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
-	ip = mon_lengths[isleap(y)];
-	for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
-		idays -= ip[tmp->tm_mon];
-	tmp->tm_mday = (int) (idays + 1);
-	tmp->tm_isdst = 0;
-#ifdef TM_GMTOFF
-	tmp->TM_GMTOFF = offset;
-#endif /* defined TM_GMTOFF */
-	return tmp;
-}
-
-// ============================================================================
-#if 0
-char *
-ctime(timep)
-const time_t * const	timep;
-{
-/*
-** Section 4.12.3.2 of X3.159-1989 requires that
-**	The ctime function converts the calendar time pointed to by timer
-**	to local time in the form of a string. It is equivalent to
-**		asctime(localtime(timer))
-*/
-	return asctime(localtime(timep));
-}
-#endif
-
-// ============================================================================
-#if 0
-char *
-ctime_r(timep, buf)
-const time_t * const	timep;
-char *			buf;
-{
-	struct tm	mytm;
-
-	return asctime_r(localtime_r(timep, &mytm), buf);
-}
-#endif
-
-/*
-** Adapted from code provided by Robert Elz, who writes:
-**	The "best" way to do mktime I think is based on an idea of Bob
-**	Kridle's (so its said...) from a long time ago.
-**	It does a binary search of the time_t space. Since time_t's are
-**	just 32 bits, its a max of 32 iterations (even at 64 bits it
-**	would still be very reasonable).
-*/
-
-#ifndef WRONG
-#define WRONG	(-1)
-#endif /* !defined WRONG */
-
-/*
-** Simplified normalize logic courtesy Paul Eggert.
-*/
-
-static int
-increment_overflow(number, delta)
-int *   number;
-int delta;
-{
-    unsigned  number0 = (unsigned)*number;
-    unsigned  number1 = (unsigned)(number0 + delta);
-
-    *number = (int)number1;
-
-    if (delta >= 0) {
-        return ((int)number1 < (int)number0);
-    } else {
-        return ((int)number1 > (int)number0);
-    }
-}
-
-static int
-long_increment_overflow(number, delta)
-long *  number;
-int delta;
-{
-    unsigned long  number0 = (unsigned long)*number;
-    unsigned long  number1 = (unsigned long)(number0 + delta);
-
-    *number = (long)number1;
-
-    if (delta >= 0) {
-        return ((long)number1 < (long)number0);
-    } else {
-        return ((long)number1 > (long)number0);
-    }
-}
-
-static int
-normalize_overflow(tensptr, unitsptr, base)
-int * const	tensptr;
-int * const	unitsptr;
-const int	base;
-{
-	register int	tensdelta;
-
-	tensdelta = (*unitsptr >= 0) ?
-		(*unitsptr / base) :
-		(-1 - (-1 - *unitsptr) / base);
-	*unitsptr -= tensdelta * base;
-	return increment_overflow(tensptr, tensdelta);
-}
-
-static int
-long_normalize_overflow(tensptr, unitsptr, base)
-long * const	tensptr;
-int * const	unitsptr;
-const int	base;
-{
-	register int	tensdelta;
-
-	tensdelta = (*unitsptr >= 0) ?
-		(*unitsptr / base) :
-		(-1 - (-1 - *unitsptr) / base);
-	*unitsptr -= tensdelta * base;
-	return long_increment_overflow(tensptr, tensdelta);
-}
-
-static int
-tmcomp(atmp, btmp)
-register const struct tm * const atmp;
-register const struct tm * const btmp;
-{
-	register int	result;
-
-	if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
-		(result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
-		(result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
-		(result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
-		(result = (atmp->tm_min - btmp->tm_min)) == 0)
-			result = atmp->tm_sec - btmp->tm_sec;
-	return result;
-}
-
-static time_t
-time2sub(tmp, funcp, offset, okayp, do_norm_secs, sp)
-struct tm * const	tmp;
-struct tm * (* const	funcp) P((const time_t*, long, struct tm*,const struct state *sp));
-const long		offset;
-int * const		okayp;
-const int		do_norm_secs;
-const struct state *	sp;
-{
-	register int			dir;
-	register int			i, j;
-	register int			saved_seconds;
-	register long			li;
-	register time_t			lo;
-	register time_t			hi;
-	long				y;
-	time_t				newt;
-	time_t				t;
-	struct tm			yourtm, mytm;
-
-	*okayp = FALSE;
-	yourtm = *tmp;
-	if (do_norm_secs) {
-		if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
-			SECSPERMIN))
-				return WRONG;
-	}
-	if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
-		return WRONG;
-	if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
-		return WRONG;
-	y = yourtm.tm_year;
-	if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
-		return WRONG;
-	/*
-	** Turn y into an actual year number for now.
-	** It is converted back to an offset from TM_YEAR_BASE later.
-	*/
-	if (long_increment_overflow(&y, TM_YEAR_BASE))
-		return WRONG;
-	while (yourtm.tm_mday <= 0) {
-		if (long_increment_overflow(&y, -1))
-			return WRONG;
-		li = y + (1 < yourtm.tm_mon);
-		yourtm.tm_mday += year_lengths[isleap(li)];
-	}
-	while (yourtm.tm_mday > DAYSPERLYEAR) {
-		li = y + (1 < yourtm.tm_mon);
-		yourtm.tm_mday -= year_lengths[isleap(li)];
-		if (long_increment_overflow(&y, 1))
-			return WRONG;
-	}
-	for ( ; ; ) {
-		i = mon_lengths[isleap(y)][yourtm.tm_mon];
-		if (yourtm.tm_mday <= i)
-			break;
-		yourtm.tm_mday -= i;
-		if (++yourtm.tm_mon >= MONSPERYEAR) {
-			yourtm.tm_mon = 0;
-			if (long_increment_overflow(&y, 1))
-				return WRONG;
-		}
-	}
-	if (long_increment_overflow(&y, -TM_YEAR_BASE))
-		return WRONG;
-	yourtm.tm_year = y;
-	if (yourtm.tm_year != y)
-		return WRONG;
-	if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
-		saved_seconds = 0;
-	else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
-		/*
-		** We can't set tm_sec to 0, because that might push the
-		** time below the minimum representable time.
-		** Set tm_sec to 59 instead.
-		** This assumes that the minimum representable time is
-		** not in the same minute that a leap second was deleted from,
-		** which is a safer assumption than using 58 would be.
-		*/
-		if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
-			return WRONG;
-		saved_seconds = yourtm.tm_sec;
-		yourtm.tm_sec = SECSPERMIN - 1;
-	} else {
-		saved_seconds = yourtm.tm_sec;
-		yourtm.tm_sec = 0;
-	}
-	/*
-	** Do a binary search (this works whatever time_t's type is).
-	*/
-	if (!TYPE_SIGNED(time_t)) {
-		lo = 0;
-		hi = lo - 1;
-	} else if (!TYPE_INTEGRAL(time_t)) {
-		if (sizeof(time_t) > sizeof(float))
-			hi = (time_t) DBL_MAX;
-		else	hi = (time_t) FLT_MAX;
-		lo = -hi;
-	} else {
-		lo = 1;
-		for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
-			lo *= 2;
-		hi = -(lo + 1);
-	}
-	for ( ; ; ) {
-		t = lo / 2 + hi / 2;
-		if (t < lo)
-			t = lo;
-		else if (t > hi)
-			t = hi;
-		if ((*funcp)(&t, offset, &mytm, sp) == NULL) {
-			/*
-			** Assume that t is too extreme to be represented in
-			** a struct tm; arrange things so that it is less
-			** extreme on the next pass.
-			*/
-			dir = (t > 0) ? 1 : -1;
-		} else	dir = tmcomp(&mytm, &yourtm);
-		if (dir != 0) {
-			if (t == lo) {
-			        if (t == TIME_T_MAX)
-			             return WRONG;
-				++t;
-				++lo;
-			} else if (t == hi) {
-			        if (t == TIME_T_MIN)
-			             return WRONG;
-				--t;
-				--hi;
-			}
-			if (lo > hi)
-				return WRONG;
-			if (dir > 0)
-				hi = t;
-			else	lo = t;
-			continue;
-		}
-		if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
-			break;
-		/*
-		** Right time, wrong type.
-		** Hunt for right time, right type.
-		** It's okay to guess wrong since the guess
-		** gets checked.
-		*/
-		/*
-		** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
-		*/
-#ifdef ALL_STATE
-		if (sp == NULL)
-			return WRONG;
-#endif /* defined ALL_STATE */
-		for (i = sp->typecnt - 1; i >= 0; --i) {
-			if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
-				continue;
-			for (j = sp->typecnt - 1; j >= 0; --j) {
-				if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
-					continue;
-				newt = t + sp->ttis[j].tt_gmtoff -
-					sp->ttis[i].tt_gmtoff;
-				if ((*funcp)(&newt, offset, &mytm, sp) == NULL)
-					continue;
-				if (tmcomp(&mytm, &yourtm) != 0)
-					continue;
-				if (mytm.tm_isdst != yourtm.tm_isdst)
-					continue;
-				/*
-				** We have a match.
-				*/
-				t = newt;
-				goto label;
-			}
-		}
-		return WRONG;
-	}
-label:
-	newt = t + saved_seconds;
-	if ((newt < t) != (saved_seconds < 0))
-		return WRONG;
-	t = newt;
-	if ((*funcp)(&t, offset, tmp, sp))
-		*okayp = TRUE;
-	return t;
-}
-
-static time_t
-time2(tmp, funcp, offset, okayp, sp)
-struct tm * const	tmp;
-struct tm * (* const	funcp) P((const time_t*, long, struct tm*,
-            const struct state* sp));
-const long		offset;
-int * const		okayp;
-const struct state *	sp;
-{
-	time_t	t;
-
-	/*
-	** First try without normalization of seconds
-	** (in case tm_sec contains a value associated with a leap second).
-	** If that fails, try with normalization of seconds.
-	*/
-	t = time2sub(tmp, funcp, offset, okayp, FALSE, sp);
-	return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, sp);
-}
-
-static time_t
-time1(tmp, funcp, offset, sp)
-struct tm * const	tmp;
-struct tm * (* const	funcp) P((const time_t *, long, struct tm *, const struct state* sp));
-const long		offset;
-const struct state *	sp;
-{
-	register time_t			t;
-	register int			samei, otheri;
-	register int			sameind, otherind;
-	register int			i;
-	register int			nseen;
-	int				seen[TZ_MAX_TYPES];
-	int				types[TZ_MAX_TYPES];
-	int				okay;
-
-	if (tmp->tm_isdst > 1)
-		tmp->tm_isdst = 1;
-	t = time2(tmp, funcp, offset, &okay, sp);
-#define PCTS 1
-#ifdef PCTS
-	/*
-	** PCTS code courtesy Grant Sullivan.
-	*/
-	if (okay)
-		return t;
-	if (tmp->tm_isdst < 0)
-		tmp->tm_isdst = 0;	/* reset to std and try again */
-#endif /* defined PCTS */
-#ifndef PCTS
-	if (okay || tmp->tm_isdst < 0)
-		return t;
-#endif /* !defined PCTS */
-	/*
-	** We're supposed to assume that somebody took a time of one type
-	** and did some math on it that yielded a "struct tm" that's bad.
-	** We try to divine the type they started from and adjust to the
-	** type they need.
-	*/
-	/*
-	** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
-	*/
-#ifdef ALL_STATE
-	if (sp == NULL)
-		return WRONG;
-#endif /* defined ALL_STATE */
-	for (i = 0; i < sp->typecnt; ++i)
-		seen[i] = FALSE;
-	nseen = 0;
-	for (i = sp->timecnt - 1; i >= 0; --i)
-		if (!seen[sp->types[i]]) {
-			seen[sp->types[i]] = TRUE;
-			types[nseen++] = sp->types[i];
-		}
-	for (sameind = 0; sameind < nseen; ++sameind) {
-		samei = types[sameind];
-		if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
-			continue;
-		for (otherind = 0; otherind < nseen; ++otherind) {
-			otheri = types[otherind];
-			if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
-				continue;
-			tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
-					sp->ttis[samei].tt_gmtoff;
-			tmp->tm_isdst = !tmp->tm_isdst;
-			t = time2(tmp, funcp, offset, &okay, sp);
-			if (okay)
-				return t;
-			tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
-					sp->ttis[samei].tt_gmtoff;
-			tmp->tm_isdst = !tmp->tm_isdst;
-		}
-	}
-	return WRONG;
-}
-
-// ============================================================================
-time_t
-mktime_tz(struct tm * const	tmp, char const * tz)
-{
-    struct state st;
-    if (tzload(tz, &st, TRUE) != 0) {
-        // not sure what's best here, but for now, we fall back to gmt
-        gmtload(&st);
-    }
-	return time1(tmp, localsub, 0L, &st);
-}
diff --git a/libcutils/zygote.c b/libcutils/zygote.c
index 75ce3ba..37236e8 100644
--- a/libcutils/zygote.c
+++ b/libcutils/zygote.c
@@ -159,44 +159,6 @@
 #endif /* HAVE_ANDROID_OS */
 }
 
-int zygote_run_wait(int argc, const char **argv, void (*post_run_func)(int))
-{
-    int fd;
-    int pid;
-    int err;
-    const char *newargv[argc + 1];
-
-    fd = socket_local_client(ZYGOTE_SOCKET, 
-            ANDROID_SOCKET_NAMESPACE_RESERVED, AF_LOCAL);
-
-    if (fd < 0) {
-        return -1;
-    }
-
-    // The command socket is passed to the peer as close-on-exec
-    // and will close when the peer dies
-    newargv[0] = "--peer-wait";
-    memcpy(newargv + 1, argv, argc * sizeof(*argv)); 
-
-    pid = send_request(fd, 1, argc + 1, newargv);
-
-    if (pid > 0 && post_run_func != NULL) {
-        post_run_func(pid);
-    }
-
-    // Wait for socket to close
-    do {
-        int dummy;
-        err = read(fd, &dummy, sizeof(dummy));
-    } while ((err < 0 && errno == EINTR) || err != 0);
-
-    do {
-        err = close(fd);
-    } while (err < 0 && errno == EINTR);
-
-    return 0;
-}
-
 /**
  * Spawns a new dalvik instance via the Zygote process. The non-zygote
  * arguments are passed to com.android.internal.os.RuntimeInit(). The
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index b91de52..3613d25 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -24,6 +24,8 @@
 #include <string.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 
 #include <cutils/logger.h>
 #include <cutils/logd.h>
@@ -37,7 +39,7 @@
 #define log_writev(filedes, vector, count) fakeLogWritev(filedes, vector, count)
 #define log_close(filedes) fakeLogClose(filedes)
 #else
-#define log_open(pathname, flags) open(pathname, flags)
+#define log_open(pathname, flags) open(pathname, (flags) | O_CLOEXEC)
 #define log_writev(filedes, vector, count) writev(filedes, vector, count)
 #define log_close(filedes) close(filedes)
 #endif
@@ -134,6 +136,7 @@
 {
     struct iovec vec[3];
     log_id_t log_id = LOG_ID_MAIN;
+    char tmp_tag[32];
 
     if (!tag)
         tag = "";
@@ -147,8 +150,12 @@
         !strcmp(tag, "STK") ||
         !strcmp(tag, "CDMA") ||
         !strcmp(tag, "PHONE") ||
-        !strcmp(tag, "SMS"))
+        !strcmp(tag, "SMS")) {
             log_id = LOG_ID_RADIO;
+            // Inform third party apps/ril/radio.. to use Rlog or RLOG
+            snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
+            tag = tmp_tag;
+    }
 
     vec[0].iov_base   = (unsigned char *) &prio;
     vec[0].iov_len    = 1;
@@ -163,12 +170,14 @@
 int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
 {
     struct iovec vec[3];
+    char tmp_tag[32];
 
     if (!tag)
         tag = "";
 
     /* XXX: This needs to go! */
-    if (!strcmp(tag, "HTC_RIL") ||
+    if ((bufID != LOG_ID_RADIO) &&
+         (!strcmp(tag, "HTC_RIL") ||
         !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
         !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
         !strcmp(tag, "AT") ||
@@ -176,8 +185,12 @@
         !strcmp(tag, "STK") ||
         !strcmp(tag, "CDMA") ||
         !strcmp(tag, "PHONE") ||
-        !strcmp(tag, "SMS"))
+        !strcmp(tag, "SMS"))) {
             bufID = LOG_ID_RADIO;
+            // Inform third party apps/ril/radio.. to use Rlog or RLOG
+            snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
+            tag = tmp_tag;
+    }
 
     vec[0].iov_base   = (unsigned char *) &prio;
     vec[0].iov_len    = 1;
diff --git a/libnetutils/Android.mk b/libnetutils/Android.mk
index 5f5849f..aba4621 100644
--- a/libnetutils/Android.mk
+++ b/libnetutils/Android.mk
@@ -9,7 +9,8 @@
         packet.c
 
 LOCAL_SHARED_LIBRARIES := \
-        libcutils
+        libcutils \
+        liblog
 
 LOCAL_MODULE:= libnetutils
 
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
index d0ca90a..da00f74 100644
--- a/libnetutils/dhcp_utils.c
+++ b/libnetutils/dhcp_utils.c
@@ -88,16 +88,17 @@
                      char *ipaddr,
                      char *gateway,
                      uint32_t *prefixLength,
-                     char *dns1,
-                     char *dns2,
+                     char *dns[],
                      char *server,
                      uint32_t *lease,
-                     char *vendorInfo)
+                     char *vendorInfo,
+                     char *domain)
 {
     char prop_name[PROPERTY_KEY_MAX];
     char prop_value[PROPERTY_VALUE_MAX];
     /* Interface name after converting p2p0-p2p0-X to p2p to reuse system properties */
     char p2p_interface[MAX_INTERFACE_LENGTH];
+    int x;
 
     get_p2p_interface_replacement(interface, p2p_interface);
 
@@ -111,7 +112,7 @@
     property_get(prop_name, server, NULL);
 
     //TODO: Handle IPv6 when we change system property usage
-    if (strcmp(gateway, "0.0.0.0") == 0) {
+    if (gateway[0] == '\0' || strncmp(gateway, "0.0.0.0", 7) == 0) {
         //DHCP server is our best bet as gateway
         strncpy(gateway, server, PROPERTY_VALUE_MAX);
     }
@@ -138,11 +139,11 @@
         }
         *prefixLength = p;
     }
-    snprintf(prop_name, sizeof(prop_name), "%s.%s.dns1", DHCP_PROP_NAME_PREFIX, p2p_interface);
-    property_get(prop_name, dns1, NULL);
 
-    snprintf(prop_name, sizeof(prop_name), "%s.%s.dns2", DHCP_PROP_NAME_PREFIX, p2p_interface);
-    property_get(prop_name, dns2, NULL);
+    for (x=0; dns[x] != NULL; x++) {
+        snprintf(prop_name, sizeof(prop_name), "%s.%s.dns%d", DHCP_PROP_NAME_PREFIX, p2p_interface, x+1);
+        property_get(prop_name, dns[x], NULL);
+    }
 
     snprintf(prop_name, sizeof(prop_name), "%s.%s.leasetime", DHCP_PROP_NAME_PREFIX, p2p_interface);
     if (property_get(prop_name, prop_value, NULL)) {
@@ -153,6 +154,10 @@
             p2p_interface);
     property_get(prop_name, vendorInfo, NULL);
 
+    snprintf(prop_name, sizeof(prop_name), "%s.%s.domain", DHCP_PROP_NAME_PREFIX,
+            p2p_interface);
+    property_get(prop_name, domain, NULL);
+
     return 0;
 }
 
@@ -177,11 +182,11 @@
                     char *ipaddr,
                     char *gateway,
                     uint32_t *prefixLength,
-                    char *dns1,
-                    char *dns2,
+                    char *dns[],
                     char *server,
                     uint32_t *lease,
-                    char *vendorInfo)
+                    char *vendorInfo,
+                    char *domain)
 {
     char result_prop_name[PROPERTY_KEY_MAX];
     char daemon_prop_name[PROPERTY_KEY_MAX];
@@ -211,7 +216,7 @@
                  p2p_interface, DHCP_CONFIG_PATH, prop_value, interface);
     else
         snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:-f %s %s", DAEMON_NAME,
-                 DHCP_CONFIG_PATH, p2p_interface, interface);
+                 p2p_interface, DHCP_CONFIG_PATH, 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) {
@@ -232,17 +237,10 @@
     }
     if (strcmp(prop_value, "ok") == 0) {
         char dns_prop_name[PROPERTY_KEY_MAX];
-        if (fill_ip_info(interface, ipaddr, gateway, prefixLength,
-                dns1, dns2, server, lease, vendorInfo) == -1) {
+        if (fill_ip_info(interface, ipaddr, gateway, prefixLength, dns,
+                server, lease, vendorInfo, domain) == -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);
-        property_set(dns_prop_name, *dns2 ? ipaddr_to_string(*dns2) : "");
         return 0;
     } else {
         snprintf(errmsg, sizeof(errmsg), "DHCP result was %s", prop_value);
@@ -327,11 +325,11 @@
                     char *ipaddr,
                     char *gateway,
                     uint32_t *prefixLength,
-                    char *dns1,
-                    char *dns2,
+                    char *dns[],
                     char *server,
                     uint32_t *lease,
-                    char *vendorInfo)
+                    char *vendorInfo,
+                    char *domain)
 {
     char result_prop_name[PROPERTY_KEY_MAX];
     char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
@@ -367,9 +365,8 @@
         return -1;
     }
     if (strcmp(prop_value, "ok") == 0) {
-        fill_ip_info(interface, ipaddr, gateway, prefixLength,
-                dns1, dns2, server, lease, vendorInfo);
-        return 0;
+        return fill_ip_info(interface, ipaddr, gateway, prefixLength, dns,
+                server, lease, vendorInfo, domain);
     } else {
         snprintf(errmsg, sizeof(errmsg), "DHCP Renew result was %s", prop_value);
         return -1;
diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index 488003f..7f20e5b 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -16,8 +16,8 @@
     codeflinger/blending.cpp \
     codeflinger/texturing.cpp \
     codeflinger/disassem.c \
-	tinyutils/SharedBuffer.cpp \
-	tinyutils/VectorImpl.cpp \
+	codeflinger/tinyutils/SharedBuffer.cpp \
+	codeflinger/tinyutils/VectorImpl.cpp \
 	fixed.cpp.arm \
 	picker.cpp.arm \
 	pixelflinger.cpp.arm \
@@ -50,14 +50,7 @@
 PIXELFLINGER_CFLAGS += -fstrict-aliasing -fomit-frame-pointer
 endif
 
-LOCAL_SHARED_LIBRARIES := libcutils
-
-ifneq ($(TARGET_ARCH),arm)
-# Required to define logging functions on the simulator.
-# TODO: move the simulator logging functions into libcutils with
-# the rest of the basic log stuff.
-LOCAL_SHARED_LIBRARIES += libutils
-endif
+LOCAL_SHARED_LIBRARIES := libcutils liblog
 
 #
 # Shared library
@@ -82,7 +75,7 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE:= libpixelflinger_static
 LOCAL_SRC_FILES := $(PIXELFLINGER_SRC_FILES)
-LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS) 
+LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS)
 include $(BUILD_STATIC_LIBRARY)
 
 
diff --git a/libpixelflinger/codeflinger/ARMAssembler.cpp b/libpixelflinger/codeflinger/ARMAssembler.cpp
index c4f42f5..607ed3c 100644
--- a/libpixelflinger/codeflinger/ARMAssembler.cpp
+++ b/libpixelflinger/codeflinger/ARMAssembler.cpp
@@ -28,9 +28,9 @@
 
 #include <private/pixelflinger/ggl_context.h>
 
-#include "codeflinger/ARMAssembler.h"
-#include "codeflinger/CodeCache.h"
-#include "codeflinger/disassem.h"
+#include "ARMAssembler.h"
+#include "CodeCache.h"
+#include "disassem.h"
 
 // ----------------------------------------------------------------------------
 
diff --git a/libpixelflinger/codeflinger/ARMAssembler.h b/libpixelflinger/codeflinger/ARMAssembler.h
index 06c66dd..c03dd9a 100644
--- a/libpixelflinger/codeflinger/ARMAssembler.h
+++ b/libpixelflinger/codeflinger/ARMAssembler.h
@@ -25,9 +25,8 @@
 #include "tinyutils/KeyedVector.h"
 #include "tinyutils/smartpointer.h"
 
-#include "tinyutils/smartpointer.h"
-#include "codeflinger/ARMAssemblerInterface.h"
-#include "codeflinger/CodeCache.h"
+#include "ARMAssemblerInterface.h"
+#include "CodeCache.h"
 
 namespace android {
 
diff --git a/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp b/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
index 82180ee..073633c 100644
--- a/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
+++ b/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
@@ -22,7 +22,7 @@
 #include <sys/types.h>
 
 #include <cutils/log.h>
-#include "codeflinger/ARMAssemblerInterface.h"
+#include "ARMAssemblerInterface.h"
 
 namespace android {
 
diff --git a/libpixelflinger/codeflinger/ARMAssemblerProxy.cpp b/libpixelflinger/codeflinger/ARMAssemblerProxy.cpp
index 7feed62..1c7bc76 100644
--- a/libpixelflinger/codeflinger/ARMAssemblerProxy.cpp
+++ b/libpixelflinger/codeflinger/ARMAssemblerProxy.cpp
@@ -19,7 +19,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include "codeflinger/ARMAssemblerProxy.h"
+#include "ARMAssemblerProxy.h"
 
 namespace android {
 
diff --git a/libpixelflinger/codeflinger/ARMAssemblerProxy.h b/libpixelflinger/codeflinger/ARMAssemblerProxy.h
index 5e3f763..70cb464 100644
--- a/libpixelflinger/codeflinger/ARMAssemblerProxy.h
+++ b/libpixelflinger/codeflinger/ARMAssemblerProxy.h
@@ -22,7 +22,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include "codeflinger/ARMAssemblerInterface.h"
+#include "ARMAssemblerInterface.h"
 
 namespace android {
 
diff --git a/libpixelflinger/codeflinger/CodeCache.cpp b/libpixelflinger/codeflinger/CodeCache.cpp
index f9ae00a..58fde7e 100644
--- a/libpixelflinger/codeflinger/CodeCache.cpp
+++ b/libpixelflinger/codeflinger/CodeCache.cpp
@@ -28,7 +28,7 @@
 #include <cutils/log.h>
 
 
-#include "codeflinger/CodeCache.h"
+#include "CodeCache.h"
 
 namespace android {
 
diff --git a/libpixelflinger/codeflinger/CodeCache.h b/libpixelflinger/codeflinger/CodeCache.h
index 54fd69b..fa67dd0 100644
--- a/libpixelflinger/codeflinger/CodeCache.h
+++ b/libpixelflinger/codeflinger/CodeCache.h
@@ -28,6 +28,8 @@
 
 namespace android {
 
+using namespace tinyutils;
+
 // ----------------------------------------------------------------------------
 
 class AssemblyKeyBase {
diff --git a/libpixelflinger/codeflinger/GGLAssembler.cpp b/libpixelflinger/codeflinger/GGLAssembler.cpp
index 1ddf93d..0cb042e 100644
--- a/libpixelflinger/codeflinger/GGLAssembler.cpp
+++ b/libpixelflinger/codeflinger/GGLAssembler.cpp
@@ -24,7 +24,7 @@
 #include <sys/types.h>
 #include <cutils/log.h>
 
-#include "codeflinger/GGLAssembler.h"
+#include "GGLAssembler.h"
 
 namespace android {
 
diff --git a/libpixelflinger/codeflinger/GGLAssembler.h b/libpixelflinger/codeflinger/GGLAssembler.h
index dd5f48e..d993684 100644
--- a/libpixelflinger/codeflinger/GGLAssembler.h
+++ b/libpixelflinger/codeflinger/GGLAssembler.h
@@ -24,7 +24,7 @@
 
 #include <private/pixelflinger/ggl_context.h>
 
-#include "codeflinger/ARMAssemblerProxy.h"
+#include "ARMAssemblerProxy.h"
 
 
 namespace android {
diff --git a/libpixelflinger/codeflinger/MIPSAssembler.cpp b/libpixelflinger/codeflinger/MIPSAssembler.cpp
index 7888a0e..a88d2fe 100644
--- a/libpixelflinger/codeflinger/MIPSAssembler.cpp
+++ b/libpixelflinger/codeflinger/MIPSAssembler.cpp
@@ -61,9 +61,9 @@
 
 #include <private/pixelflinger/ggl_context.h>
 
-#include "codeflinger/MIPSAssembler.h"
-#include "codeflinger/CodeCache.h"
-#include "codeflinger/mips_disassem.h"
+#include "MIPSAssembler.h"
+#include "CodeCache.h"
+#include "mips_disassem.h"
 
 // Choose MIPS arch variant following gcc flags
 #if defined(__mips__) && __mips==32 && __mips_isa_rev>=2
diff --git a/libpixelflinger/codeflinger/MIPSAssembler.h b/libpixelflinger/codeflinger/MIPSAssembler.h
index d8e8165..430ab06 100644
--- a/libpixelflinger/codeflinger/MIPSAssembler.h
+++ b/libpixelflinger/codeflinger/MIPSAssembler.h
@@ -21,12 +21,12 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <utils/Vector.h>
-#include <utils/KeyedVector.h>
-
+#include "tinyutils/KeyedVector.h"
+#include "tinyutils/Vector.h"
 #include "tinyutils/smartpointer.h"
-#include "codeflinger/ARMAssemblerInterface.h"
-#include "codeflinger/CodeCache.h"
+
+#include "ARMAssemblerInterface.h"
+#include "CodeCache.h"
 
 namespace android {
 
diff --git a/libpixelflinger/codeflinger/blending.cpp b/libpixelflinger/codeflinger/blending.cpp
index c90eaa0..b20219c 100644
--- a/libpixelflinger/codeflinger/blending.cpp
+++ b/libpixelflinger/codeflinger/blending.cpp
@@ -23,7 +23,7 @@
 
 #include <cutils/log.h>
 
-#include "codeflinger/GGLAssembler.h"
+#include "GGLAssembler.h"
 
 
 namespace android {
diff --git a/libpixelflinger/codeflinger/load_store.cpp b/libpixelflinger/codeflinger/load_store.cpp
index 146fa52..0a46eaa 100644
--- a/libpixelflinger/codeflinger/load_store.cpp
+++ b/libpixelflinger/codeflinger/load_store.cpp
@@ -18,7 +18,7 @@
 #include <assert.h>
 #include <stdio.h>
 #include <cutils/log.h>
-#include "codeflinger/GGLAssembler.h"
+#include "GGLAssembler.h"
 
 #ifdef __ARM_ARCH__
 #include <machine/cpu-features.h>
diff --git a/libpixelflinger/codeflinger/texturing.cpp b/libpixelflinger/codeflinger/texturing.cpp
index 4d5a50f..9e3d217 100644
--- a/libpixelflinger/codeflinger/texturing.cpp
+++ b/libpixelflinger/codeflinger/texturing.cpp
@@ -23,7 +23,7 @@
 
 #include <cutils/log.h>
 
-#include "codeflinger/GGLAssembler.h"
+#include "GGLAssembler.h"
 
 #ifdef __ARM_ARCH__
 #include <machine/cpu-features.h>
diff --git a/libpixelflinger/tinyutils/Errors.h b/libpixelflinger/codeflinger/tinyutils/Errors.h
similarity index 60%
rename from libpixelflinger/tinyutils/Errors.h
rename to libpixelflinger/codeflinger/tinyutils/Errors.h
index b9fd5f4..47ae9d7 100644
--- a/libpixelflinger/tinyutils/Errors.h
+++ b/libpixelflinger/codeflinger/tinyutils/Errors.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright 2007 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.
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_ERRORS_H
-#define ANDROID_ERRORS_H
+#ifndef ANDROID_PIXELFLINGER_ERRORS_H
+#define ANDROID_PIXELFLINGER_ERRORS_H
 
 #include <sys/types.h>
 #include <errno.h>
 
 namespace android {
+namespace tinyutils {
 
 // use this type to return error codes
 typedef int32_t     status_t;
@@ -31,32 +32,17 @@
  */
 
 enum {
-    OK                = 0,    // Everything's swell.
     NO_ERROR          = 0,    // No errors.
-    
-    UNKNOWN_ERROR       = 0x80000000,
-
     NO_MEMORY           = -ENOMEM,
-    INVALID_OPERATION   = -ENOSYS,
     BAD_VALUE           = -EINVAL,
-    BAD_TYPE            = 0x80000001,
-    NAME_NOT_FOUND      = -ENOENT,
-    PERMISSION_DENIED   = -EPERM,
-    NO_INIT             = -ENODEV,
-    ALREADY_EXISTS      = -EEXIST,
-    DEAD_OBJECT         = -EPIPE,
-    FAILED_TRANSACTION  = 0x80000002,
-    JPARKS_BROKE_IT     = -EPIPE,
     BAD_INDEX           = -EOVERFLOW,
-    NOT_ENOUGH_DATA     = -ENODATA,
-    WOULD_BLOCK         = -EWOULDBLOCK, 
-    TIMED_OUT           = -ETIME,
-    UNKNOWN_TRANSACTION = -EBADMSG,
+    NAME_NOT_FOUND      = -ENOENT,
 };
 
 
-}; // namespace android
+} // namespace tinyutils
+} // namespace android
     
 // ---------------------------------------------------------------------------
     
-#endif // ANDROID_ERRORS_H
+#endif // ANDROID_PIXELFLINGER_ERRORS_H
diff --git a/libpixelflinger/tinyutils/KeyedVector.h b/libpixelflinger/codeflinger/tinyutils/KeyedVector.h
similarity index 85%
rename from libpixelflinger/tinyutils/KeyedVector.h
rename to libpixelflinger/codeflinger/tinyutils/KeyedVector.h
index 1be2094..9d8668b 100644
--- a/libpixelflinger/tinyutils/KeyedVector.h
+++ b/libpixelflinger/codeflinger/tinyutils/KeyedVector.h
@@ -1,25 +1,34 @@
 /*
- *  keyed_vector.h
- *  Android  
+ * Copyright 2005 The Android Open Source Project
  *
- *  Created on 11/18/05.
- *  Copyright 2005 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_KEYED_VECTOR_H
-#define ANDROID_KEYED_VECTOR_H
+#ifndef ANDROID_PIXELFLINGER_KEYED_VECTOR_H
+#define ANDROID_PIXELFLINGER_KEYED_VECTOR_H
 
 #include <assert.h>
 #include <stdint.h>
 #include <sys/types.h>
 
-#include "tinyutils/SortedVector.h"
-#include "tinyutils/TypeHelpers.h"
+#include "Errors.h"
+#include "SortedVector.h"
+#include "TypeHelpers.h"
 
 // ---------------------------------------------------------------------------
 
 namespace android {
+namespace tinyutils {
 
 template <typename KEY, typename VALUE>
 class KeyedVector
@@ -186,8 +195,9 @@
     return i >= 0 ? KeyedVector<KEY,VALUE>::valueAt(i) : mDefault;
 }
 
-}; // namespace android
+} // namespace tinyutils
+} // namespace android
 
 // ---------------------------------------------------------------------------
 
-#endif // ANDROID_KEYED_VECTOR_H
+#endif // ANDROID_PIXELFLINGER_KEYED_VECTOR_H
diff --git a/libpixelflinger/tinyutils/SharedBuffer.cpp b/libpixelflinger/codeflinger/tinyutils/SharedBuffer.cpp
similarity index 75%
rename from libpixelflinger/tinyutils/SharedBuffer.cpp
rename to libpixelflinger/codeflinger/tinyutils/SharedBuffer.cpp
index ef781a7..ef453fa 100644
--- a/libpixelflinger/tinyutils/SharedBuffer.cpp
+++ b/libpixelflinger/codeflinger/tinyutils/SharedBuffer.cpp
@@ -1,9 +1,17 @@
 /*
- *  SharedBuffer.cpp
- *  Android  
+ * Copyright 2005 The Android Open Source Project
  *
- *  Copyright 2005 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 <stdlib.h>
@@ -11,11 +19,12 @@
 
 #include <cutils/atomic.h>
 
-#include "tinyutils/SharedBuffer.h"
+#include "SharedBuffer.h"
 
 // ---------------------------------------------------------------------------
 
 namespace android {
+namespace tinyutils {
 
 SharedBuffer* SharedBuffer::alloc(size_t size)
 {
@@ -102,5 +111,5 @@
     return prev;
 }
 
-
-}; // namespace android
+} // namespace tinyutils
+} // namespace android
diff --git a/libpixelflinger/tinyutils/SharedBuffer.h b/libpixelflinger/codeflinger/tinyutils/SharedBuffer.h
similarity index 82%
rename from libpixelflinger/tinyutils/SharedBuffer.h
rename to libpixelflinger/codeflinger/tinyutils/SharedBuffer.h
index 9f63121..d69b417 100644
--- a/libpixelflinger/tinyutils/SharedBuffer.h
+++ b/libpixelflinger/codeflinger/tinyutils/SharedBuffer.h
@@ -1,13 +1,21 @@
 /*
- *  SharedBuffer.h
- *  Android  
+ * Copyright 2005 The Android Open Source Project
  *
- *  Copyright 2005 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_SHARED_BUFFER_H
-#define ANDROID_SHARED_BUFFER_H
+#ifndef ANDROID_PIXELFLINGER_SHARED_BUFFER_H
+#define ANDROID_PIXELFLINGER_SHARED_BUFFER_H
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -15,6 +23,7 @@
 // ---------------------------------------------------------------------------
 
 namespace android {
+namespace tinyutils {
 
 class SharedBuffer
 {
@@ -131,8 +140,9 @@
     return (mRefs == 1);
 }
 
-}; // namespace android
+} // namespace tinyutils
+} // namespace android
 
 // ---------------------------------------------------------------------------
 
-#endif // ANDROID_VECTOR_H
+#endif // ANDROID_PIXELFLINGER_SHARED_BUFFER_H
diff --git a/libpixelflinger/tinyutils/SortedVector.h b/libpixelflinger/codeflinger/tinyutils/SortedVector.h
similarity index 96%
rename from libpixelflinger/tinyutils/SortedVector.h
rename to libpixelflinger/codeflinger/tinyutils/SortedVector.h
index 7a6b443..a2b7005 100644
--- a/libpixelflinger/tinyutils/SortedVector.h
+++ b/libpixelflinger/codeflinger/tinyutils/SortedVector.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005 The Android Open Source Project
+ * Copyright 2005 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.
@@ -14,20 +14,21 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_SORTED_VECTOR_H
-#define ANDROID_SORTED_VECTOR_H
+#ifndef ANDROID_PIXELFLINGER_SORTED_VECTOR_H
+#define ANDROID_PIXELFLINGER_SORTED_VECTOR_H
 
 #include <assert.h>
 #include <stdint.h>
 #include <sys/types.h>
 
-#include "tinyutils/Vector.h"
-#include "tinyutils/VectorImpl.h"
-#include "tinyutils/TypeHelpers.h"
+#include "Vector.h"
+#include "VectorImpl.h"
+#include "TypeHelpers.h"
 
 // ---------------------------------------------------------------------------
 
 namespace android {
+namespace tinyutils {
 
 template <class TYPE>
 class SortedVector : private SortedVectorImpl
@@ -274,9 +275,10 @@
     return compare_type( *reinterpret_cast<const TYPE*>(lhs), *reinterpret_cast<const TYPE*>(rhs) );
 }
 
-}; // namespace android
+} // namespace tinyutils
+} // namespace android
 
 
 // ---------------------------------------------------------------------------
 
-#endif // ANDROID_SORTED_VECTOR_H
+#endif // ANDROID_PIXELFLINGER_SORTED_VECTOR_H
diff --git a/libpixelflinger/tinyutils/TypeHelpers.h b/libpixelflinger/codeflinger/tinyutils/TypeHelpers.h
similarity index 89%
rename from libpixelflinger/tinyutils/TypeHelpers.h
rename to libpixelflinger/codeflinger/tinyutils/TypeHelpers.h
index 9500c90..7abff07 100644
--- a/libpixelflinger/tinyutils/TypeHelpers.h
+++ b/libpixelflinger/codeflinger/tinyutils/TypeHelpers.h
@@ -1,12 +1,21 @@
 /*
- *  TypeHelpers.h
- *  
- *  Copyright 2005 The Android Open Source Project
+ * Copyright 2005 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_TYPE_HELPERS_H
-#define ANDROID_TYPE_HELPERS_H
+#ifndef ANDROID_PIXELFLINGER_TYPE_HELPERS_H
+#define ANDROID_PIXELFLINGER_TYPE_HELPERS_H
 
 #include <new>
 #include <stdint.h>
@@ -16,6 +25,7 @@
 // ---------------------------------------------------------------------------
 
 namespace android {
+namespace tinyutils {
 
 /*
  * Types traits
@@ -238,8 +248,9 @@
 
 // ---------------------------------------------------------------------------
 
-}; // namespace android
+} // namespace tinyutils
+} // namespace android
 
 // ---------------------------------------------------------------------------
 
-#endif // ANDROID_TYPE_HELPERS_H
+#endif // ANDROID_PIXELFLINGER_TYPE_HELPERS_H
diff --git a/libpixelflinger/tinyutils/Vector.h b/libpixelflinger/codeflinger/tinyutils/Vector.h
similarity index 92%
rename from libpixelflinger/tinyutils/Vector.h
rename to libpixelflinger/codeflinger/tinyutils/Vector.h
index 14cf99a..c07a17a 100644
--- a/libpixelflinger/tinyutils/Vector.h
+++ b/libpixelflinger/codeflinger/tinyutils/Vector.h
@@ -1,13 +1,21 @@
 /*
- *  vector.h
- *  Android  
+ * Copyright 2005 The Android Open Source Project
  *
- *  Copyright 2005 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_VECTOR_H
-#define ANDROID_VECTOR_H
+#ifndef ANDROID_PIXELFLINGER_VECTOR_H
+#define ANDROID_PIXELFLINGER_VECTOR_H
 
 #include <new>
 #include <stdint.h>
@@ -15,13 +23,14 @@
 
 #include <cutils/log.h>
 
-#include "tinyutils/Errors.h"
-#include "tinyutils/VectorImpl.h"
-#include "tinyutils/TypeHelpers.h"
+#include "Errors.h"
+#include "VectorImpl.h"
+#include "TypeHelpers.h"
 
 // ---------------------------------------------------------------------------
 
 namespace android {
+namespace tinyutils {
 
 /*!
  * The main templated vector class ensuring type safety
@@ -335,9 +344,10 @@
     move_backward_type( reinterpret_cast<TYPE*>(dest), reinterpret_cast<const TYPE*>(from), num );
 }
 
-}; // namespace android
+} // namespace tinyutils
+} // namespace android
 
 
 // ---------------------------------------------------------------------------
 
-#endif // ANDROID_VECTOR_H
+#endif // ANDROID_PIXELFLINGER_VECTOR_H
diff --git a/libpixelflinger/tinyutils/VectorImpl.cpp b/libpixelflinger/codeflinger/tinyutils/VectorImpl.cpp
similarity index 94%
rename from libpixelflinger/tinyutils/VectorImpl.cpp
rename to libpixelflinger/codeflinger/tinyutils/VectorImpl.cpp
index 05c4945..689129a 100644
--- a/libpixelflinger/tinyutils/VectorImpl.cpp
+++ b/libpixelflinger/codeflinger/tinyutils/VectorImpl.cpp
@@ -1,9 +1,17 @@
 /*
- *  vector_impl.cpp
- *  Android  
+ * Copyright 2005 The Android Open Source Project
  *
- *  Copyright 2005 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 "Vector"
@@ -15,21 +23,15 @@
 
 #include <cutils/log.h>
 
-#include "tinyutils/SharedBuffer.h"
-#include "tinyutils/VectorImpl.h"
+#include "Errors.h"
+#include "SharedBuffer.h"
+#include "VectorImpl.h"
 
 /*****************************************************************************/
 
 
 namespace android {
-
-enum {
-    NO_ERROR          = 0,    // No errors.
-    NO_MEMORY           = -ENOMEM,
-    BAD_VALUE           = -EINVAL,
-    BAD_INDEX           = -EOVERFLOW,
-    NAME_NOT_FOUND      = -ENOENT,
-};
+namespace tinyutils {
 
 // ----------------------------------------------------------------------------
 
@@ -548,5 +550,6 @@
 
 /*****************************************************************************/
 
-}; // namespace android
+} // namespace tinyutils
+} // namespace android
 
diff --git a/libpixelflinger/tinyutils/VectorImpl.h b/libpixelflinger/codeflinger/tinyutils/VectorImpl.h
similarity index 89%
rename from libpixelflinger/tinyutils/VectorImpl.h
rename to libpixelflinger/codeflinger/tinyutils/VectorImpl.h
index e868eca..56089b3 100644
--- a/libpixelflinger/tinyutils/VectorImpl.h
+++ b/libpixelflinger/codeflinger/tinyutils/VectorImpl.h
@@ -1,13 +1,21 @@
 /*
- *  vector_impl.h
- *  Android  
+ * Copyright 2005 The Android Open Source Project
  *
- *  Copyright 2005 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_VECTOR_IMPL_H
-#define ANDROID_VECTOR_IMPL_H
+#ifndef ANDROID_PIXELFLINGER_VECTOR_IMPL_H
+#define ANDROID_PIXELFLINGER_VECTOR_IMPL_H
 
 #include <assert.h>
 #include <stdint.h>
@@ -18,6 +26,7 @@
 // ---------------------------------------------------------------------------
 
 namespace android {
+namespace tinyutils {
 
 /*!
  * Implementation of the guts of the vector<> class
@@ -177,9 +186,10 @@
             ssize_t         replaceAt(const void* item, size_t index);
 };
 
-}; // namespace android
+} // namespace tinyutils
+} // namespace android
 
 
 // ---------------------------------------------------------------------------
 
-#endif // ANDROID_VECTOR_IMPL_H
+#endif // ANDROID_PIXELFLINGER_VECTOR_IMPL_H
diff --git a/libpixelflinger/tinyutils/smartpointer.h b/libpixelflinger/codeflinger/tinyutils/smartpointer.h
similarity index 82%
rename from libpixelflinger/tinyutils/smartpointer.h
rename to libpixelflinger/codeflinger/tinyutils/smartpointer.h
index 88032d7..9d0a16e 100644
--- a/libpixelflinger/tinyutils/smartpointer.h
+++ b/libpixelflinger/codeflinger/tinyutils/smartpointer.h
@@ -1,13 +1,21 @@
 /*
- *  smartpointer.h
- *  Android  
+ * Copyright 2005 The Android Open Source Project
  *
- *  Copyright 2005 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_SMART_POINTER_H
-#define ANDROID_SMART_POINTER_H
+#ifndef ANDROID_PIXELFLINGER_SMART_POINTER_H
+#define ANDROID_PIXELFLINGER_SMART_POINTER_H
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -15,6 +23,7 @@
 
 // ---------------------------------------------------------------------------
 namespace android {
+namespace tinyutils {
 
 // ---------------------------------------------------------------------------
 
@@ -163,8 +172,9 @@
 
 // ---------------------------------------------------------------------------
 
-}; // namespace android
+} // namespace tinyutils
+} // namespace android
 
 // ---------------------------------------------------------------------------
 
-#endif // ANDROID_SMART_POINTER_H
+#endif // ANDROID_PIXELFLINGER_SMART_POINTER_H
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
index b5ae419..5014e4a 100644
--- a/libsparse/output_file.c
+++ b/libsparse/output_file.c
@@ -675,6 +675,9 @@
 	} else {
 		out = output_file_new_normal();
 	}
+	if (!out) {
+		return NULL;
+	}
 
 	out->ops->open(out, fd);
 
diff --git a/libsuspend/Android.mk b/libsuspend/Android.mk
index 45cb701..a2fa3e0 100644
--- a/libsuspend/Android.mk
+++ b/libsuspend/Android.mk
@@ -12,7 +12,6 @@
 	liblog libcutils
 
 include $(CLEAR_VARS)
-
 LOCAL_SRC_FILES := $(libsuspend_src_files)
 LOCAL_MODULE := libsuspend
 LOCAL_MODULE_TAGS := optional
@@ -21,3 +20,12 @@
 LOCAL_SHARED_LIBRARIES := $(libsuspend_libraries)
 #LOCAL_CFLAGS += -DLOG_NDEBUG=0
 include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(libsuspend_src_files)
+LOCAL_MODULE := libsuspend
+LOCAL_MODULE_TAGS := optional
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
+#LOCAL_CFLAGS += -DLOG_NDEBUG=0
+include $(BUILD_STATIC_LIBRARY)
diff --git a/libsysutils/Android.mk b/libsysutils/Android.mk
index 57cc313..1d396b2 100644
--- a/libsysutils/Android.mk
+++ b/libsysutils/Android.mk
@@ -16,11 +16,11 @@
 
 LOCAL_MODULE:= libsysutils
 
-LOCAL_C_INCLUDES := $(KERNEL_HEADERS) 
+LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
 
-LOCAL_CFLAGS := 
+LOCAL_CFLAGS :=
 
-LOCAL_SHARED_LIBRARIES := libcutils
+LOCAL_SHARED_LIBRARIES := libcutils liblog
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index 6731cf1..02a401d 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -25,6 +25,8 @@
 #include <sysutils/FrameworkCommand.h>
 #include <sysutils/SocketClient.h>
 
+static const int CMD_BUF_SIZE = 1024;
+
 FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :
                             SocketListener(socketName, true, withSeq) {
     init(socketName, withSeq);
@@ -43,7 +45,7 @@
 }
 
 bool FrameworkListener::onDataAvailable(SocketClient *c) {
-    char buffer[255];
+    char buffer[CMD_BUF_SIZE];
     int len;
 
     len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));
@@ -52,6 +54,8 @@
         return false;
     } else if (!len)
         return false;
+   if(buffer[len-1] != '\0')
+        SLOGW("String is not zero-terminated");
 
     int offset = 0;
     int i;
@@ -63,6 +67,7 @@
             offset = i + 1;
         }
     }
+
     return true;
 }
 
@@ -74,7 +79,7 @@
     FrameworkCommandCollection::iterator i;
     int argc = 0;
     char *argv[FrameworkListener::CMD_ARGS_MAX];
-    char tmp[255];
+    char tmp[CMD_BUF_SIZE];
     char *p = data;
     char *q = tmp;
     char *qlimit = tmp + sizeof(tmp) - 1;
@@ -180,7 +185,6 @@
             goto out;
         }
     }
-
     cli->sendMsg(500, "Command not recognized", false);
 out:
     int j;
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index 3d4984d..ae0e077 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -112,6 +112,12 @@
     char *result = (char *)malloc(len * 2 + 3);
     char *current = result;
     const char *end = arg + len;
+    char *oldresult;
+
+    if(result == NULL) {
+        SLOGW("malloc error (%s)", strerror(errno));
+        return NULL;
+    }
 
     *(current++) = '"';
     while (arg < end) {
@@ -125,8 +131,9 @@
     }
     *(current++) = '"';
     *(current++) = '\0';
+    oldresult = result; // save pointer in case realloc fails
     result = (char *)realloc(result, current-result);
-    return result;
+    return result ? result : oldresult;
 }
 
 
diff --git a/libusbhost/Android.mk b/libusbhost/Android.mk
index 52b4ead..9565cc5 100644
--- a/libusbhost/Android.mk
+++ b/libusbhost/Android.mk
@@ -44,3 +44,13 @@
 LOCAL_SHARED_LIBRARIES := libcutils
 
 include $(BUILD_SHARED_LIBRARY)
+
+# Static library for target
+# ========================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libusbhost
+LOCAL_SRC_FILES := usbhost.c
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index c059b89..8be393e 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -33,6 +33,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
+#include <stddef.h>
 
 #include <sys/ioctl.h>
 #include <sys/types.h>
@@ -50,16 +51,25 @@
 #include "usbhost/usbhost.h"
 
 #define DEV_DIR             "/dev"
-#define USB_FS_DIR          "/dev/bus/usb"
-#define USB_FS_ID_SCANNER   "/dev/bus/usb/%d/%d"
-#define USB_FS_ID_FORMAT    "/dev/bus/usb/%03d/%03d"
+#define DEV_BUS_DIR         DEV_DIR "/bus"
+#define USB_FS_DIR          DEV_BUS_DIR "/usb"
+#define USB_FS_ID_SCANNER   USB_FS_DIR "/%d/%d"
+#define USB_FS_ID_FORMAT    USB_FS_DIR "/%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
 
+#define MAX_USBFS_WD_COUNT      10
+
 struct usb_host_context {
-    int fd;
+    int                         fd;
+    usb_device_added_cb         cb_added;
+    usb_device_removed_cb       cb_removed;
+    void                        *data;
+    int                         wds[MAX_USBFS_WD_COUNT];
+    int                         wdd;
+    int                         wddbus;
 };
 
 struct usb_device {
@@ -116,10 +126,10 @@
     while ((de = readdir(busdir)) != 0 && !done) {
         if(badname(de->d_name)) continue;
 
-        snprintf(busname, sizeof(busname), "%s/%s", USB_FS_DIR, de->d_name);
+        snprintf(busname, sizeof(busname), USB_FS_DIR "/%s", de->d_name);
         done = find_existing_devices_bus(busname, added_cb,
                                          client_data);
-    }
+    } //end of busdir while
     closedir(busdir);
 
     return done;
@@ -137,7 +147,7 @@
 
     /* watch existing subdirectories of USB_FS_DIR */
     for (i = 1; i < wd_count; i++) {
-        snprintf(path, sizeof(path), "%s/%03d", USB_FS_DIR, i);
+        snprintf(path, sizeof(path), USB_FS_DIR "/%03d", i);
         ret = inotify_add_watch(context->fd, path, IN_CREATE | IN_DELETE);
         if (ret >= 0)
             wds[i] = ret;
@@ -166,93 +176,142 @@
     free(context);
 }
 
-void usb_host_run(struct usb_host_context *context,
+int usb_host_get_fd(struct usb_host_context *context)
+{
+    return context->fd;
+} /* usb_host_get_fd() */
+
+int usb_host_load(struct usb_host_context *context,
                   usb_device_added_cb added_cb,
                   usb_device_removed_cb removed_cb,
                   usb_discovery_done_cb discovery_done_cb,
                   void *client_data)
 {
-    struct inotify_event* event;
-    char event_buf[512];
-    char path[100];
-    int i, ret, done = 0;
-    int wd, wdd, wds[10];
-    int wd_count = sizeof(wds) / sizeof(wds[0]);
+    int done = 0;
+    int i;
+
+    context->cb_added = added_cb;
+    context->cb_removed = removed_cb;
+    context->data = client_data;
 
     D("Created device discovery thread\n");
 
     /* watch for files added and deleted within USB_FS_DIR */
-    for (i = 0; i < wd_count; i++)
-        wds[i] = -1;
+    context->wddbus = -1;
+    for (i = 0; i < MAX_USBFS_WD_COUNT; i++)
+        context->wds[i] = -1;
 
     /* watch the root for new subdirectories */
-    wdd = inotify_add_watch(context->fd, DEV_DIR, IN_CREATE | IN_DELETE);
-    if (wdd < 0) {
+    context->wdd = inotify_add_watch(context->fd, DEV_DIR, IN_CREATE | IN_DELETE);
+    if (context->wdd < 0) {
         fprintf(stderr, "inotify_add_watch failed\n");
         if (discovery_done_cb)
             discovery_done_cb(client_data);
-        return;
+        return done;
     }
 
-    watch_existing_subdirs(context, wds, wd_count);
+    watch_existing_subdirs(context, context->wds, MAX_USBFS_WD_COUNT);
 
     /* check for existing devices first, after we have inotify set up */
     done = find_existing_devices(added_cb, client_data);
     if (discovery_done_cb)
         done |= discovery_done_cb(client_data);
 
-    while (!done) {
-        ret = read(context->fd, event_buf, sizeof(event_buf));
-        if (ret >= (int)sizeof(struct inotify_event)) {
-            event = (struct inotify_event *)event_buf;
+    return done;
+} /* usb_host_load() */
+
+int usb_host_read_event(struct usb_host_context *context)
+{
+    struct inotify_event* event;
+    char event_buf[512];
+    char path[100];
+    int i, ret, done = 0;
+    int offset = 0;
+    int wd;
+
+    ret = read(context->fd, event_buf, sizeof(event_buf));
+    if (ret >= (int)sizeof(struct inotify_event)) {
+        while (offset < ret && !done) {
+            event = (struct inotify_event*)&event_buf[offset];
+            done = 0;
             wd = event->wd;
-            if (wd == wdd) {
+            if (wd == context->wdd) {
                 if ((event->mask & IN_CREATE) && !strcmp(event->name, "bus")) {
-                    watch_existing_subdirs(context, wds, wd_count);
-                    done = find_existing_devices(added_cb, client_data);
-                } else if ((event->mask & IN_DELETE) && !strcmp(event->name, "bus")) {
-                    for (i = 0; i < wd_count; i++) {
-                        if (wds[i] >= 0) {
-                            inotify_rm_watch(context->fd, wds[i]);
-                            wds[i] = -1;
+                    context->wddbus = inotify_add_watch(context->fd, DEV_BUS_DIR, IN_CREATE | IN_DELETE);
+                    if (context->wddbus < 0) {
+                        done = 1;
+                    } else {
+                        watch_existing_subdirs(context, context->wds, MAX_USBFS_WD_COUNT);
+                        done = find_existing_devices(context->cb_added, context->data);
+                    }
+                }
+            } else if (wd == context->wddbus) {
+                if ((event->mask & IN_CREATE) && !strcmp(event->name, "usb")) {
+                    watch_existing_subdirs(context, context->wds, MAX_USBFS_WD_COUNT);
+                    done = find_existing_devices(context->cb_added, context->data);
+                } else if ((event->mask & IN_DELETE) && !strcmp(event->name, "usb")) {
+                    for (i = 0; i < MAX_USBFS_WD_COUNT; i++) {
+                        if (context->wds[i] >= 0) {
+                            inotify_rm_watch(context->fd, context->wds[i]);
+                            context->wds[i] = -1;
                         }
                     }
                 }
-            } else if (wd == wds[0]) {
+            } else if (wd == context->wds[0]) {
                 i = atoi(event->name);
-                snprintf(path, sizeof(path), "%s/%s", USB_FS_DIR, event->name);
+                snprintf(path, sizeof(path), USB_FS_DIR "/%s", event->name);
                 D("%s subdirectory %s: index: %d\n", (event->mask & IN_CREATE) ?
-                                                     "new" : "gone", path, i);
-                if (i > 0 && i < wd_count) {
+                        "new" : "gone", path, i);
+                if (i > 0 && i < MAX_USBFS_WD_COUNT) {
                     if (event->mask & IN_CREATE) {
                         ret = inotify_add_watch(context->fd, path,
-                                                IN_CREATE | IN_DELETE);
+                                IN_CREATE | IN_DELETE);
                         if (ret >= 0)
-                            wds[i] = ret;
-                        done = find_existing_devices_bus(path, added_cb,
-                                                         client_data);
+                            context->wds[i] = ret;
+                        done = find_existing_devices_bus(path, context->cb_added,
+                                context->data);
                     } else if (event->mask & IN_DELETE) {
-                        inotify_rm_watch(context->fd, wds[i]);
-                        wds[i] = -1;
+                        inotify_rm_watch(context->fd, context->wds[i]);
+                        context->wds[i] = -1;
                     }
                 }
             } else {
-                for (i = 1; i < wd_count && !done; i++) {
-                    if (wd == wds[i]) {
-                        snprintf(path, sizeof(path), "%s/%03d/%s", USB_FS_DIR, i, event->name);
+                for (i = 1; (i < MAX_USBFS_WD_COUNT) && !done; i++) {
+                    if (wd == context->wds[i]) {
+                        snprintf(path, sizeof(path), USB_FS_DIR "/%03d/%s", i, event->name);
                         if (event->mask == IN_CREATE) {
                             D("new device %s\n", path);
-                            done = added_cb(path, client_data);
+                            done = context->cb_added(path, context->data);
                         } else if (event->mask == IN_DELETE) {
                             D("gone device %s\n", path);
-                            done = removed_cb(path, client_data);
+                            done = context->cb_removed(path, context->data);
                         }
                     }
                 }
             }
+
+            offset += sizeof(struct inotify_event) + event->len;
         }
     }
-}
+
+    return done;
+} /* usb_host_read_event() */
+
+void usb_host_run(struct usb_host_context *context,
+                  usb_device_added_cb added_cb,
+                  usb_device_removed_cb removed_cb,
+                  usb_discovery_done_cb discovery_done_cb,
+                  void *client_data)
+{
+    int done;
+
+    done = usb_host_load(context, added_cb, removed_cb, discovery_done_cb, client_data);
+
+    while (!done) {
+
+        done = usb_host_read_event(context);
+    }
+} /* usb_host_run() */
 
 struct usb_device *usb_device_open(const char *dev_name)
 {
@@ -606,7 +665,6 @@
 {
     struct usbdevfs_urb *urb = NULL;
     struct usb_request *req = NULL;
-    int res;
 
     while (1) {
         int res = ioctl(dev->fd, USBDEVFS_REAPURB, &urb);
diff --git a/logwrapper/Android.mk b/logwrapper/Android.mk
index 5fd6356..917bf37 100644
--- a/logwrapper/Android.mk
+++ b/logwrapper/Android.mk
@@ -1,7 +1,34 @@
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
+
+# ========================================================
+# Static library
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := liblogwrap
+LOCAL_SRC_FILES := logwrap.c
+LOCAL_SHARED_LIBRARIES := libcutils liblog
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+include $(BUILD_STATIC_LIBRARY)
+
+# ========================================================
+# Shared library
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := liblogwrap
+LOCAL_SHARED_LIBRARIES := libcutils liblog
+LOCAL_WHOLE_STATIC_LIBRARIES := liblogwrap
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+include $(BUILD_SHARED_LIBRARY)
+
+# ========================================================
+# Executable
+# ========================================================
+include $(CLEAR_VARS)
 LOCAL_SRC_FILES:= logwrapper.c
 LOCAL_MODULE := logwrapper
-LOCAL_STATIC_LIBRARIES := liblog
+LOCAL_STATIC_LIBRARIES := liblog liblogwrap libcutils
 include $(BUILD_EXECUTABLE)
diff --git a/logwrapper/include/logwrap/logwrap.h b/logwrapper/include/logwrap/logwrap.h
new file mode 100644
index 0000000..8087f0a
--- /dev/null
+++ b/logwrapper/include/logwrap/logwrap.h
@@ -0,0 +1,83 @@
+/* system/core/include/logwrap/logwrap.h
+ *
+ * Copyright 2013, 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 __LIBS_LOGWRAP_H
+#define __LIBS_LOGWRAP_H
+
+#include <stdbool.h>
+
+__BEGIN_DECLS
+
+/*
+ * Run a command while logging its stdout and stderr
+ *
+ * WARNING: while this function is running it will clear all SIGCHLD handlers
+ * if you rely on SIGCHLD in the caller there is a chance zombies will be
+ * created if you're not calling waitpid after calling this. This function will
+ * log a warning when it clears SIGCHLD for processes other than the child it
+ * created.
+ *
+ * Arguments:
+ *   argc:   the number of elements in argv
+ *   argv:   an array of strings containing the command to be executed and its
+ *           arguments as separate strings. argv does not need to be
+ *           NULL-terminated
+ *   status: the equivalent child status as populated by wait(status). This
+ *           value is only valid when logwrap successfully completes. If NULL
+ *           the return value of the child will be the function's return value.
+ *   ignore_int_quit: set to true if you want to completely ignore SIGINT and
+ *           SIGQUIT while logwrap is running. This may force the end-user to
+ *           send a signal twice to signal the caller (once for the child, and
+ *           once for the caller)
+ *   log_target: Specify where to log the output of the child, either LOG_NONE,
+ *           LOG_ALOG (for the Android system log) or LOG_KLOG (for the kernel
+ *           log).
+ *   abbreviated: If true, capture up to the first 100 lines and last 4K of
+ *           output from the child.  The abbreviated output is not dumped to
+ *           the specified log until the child has exited.
+ *
+ * Return value:
+ *   0 when logwrap successfully run the child process and captured its status
+ *   -1 when an internal error occurred
+ *   -ECHILD if status is NULL and the child didn't exit properly
+ *   the return value of the child if it exited properly and status is NULL
+ *
+ */
+
+/* Values for the log_target parameter android_fork_exec_ext() */
+#define LOG_NONE        0
+#define LOG_ALOG        1
+#define LOG_KLOG        2
+
+int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
+        int log_target, bool abbreviated);
+
+/* Similar to above, except abbreviated logging is not available, and if logwrap
+ * is true, logging is to the Android system log, and if false, there is no
+ * logging.
+ */
+static inline int android_fork_execvp(int argc, char* argv[], int *status,
+                                     bool ignore_int_quit, bool logwrap)
+{
+    return android_fork_execvp_ext(argc, argv, status, ignore_int_quit,
+                                   (logwrap ? LOG_ALOG : LOG_NONE), false);
+}
+
+
+__END_DECLS
+
+#endif /* __LIBS_LOGWRAP_H */
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
new file mode 100644
index 0000000..01cc9a1
--- /dev/null
+++ b/logwrapper/logwrap.c
@@ -0,0 +1,542 @@
+/*
+ * Copyright (C) 2008 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 <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <poll.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdbool.h>
+#include <pthread.h>
+
+#include <logwrap/logwrap.h>
+#include "private/android_filesystem_config.h"
+#include "cutils/log.h"
+#include <cutils/klog.h>
+
+#define ARRAY_SIZE(x)   (sizeof(x) / sizeof(*(x)))
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+static pthread_mutex_t fd_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+#define ERROR(fmt, args...)                                                   \
+do {                                                                          \
+    fprintf(stderr, fmt, ## args);                                            \
+    ALOG(LOG_ERROR, "logwrapper", fmt, ## args);                              \
+} while(0)
+
+#define FATAL_CHILD(fmt, args...)                                             \
+do {                                                                          \
+    ERROR(fmt, ## args);                                                      \
+    _exit(-1);                                                                \
+} while(0)
+
+#define MAX_KLOG_TAG 16
+
+/* This is a simple buffer that holds up to the first beginning_buf->buf_size
+ * bytes of output from a command.
+ */
+#define BEGINNING_BUF_SIZE 0x1000
+struct beginning_buf {
+    char *buf;
+    size_t alloc_len;
+    /* buf_size is the usable space, which is one less than the allocated size */
+    size_t buf_size;
+    size_t used_len;
+};
+
+/* This is a circular buf that holds up to the last ending_buf->buf_size bytes
+ * of output from a command after the first beginning_buf->buf_size bytes
+ * (which are held in beginning_buf above).
+ */
+#define ENDING_BUF_SIZE 0x1000
+struct ending_buf {
+    char *buf;
+    ssize_t alloc_len;
+    /* buf_size is the usable space, which is one less than the allocated size */
+    ssize_t buf_size;
+    ssize_t used_len;
+    /* read and write offsets into the circular buffer */
+    int read;
+    int write;
+};
+
+ /* A structure to hold all the abbreviated buf data */
+struct abbr_buf {
+    struct beginning_buf b_buf;
+    struct ending_buf e_buf;
+    int beginning_buf_full;
+};
+
+/* Collect all the various bits of info needed for logging in one place. */
+struct log_info {
+    int log_target;
+    char klog_fmt[MAX_KLOG_TAG * 2];
+    char *btag;
+    bool abbreviated;
+    struct abbr_buf a_buf;
+};
+
+/* Forware declaration */
+static void add_line_to_abbr_buf(struct abbr_buf *a_buf, char *linebuf, int linelen);
+
+/* Return 0 on success, and 1 when full */
+static int add_line_to_linear_buf(struct beginning_buf *b_buf,
+                                   char *line, ssize_t line_len)
+{
+    size_t new_len;
+    char *new_buf;
+    int full = 0;
+
+    if ((line_len + b_buf->used_len) > b_buf->buf_size) {
+        full = 1;
+    } else {
+        /* Add to the end of the buf */
+        memcpy(b_buf->buf + b_buf->used_len, line, line_len);
+        b_buf->used_len += line_len;
+    }
+
+    return full;
+}
+
+static void add_line_to_circular_buf(struct ending_buf *e_buf,
+                                     char *line, ssize_t line_len)
+{
+    ssize_t free_len;
+    ssize_t needed_space;
+    char *new_buf;
+    int cnt;
+
+    if (e_buf->buf == NULL) {
+        return;
+    }
+
+   if (line_len > e_buf->buf_size) {
+       return;
+   }
+
+    free_len = e_buf->buf_size - e_buf->used_len;
+
+    if (line_len > free_len) {
+        /* remove oldest entries at read, and move read to make
+         * room for the new string */
+        needed_space = line_len - free_len;
+        e_buf->read = (e_buf->read + needed_space) % e_buf->buf_size;
+        e_buf->used_len -= needed_space;
+    }
+
+    /* Copy the line into the circular buffer, dealing with possible
+     * wraparound.
+     */
+    cnt = MIN(line_len, e_buf->buf_size - e_buf->write);
+    memcpy(e_buf->buf + e_buf->write, line, cnt);
+    if (cnt < line_len) {
+        memcpy(e_buf->buf, line + cnt, line_len - cnt);
+    }
+    e_buf->used_len += line_len;
+    e_buf->write = (e_buf->write + line_len) % e_buf->buf_size;
+}
+
+/* Log directly to the specified log */
+static void do_log_line(struct log_info *log_info, char *line) {
+    if (log_info->log_target == LOG_KLOG) {
+        klog_write(6, log_info->klog_fmt, line);
+    } else if (log_info->log_target == LOG_ALOG) {
+        ALOG(LOG_INFO, log_info->btag, "%s", line);
+    }
+}
+
+/* Log to either the abbreviated buf, or directly to the specified log
+ * via do_log_line() above.
+ */
+static void log_line(struct log_info *log_info, char *line, int len) {
+    if (log_info->abbreviated) {
+        add_line_to_abbr_buf(&log_info->a_buf, line, len);
+    } else {
+        do_log_line(log_info, line);
+    }
+}
+
+/*
+ * The kernel will take a maximum of 1024 bytes in any single write to
+ * the kernel logging device file, so find and print each line one at
+ * a time.  The allocated size for buf should be at least 1 byte larger
+ * than buf_size (the usable size of the buffer) to make sure there is
+ * room to temporarily stuff a null byte to terminate a line for logging.
+ */
+static void print_buf_lines(struct log_info *log_info, char *buf, int buf_size)
+{
+    char *line_start;
+    char c;
+    int line_len;
+    int i;
+
+    line_start = buf;
+    for (i = 0; i < buf_size; i++) {
+        if (*(buf + i) == '\n') {
+            /* Found a line ending, print the line and compute new line_start */
+            /* Save the next char and replace with \0 */
+            c = *(buf + i + 1);
+            *(buf + i + 1) = '\0';
+            do_log_line(log_info, line_start);
+            /* Restore the saved char */
+            *(buf + i + 1) = c;
+            line_start = buf + i + 1;
+        } else if (*(buf + i) == '\0') {
+            /* The end of the buffer, print the last bit */
+            do_log_line(log_info, line_start);
+            break;
+        }
+    }
+    /* If the buffer was completely full, and didn't end with a newline, just
+     * ignore the partial last line.
+     */
+}
+
+static void init_abbr_buf(struct abbr_buf *a_buf) {
+    char *new_buf;
+
+    memset(a_buf, 0, sizeof(struct abbr_buf));
+    new_buf = malloc(BEGINNING_BUF_SIZE);
+    if (new_buf) {
+        a_buf->b_buf.buf = new_buf;
+        a_buf->b_buf.alloc_len = BEGINNING_BUF_SIZE;
+        a_buf->b_buf.buf_size = BEGINNING_BUF_SIZE - 1;
+    }
+    new_buf = malloc(ENDING_BUF_SIZE);
+    if (new_buf) {
+        a_buf->e_buf.buf = new_buf;
+        a_buf->e_buf.alloc_len = ENDING_BUF_SIZE;
+        a_buf->e_buf.buf_size = ENDING_BUF_SIZE - 1;
+    }
+}
+
+static void free_abbr_buf(struct abbr_buf *a_buf) {
+    free(a_buf->b_buf.buf);
+    free(a_buf->e_buf.buf);
+}
+
+static void add_line_to_abbr_buf(struct abbr_buf *a_buf, char *linebuf, int linelen) {
+    if (!a_buf->beginning_buf_full) {
+        a_buf->beginning_buf_full =
+            add_line_to_linear_buf(&a_buf->b_buf, linebuf, linelen);
+    }
+    if (a_buf->beginning_buf_full) {
+        add_line_to_circular_buf(&a_buf->e_buf, linebuf, linelen);
+    }
+}
+
+static void print_abbr_buf(struct log_info *log_info) {
+    struct abbr_buf *a_buf = &log_info->a_buf;
+
+    /* Add the abbreviated output to the kernel log */
+    if (a_buf->b_buf.alloc_len) {
+        print_buf_lines(log_info, a_buf->b_buf.buf, a_buf->b_buf.used_len);
+    }
+
+    /* Print an ellipsis to indicate that the buffer has wrapped or
+     * is full, and some data was not logged.
+     */
+    if (a_buf->e_buf.used_len == a_buf->e_buf.buf_size) {
+        do_log_line(log_info, "...\n");
+    }
+
+    if (a_buf->e_buf.used_len == 0) {
+        return;
+    }
+
+    /* Simplest way to print the circular buffer is allocate a second buf
+     * of the same size, and memcpy it so it's a simple linear buffer,
+     * and then cal print_buf_lines on it */
+    if (a_buf->e_buf.read < a_buf->e_buf.write) {
+        /* no wrap around, just print it */
+        print_buf_lines(log_info, a_buf->e_buf.buf + a_buf->e_buf.read,
+                        a_buf->e_buf.used_len);
+    } else {
+        /* The circular buffer will always have at least 1 byte unused,
+         * so by allocating alloc_len here we will have at least
+         * 1 byte of space available as required by print_buf_lines().
+         */
+        char * nbuf = malloc(a_buf->e_buf.alloc_len);
+        if (!nbuf) {
+            return;
+        }
+        int first_chunk_len = a_buf->e_buf.buf_size - a_buf->e_buf.read;
+        memcpy(nbuf, a_buf->e_buf.buf + a_buf->e_buf.read, first_chunk_len);
+        /* copy second chunk */
+        memcpy(nbuf + first_chunk_len, a_buf->e_buf.buf, a_buf->e_buf.write);
+        print_buf_lines(log_info, nbuf, first_chunk_len + a_buf->e_buf.write);
+        free(nbuf);
+    }
+}
+
+static int parent(const char *tag, int parent_read, pid_t pid,
+        int *chld_sts, int log_target, bool abbreviated) {
+    int status = 0;
+    char buffer[4096];
+    struct pollfd poll_fds[] = {
+        [0] = {
+            .fd = parent_read,
+            .events = POLLIN,
+        },
+    };
+    int rc = 0;
+
+    struct log_info log_info;
+
+    int a = 0;  // start index of unprocessed data
+    int b = 0;  // end index of unprocessed data
+    int sz;
+    bool found_child = false;
+    char tmpbuf[256];
+
+    log_info.log_target = log_target;
+    log_info.abbreviated = abbreviated;
+    log_info.btag = basename(tag);
+    if (!log_info.btag) {
+        log_info.btag = (char*) tag;
+    }
+
+    if (abbreviated && (log_target == LOG_NONE)) {
+        abbreviated = 0;
+    }
+    if (abbreviated) {
+        init_abbr_buf(&log_info.a_buf);
+    }
+
+    if (log_target == LOG_KLOG) {
+        snprintf(log_info.klog_fmt, sizeof(log_info.klog_fmt),
+                 "<6>%.*s: %%s", MAX_KLOG_TAG, log_info.btag);
+    }
+
+    while (!found_child) {
+        if (TEMP_FAILURE_RETRY(poll(poll_fds, ARRAY_SIZE(poll_fds), -1)) < 0) {
+            ERROR("poll failed\n");
+            rc = -1;
+            goto err_poll;
+        }
+
+        if (poll_fds[0].revents & POLLIN) {
+            sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b);
+
+            sz += b;
+            // Log one line at a time
+            for (b = 0; b < sz; b++) {
+                if (buffer[b] == '\r') {
+                    if (abbreviated) {
+                        /* The abbreviated logging code uses newline as
+                         * the line separator.  Lucikly, the pty layer
+                         * helpfully cooks the output of the command
+                         * being run and inserts a CR before NL.  So
+                         * I just change it to NL here when doing
+                         * abbreviated logging.
+                         */
+                        buffer[b] = '\n';
+                    } else {
+                        buffer[b] = '\0';
+                    }
+                } else if (buffer[b] == '\n') {
+                    buffer[b] = '\0';
+                    log_line(&log_info, &buffer[a], b - a);
+                    a = b + 1;
+                }
+            }
+
+            if (a == 0 && b == sizeof(buffer) - 1) {
+                // buffer is full, flush
+                buffer[b] = '\0';
+                log_line(&log_info, &buffer[a], b - a);
+                b = 0;
+            } else if (a != b) {
+                // Keep left-overs
+                b -= a;
+                memmove(buffer, &buffer[a], b);
+                a = 0;
+            } else {
+                a = 0;
+                b = 0;
+            }
+        }
+
+        if (poll_fds[0].revents & POLLHUP) {
+            int ret;
+
+            ret = waitpid(pid, &status, WNOHANG);
+            if (ret < 0) {
+                rc = errno;
+                ALOG(LOG_ERROR, "logwrap", "waitpid failed with %s\n", strerror(errno));
+                goto err_waitpid;
+            }
+            if (ret > 0) {
+                found_child = true;
+            }
+        }
+    }
+
+    if (chld_sts != NULL) {
+        *chld_sts = status;
+    } else {
+      if (WIFEXITED(status))
+        rc = WEXITSTATUS(status);
+      else
+        rc = -ECHILD;
+    }
+
+    // Flush remaining data
+    if (a != b) {
+      buffer[b] = '\0';
+      log_line(&log_info, &buffer[a], b - a);
+    }
+
+    /* All the output has been processed, time to dump the abbreviated output */
+    if (abbreviated) {
+        print_abbr_buf(&log_info);
+    }
+
+    if (WIFEXITED(status)) {
+      if (WEXITSTATUS(status)) {
+        snprintf(tmpbuf, sizeof(tmpbuf),
+                 "%s terminated by exit(%d)\n", log_info.btag, WEXITSTATUS(status));
+        do_log_line(&log_info, tmpbuf);
+      }
+    } else {
+      if (WIFSIGNALED(status)) {
+        snprintf(tmpbuf, sizeof(tmpbuf),
+                       "%s terminated by signal %d\n", log_info.btag, WTERMSIG(status));
+        do_log_line(&log_info, tmpbuf);
+      } else if (WIFSTOPPED(status)) {
+        snprintf(tmpbuf, sizeof(tmpbuf),
+                       "%s stopped by signal %d\n", log_info.btag, WSTOPSIG(status));
+        do_log_line(&log_info, tmpbuf);
+      }
+    }
+
+err_waitpid:
+err_poll:
+    if (abbreviated) {
+        free_abbr_buf(&log_info.a_buf);
+    }
+    return rc;
+}
+
+static void child(int argc, char* argv[]) {
+    // create null terminated argv_child array
+    char* argv_child[argc + 1];
+    memcpy(argv_child, argv, argc * sizeof(char *));
+    argv_child[argc] = NULL;
+
+    if (execvp(argv_child[0], argv_child)) {
+        FATAL_CHILD("executing %s failed: %s\n", argv_child[0],
+                strerror(errno));
+    }
+}
+
+int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
+        int log_target, bool abbreviated) {
+    pid_t pid;
+    int parent_ptty;
+    int child_ptty;
+    char *child_devname = NULL;
+    struct sigaction intact;
+    struct sigaction quitact;
+    sigset_t blockset;
+    sigset_t oldset;
+    int rc = 0;
+
+    rc = pthread_mutex_lock(&fd_mutex);
+    if (rc) {
+        ERROR("failed to lock signal_fd mutex\n");
+        goto err_lock;
+    }
+
+    /* Use ptty instead of socketpair so that STDOUT is not buffered */
+    parent_ptty = open("/dev/ptmx", O_RDWR);
+    if (parent_ptty < 0) {
+        ERROR("Cannot create parent ptty\n");
+        rc = -1;
+        goto err_open;
+    }
+
+    if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
+            ((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
+        ERROR("Problem with /dev/ptmx\n");
+        rc = -1;
+        goto err_ptty;
+    }
+
+    child_ptty = open(child_devname, O_RDWR);
+    if (child_ptty < 0) {
+        ERROR("Cannot open child_ptty\n");
+        rc = -1;
+        goto err_child_ptty;
+    }
+
+    sigemptyset(&blockset);
+    sigaddset(&blockset, SIGINT);
+    sigaddset(&blockset, SIGQUIT);
+    pthread_sigmask(SIG_BLOCK, &blockset, &oldset);
+
+    pid = fork();
+    if (pid < 0) {
+        close(child_ptty);
+        ERROR("Failed to fork\n");
+        rc = -1;
+        goto err_fork;
+    } else if (pid == 0) {
+        pthread_mutex_unlock(&fd_mutex);
+        pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+        close(parent_ptty);
+
+        // redirect stdout and stderr
+        dup2(child_ptty, 1);
+        dup2(child_ptty, 2);
+        close(child_ptty);
+
+        child(argc, argv);
+    } else {
+        close(child_ptty);
+        if (ignore_int_quit) {
+            struct sigaction ignact;
+
+            memset(&ignact, 0, sizeof(ignact));
+            ignact.sa_handler = SIG_IGN;
+            sigaction(SIGINT, &ignact, &intact);
+            sigaction(SIGQUIT, &ignact, &quitact);
+        }
+
+        rc = parent(argv[0], parent_ptty, pid, status, log_target, abbreviated);
+    }
+
+    if (ignore_int_quit) {
+        sigaction(SIGINT, &intact, NULL);
+        sigaction(SIGQUIT, &quitact, NULL);
+    }
+err_fork:
+    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+err_child_ptty:
+err_ptty:
+    close(parent_ptty);
+err_open:
+    pthread_mutex_unlock(&fd_mutex);
+err_lock:
+    return rc;
+}
diff --git a/logwrapper/logwrapper.c b/logwrapper/logwrapper.c
index dd777c0..d1c6240 100644
--- a/logwrapper/logwrapper.c
+++ b/logwrapper/logwrapper.c
@@ -14,17 +14,14 @@
  * limitations under the License.
  */
 
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/wait.h>
 #include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <libgen.h>
 
-#include "private/android_filesystem_config.h"
+#include <logwrap/logwrap.h>
+#include <cutils/klog.h>
+
 #include "cutils/log.h"
 
 void fatal(const char *msg) {
@@ -35,152 +32,65 @@
 
 void usage() {
     fatal(
-        "Usage: logwrapper [-d] BINARY [ARGS ...]\n"
+        "Usage: logwrapper [-a] [-d] [-k] BINARY [ARGS ...]\n"
         "\n"
         "Forks and executes BINARY ARGS, redirecting stdout and stderr to\n"
         "the Android logging system. Tag is set to BINARY, priority is\n"
         "always LOG_INFO.\n"
         "\n"
+        "-a: Causes logwrapper to do abbreviated logging.\n"
+        "    This logs up to the first 4K and last 4K of the command\n"
+        "    being run, and logs the output when the command exits\n"
         "-d: Causes logwrapper to SIGSEGV when BINARY terminates\n"
-        "    fault address is set to the status of wait()\n");
-}
-
-void parent(const char *tag, int seg_fault_on_exit, int parent_read) {
-    int status;
-    char buffer[4096];
-
-    int a = 0;  // start index of unprocessed data
-    int b = 0;  // end index of unprocessed data
-    int sz;
-
-    char *btag = basename(tag);
-    if (!btag) btag = (char*) tag;
-
-    while ((sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b)) > 0) {
-
-        sz += b;
-        // Log one line at a time
-        for (b = 0; b < sz; b++) {
-            if (buffer[b] == '\r') {
-                buffer[b] = '\0';
-            } else if (buffer[b] == '\n') {
-                buffer[b] = '\0';
-                ALOG(LOG_INFO, btag, "%s", &buffer[a]);
-                a = b + 1;
-            }
-        }
-
-        if (a == 0 && b == sizeof(buffer) - 1) {
-            // buffer is full, flush
-            buffer[b] = '\0';
-            ALOG(LOG_INFO, btag, "%s", &buffer[a]);
-            b = 0;
-        } else if (a != b) {
-            // Keep left-overs
-            b -= a;
-            memmove(buffer, &buffer[a], b);
-            a = 0;
-        } else {
-            a = 0;
-            b = 0;
-        }
-
-    }
-    // Flush remaining data
-    if (a != b) {
-        buffer[b] = '\0';
-        ALOG(LOG_INFO, btag, "%s", &buffer[a]);
-    }
-    status = 0xAAAA;
-    if (wait(&status) != -1) {  // Wait for child
-        if (WIFEXITED(status) && WEXITSTATUS(status))
-            ALOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
-                    WEXITSTATUS(status));
-        else if (WIFSIGNALED(status))
-            ALOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
-                    WTERMSIG(status));
-        else if (WIFSTOPPED(status))
-            ALOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
-                    WSTOPSIG(status));
-    } else
-        ALOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
-                strerror(errno), errno);
-    if (seg_fault_on_exit)
-        *(int *)status = 0;  // causes SIGSEGV with fault_address = status
-}
-
-void child(int argc, char* argv[]) {
-    // create null terminated argv_child array
-    char* argv_child[argc + 1];
-    memcpy(argv_child, argv, argc * sizeof(char *));
-    argv_child[argc] = NULL;
-
-    if (execvp(argv_child[0], argv_child)) {
-        ALOG(LOG_ERROR, "logwrapper",
-            "executing %s failed: %s\n", argv_child[0], strerror(errno));
-        exit(-1);
-    }
+        "    fault address is set to the status of wait()\n"
+        "-k: Causes logwrapper to log to the kernel log instead of\n"
+        "    the Android system log\n");
 }
 
 int main(int argc, char* argv[]) {
-    pid_t pid;
     int seg_fault_on_exit = 0;
+    int log_target = LOG_ALOG;
+    bool abbreviated = false;
+    int ch;
+    int status = 0xAAAA;
+    int rc;
 
-    int parent_ptty;
-    int child_ptty;
-    char *child_devname = NULL;
-
-    if (argc < 2) {
-        usage();
-    }
-
-    if (strncmp(argv[1], "-d", 2) == 0) {
-        seg_fault_on_exit = 1;
-        argc--;
-        argv++;
-    }
-
-    if (argc < 2) {
-        usage();
-    }
-
-    /* Use ptty instead of socketpair so that STDOUT is not buffered */
-    parent_ptty = open("/dev/ptmx", O_RDWR);
-    if (parent_ptty < 0) {
-        fatal("Cannot create parent ptty\n");
-    }
-
-    if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
-            ((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
-        fatal("Problem with /dev/ptmx\n");
-    }
-
-    pid = fork();
-    if (pid < 0) {
-        fatal("Failed to fork\n");
-    } else if (pid == 0) {
-        child_ptty = open(child_devname, O_RDWR);
-        if (child_ptty < 0) {
-            fatal("Problem with child ptty\n");
+    while ((ch = getopt(argc, argv, "adk")) != -1) {
+        switch (ch) {
+            case 'a':
+                abbreviated = true;
+                break;
+            case 'd':
+                seg_fault_on_exit = 1;
+                break;
+            case 'k':
+                log_target = LOG_KLOG;
+                klog_set_level(6);
+                break;
+            case '?':
+            default:
+              usage();
         }
+    }
+    argc -= optind;
+    argv += optind;
 
-        // redirect stdout and stderr
-        close(parent_ptty);
-        dup2(child_ptty, 1);
-        dup2(child_ptty, 2);
-        close(child_ptty);
-
-        child(argc - 1, &argv[1]);
-
-    } else {
-        // switch user and group to "log"
-        // this may fail if we are not root, 
-        // but in that case switching user/group is unnecessary 
-        setgid(AID_LOG);
-        setuid(AID_LOG);
-
-        parent(argv[1], seg_fault_on_exit, parent_ptty);
+    if (argc < 1) {
+        usage();
     }
 
-    return 0;
+    rc = android_fork_execvp_ext(argc, &argv[0], &status, true,
+                                 log_target, abbreviated);
+    if (!rc) {
+        if (WIFEXITED(status))
+            rc = WEXITSTATUS(status);
+        else
+            rc = -ECHILD;
+    }
+
+    if (seg_fault_on_exit) {
+        *(int *)status = 0;  // causes SIGSEGV with fault_address = status
+    }
+
+    return rc;
 }
diff --git a/mkbootimg/bootimg.h b/mkbootimg/bootimg.h
index 242ab35..9171d85 100644
--- a/mkbootimg/bootimg.h
+++ b/mkbootimg/bootimg.h
@@ -24,6 +24,7 @@
 #define BOOT_MAGIC_SIZE 8
 #define BOOT_NAME_SIZE 16
 #define BOOT_ARGS_SIZE 512
+#define BOOT_EXTRA_ARGS_SIZE 1024
 
 struct boot_img_hdr
 {
@@ -43,10 +44,14 @@
     unsigned unused[2];    /* future expansion: should be 0 */
 
     unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
-    
+
     unsigned char cmdline[BOOT_ARGS_SIZE];
 
     unsigned id[8]; /* timestamp / checksum / sha1 / etc */
+
+    /* Supplemental command line data; kept here to maintain
+     * binary compatibility with older versions of mkbootimg */
+    unsigned char extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
 };
 
 /*
diff --git a/mkbootimg/mkbootimg.c b/mkbootimg/mkbootimg.c
index 2c32ce3..d598f03 100644
--- a/mkbootimg/mkbootimg.c
+++ b/mkbootimg/mkbootimg.c
@@ -72,7 +72,7 @@
 
 
 
-static unsigned char padding[4096] = { 0, };
+static unsigned char padding[16384] = { 0, };
 
 int write_padding(int fd, unsigned pagesize, unsigned itemsize)
 {
@@ -114,6 +114,7 @@
     unsigned ramdisk_offset = 0x01000000;
     unsigned second_offset  = 0x00f00000;
     unsigned tags_offset    = 0x00000100;
+    size_t cmdlen;
 
     argc--;
     argv++;
@@ -152,7 +153,8 @@
             board = val;
         } else if(!strcmp(arg,"--pagesize")) {
             pagesize = strtoul(val, 0, 10);
-            if ((pagesize != 2048) && (pagesize != 4096)) {
+            if ((pagesize != 2048) && (pagesize != 4096)
+                && (pagesize != 8192) && (pagesize != 16384)) {
                 fprintf(stderr,"error: unsupported page size %d\n", pagesize);
                 return -1;
             }
@@ -191,11 +193,19 @@
 
     memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
 
-    if(strlen(cmdline) > (BOOT_ARGS_SIZE - 1)) {
+    cmdlen = strlen(cmdline);
+    if(cmdlen > (BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE - 2)) {
         fprintf(stderr,"error: kernel commandline too large\n");
         return 1;
     }
-    strcpy((char*)hdr.cmdline, cmdline);
+    /* Even if we need to use the supplemental field, ensure we
+     * are still NULL-terminated */
+    strncpy((char *)hdr.cmdline, cmdline, BOOT_ARGS_SIZE - 1);
+    hdr.cmdline[BOOT_ARGS_SIZE - 1] = '\0';
+    if (cmdlen >= (BOOT_ARGS_SIZE - 1)) {
+        cmdline += (BOOT_ARGS_SIZE - 1);
+        strncpy((char *)hdr.extra_cmdline, cmdline, BOOT_EXTRA_ARGS_SIZE);
+    }
 
     kernel_data = load_file(kernel_fn, &hdr.kernel_size);
     if(kernel_data == 0) {
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 64ff522..3417f54 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -4,28 +4,8 @@
 # files that live under /system/etc/...
 
 copy_from := \
-	etc/dbus.conf \
 	etc/hosts
 
-ifeq ($(TARGET_PRODUCT),full)
-copy_from += etc/vold.fstab
-endif
-
-ifeq ($(TARGET_PRODUCT),full_x86)
-copy_from += etc/vold.fstab
-endif
-
-ifeq ($(TARGET_PRODUCT),full_mips)
-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
-# to run the dex pre-optimization *in* the emulator. So keep the file until
-# we are capable of running dex preopt on the host.
-#
-copy_from += etc/init.goldfish.sh
 
 copy_to := $(addprefix $(TARGET_OUT)/,$(copy_from))
 copy_from := $(addprefix $(LOCAL_PATH)/,$(copy_from))
@@ -56,20 +36,6 @@
 
 # init.usb.rc is handled by build/target/product/core.rc
 
-# Just like /system/etc/init.goldfish.sh, the /init.godlfish.rc is here
-# to allow -user builds to properly run the dex pre-optimization pass in
-# the emulator.
-file := $(TARGET_ROOT_OUT)/init.goldfish.rc
-$(file) : $(LOCAL_PATH)/etc/init.goldfish.rc | $(ACP)
-	$(transform-prebuilt-to-target)
-ALL_PREBUILT += $(file)
-$(INSTALLED_RAMDISK_TARGET): $(file)
-
-file := $(TARGET_ROOT_OUT)/ueventd.goldfish.rc
-$(file) : $(LOCAL_PATH)/etc/ueventd.goldfish.rc | $(ACP)
-	$(transform-prebuilt-to-target)
-ALL_PREBUILT += $(file)
-$(INSTALLED_RAMDISK_TARGET): $(file)
 
 # create some directories (some are mount points)
 DIRS := $(addprefix $(TARGET_ROOT_OUT)/, \
diff --git a/rootdir/etc/dbus.conf b/rootdir/etc/dbus.conf
deleted file mode 100644
index 75586b9..0000000
--- a/rootdir/etc/dbus.conf
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
- "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
-<busconfig>
-
-  <!-- Our well-known bus type, do not change this -->
-  <type>system</type>
-
-  <!-- Only allow socket-credentials-based authentication -->
-  <auth>EXTERNAL</auth>
-
-  <!-- Only listen on a local socket. (abstract=/path/to/socket 
-       means use abstract namespace, don't really create filesystem 
-       file; only Linux supports this. Use path=/whatever on other 
-       systems.) -->
-  <listen>unix:path=/dev/socket/dbus</listen>
-
-  <!-- Allow everything, D-Bus socket is protected by unix filesystem
-       permissions -->
-  <policy context="default">
-    <allow send_interface="*"/>
-    <allow receive_interface="*"/>
-    <allow own="*"/>
-    <allow user="*"/>
-    <allow send_requested_reply="true"/>
-    <allow receive_requested_reply="true"/>
-  </policy>
-</busconfig>
diff --git a/rootdir/etc/init.goldfish.rc b/rootdir/etc/init.goldfish.rc
deleted file mode 100644
index cde9dee..0000000
--- a/rootdir/etc/init.goldfish.rc
+++ /dev/null
@@ -1,82 +0,0 @@
-on early-init
-    export EXTERNAL_STORAGE /mnt/sdcard
-    mkdir /mnt/sdcard 0000 system system
-    # for backwards compatibility
-    symlink /mnt/sdcard /sdcard
-
-on boot
-    setsebool in_qemu=1
-    restorecon /sys/qemu_trace/process_name
-    restorecon /sys/qemu_trace/state
-    restorecon /sys/qemu_trace/symbol
-    setprop ARGH ARGH
-    setprop net.eth0.gw 10.0.2.2
-    setprop net.eth0.dns1 10.0.2.3
-    setprop net.gprs.local-ip 10.0.2.15
-    setprop ro.radio.use-ppp no
-    setprop ro.build.product generic
-    setprop ro.product.device generic
-
-# fake some battery state
-    setprop status.battery.state Slow
-    setprop status.battery.level 5
-    setprop status.battery.level_raw  50
-    setprop status.battery.level_scale 9
-
-# disable some daemons the emulator doesn't want
-    stop dund
-    stop akmd
-
-# start essential services
-    start qemud
-    start goldfish-logcat
-    start goldfish-setup
-
-    setprop ro.setupwizard.mode EMULATOR
-
-# enable Google-specific location features,
-# like NetworkLocationProvider and LocationCollector
-    setprop ro.com.google.locationfeatures 1
-
-# For the emulator, which bypasses Setup Wizard, you can specify
-# account info for the device via these two properties.  Google
-# Login Service will insert these accounts into the database when
-# it is created (ie, after a data wipe).
-#
-#   setprop ro.config.hosted_account username@hosteddomain.org:password
-#   setprop ro.config.google_account username@gmail.com:password
-#
-# You MUST have a Google account on the device, and you MAY
-# additionally have a hosted account.  No other configuration is
-# supported, and arbitrary breakage may result if you specify
-# something else.
-
-service goldfish-setup /system/etc/init.goldfish.sh
-    user root
-    group root
-    oneshot
-
-# The qemu-props program is used to set various system
-# properties on boot. It must be run early during the boot
-# process to avoid race conditions with other daemons that
-# might read them (e.g. surface flinger), so define it in
-# class 'core'
-#
-service qemu-props /system/bin/qemu-props
-    class core
-    user root
-    group root
-    oneshot
-
-service qemud /system/bin/qemud
-    socket qemud    stream 666
-    oneshot
-
-# -Q is a special logcat option that forces the
-# program to check wether it runs on the emulator
-# if it does, it redirects its output to the device
-# named by the androidboot.console kernel option
-# if not, is simply exits immediately
-
-service goldfish-logcat /system/bin/logcat -Q
-    oneshot
diff --git a/rootdir/etc/init.goldfish.sh b/rootdir/etc/init.goldfish.sh
deleted file mode 100755
index ece75b4..0000000
--- a/rootdir/etc/init.goldfish.sh
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/system/bin/sh
-
-# Setup networking when boot starts
-ifconfig eth0 10.0.2.15 netmask 255.255.255.0 up
-route add default gw 10.0.2.2 dev eth0
-
-# ro.kernel.android.qemud is normally set when we
-# want the RIL (radio interface layer) to talk to
-# the emulated modem through qemud.
-#
-# However, this will be undefined in two cases:
-#
-# - When we want the RIL to talk directly to a guest
-#   serial device that is connected to a host serial
-#   device by the emulator.
-#
-# - We don't want to use the RIL but the VM-based
-#   modem emulation that runs inside the guest system
-#   instead.
-#
-# The following detects the latter case and sets up the
-# system for it.
-#
-qemud=`getprop ro.kernel.android.qemud`
-case "$qemud" in
-    "")
-    radio_ril=`getprop ro.kernel.android.ril`
-    case "$radio_ril" in
-        "")
-        # no need for the radio interface daemon
-        # telephony is entirely emulated in Java
-        setprop ro.radio.noril yes
-        stop ril-daemon
-        ;;
-    esac
-    ;;
-esac
-
-# Setup additionnal DNS servers if needed
-num_dns=`getprop ro.kernel.ndns`
-case "$num_dns" in
-    2) setprop net.eth0.dns2 10.0.2.4
-       ;;
-    3) setprop net.eth0.dns2 10.0.2.4
-       setprop net.eth0.dns3 10.0.2.5
-       ;;
-    4) setprop net.eth0.dns2 10.0.2.4
-       setprop net.eth0.dns3 10.0.2.5
-       setprop net.eth0.dns4 10.0.2.6
-       ;;
-esac
-
-# disable boot animation for a faster boot sequence when needed
-boot_anim=`getprop ro.kernel.android.bootanim`
-case "$boot_anim" in
-    0)  setprop debug.sf.nobootanimation 1
-    ;;
-esac
-
-# set up the second interface (for inter-emulator connections)
-# if required
-my_ip=`getprop net.shared_net_ip`
-case "$my_ip" in
-    "")
-    ;;
-    *) ifconfig eth1 "$my_ip" netmask 255.255.255.0 up
-    ;;
-esac
diff --git a/rootdir/etc/ueventd.goldfish.rc b/rootdir/etc/ueventd.goldfish.rc
deleted file mode 100644
index 8de7049..0000000
--- a/rootdir/etc/ueventd.goldfish.rc
+++ /dev/null
@@ -1,5 +0,0 @@
-# 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/etc/vold.fstab b/rootdir/etc/vold.fstab
deleted file mode 100644
index 4aad8dc..0000000
--- a/rootdir/etc/vold.fstab
+++ /dev/null
@@ -1,24 +0,0 @@
-## Vold 2.0 Generic fstab
-## - San Mehat (san@android.com)
-## 
-
-#######################
-## Regular device mount
-##
-## Format: dev_mount <label> <mount_point> <part> <sysfs_path1...> 
-## label        - Label for the volume
-## mount_point  - Where the volume will be mounted
-## part         - Partition # (1 based), or 'auto' for first usable partition.
-## <sysfs_path> - List of sysfs paths to source devices
-######################
-
-## Example of a standard sdcard mount for the emulator / Dream
-# Mounts the first usable partition of the specified device
-dev_mount sdcard /mnt/sdcard auto /devices/platform/goldfish_mmc.0 /devices/platform/msm_sdcc.2/mmc_host/mmc1
-
-## Example of a dual card setup
-# dev_mount left_sdcard  /sdcard1  auto /devices/platform/goldfish_mmc.0 /devices/platform/msm_sdcc.2/mmc_host/mmc1
-# dev_mount right_sdcard /sdcard2  auto /devices/platform/goldfish_mmc.1 /devices/platform/msm_sdcc.3/mmc_host/mmc1
-
-## Example of specifying a specific partition for mounts
-# dev_mount sdcard /sdcard 2 /devices/platform/goldfish_mmc.0 /devices/platform/msm_sdcc.2/mmc_host/mmc1
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a76602c..5e3c991 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -37,7 +37,7 @@
     export ANDROID_STORAGE /storage
     export ASEC_MOUNTPOINT /mnt/asec
     export LOOP_MOUNTPOINT /mnt/obb
-    export BOOTCLASSPATH /system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/telephony-common.jar:/system/framework/mms-common.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar
+    export BOOTCLASSPATH /system/framework/core.jar:/system/framework/conscrypt.jar:/system/framework/okhttp.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/telephony-common.jar:/system/framework/voip-common.jar:/system/framework/mms-common.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar
 
 # Backward compatibility
     symlink /system/etc /etc
@@ -92,6 +92,7 @@
     write /proc/sys/kernel/kptr_restrict 2
     write /proc/sys/kernel/dmesg_restrict 1
     write /proc/sys/vm/mmap_min_addr 32768
+    write /proc/sys/net/ipv4/ping_group_range "0 2147483647"
     write /proc/sys/kernel/sched_rt_runtime_us 950000
     write /proc/sys/kernel/sched_rt_period_us 1000000
 
@@ -120,18 +121,16 @@
     write /dev/cpuctl/apps/bg_non_interactive/cpu.rt_runtime_us 700000
     write /dev/cpuctl/apps/bg_non_interactive/cpu.rt_period_us 1000000
 
+# qtaguid will limit access to specific data based on group memberships.
+#   net_bw_acct grants impersonation of socket owners.
+#   net_bw_stats grants access to other apps' detailed tagged-socket stats.
+    chown root net_bw_acct /proc/net/xt_qtaguid/ctrl
+    chown root net_bw_stats /proc/net/xt_qtaguid/stats
+
 # Allow everybody to read the xt_qtaguid resource tracking misc dev.
 # This is needed by any process that uses socket tagging.
     chmod 0644 /dev/xt_qtaguid
 
-on fs
-# mount mtd partitions
-    # Mount /system rw first to give the filesystem a chance to save a checkpoint
-    mount yaffs2 mtd@system /system
-    mount yaffs2 mtd@system /system ro remount
-    mount yaffs2 mtd@userdata /data nosuid nodev
-    mount yaffs2 mtd@cache /cache nosuid nodev
-
 on post-fs
     # once everything is setup, no need to modify /
     mount rootfs rootfs / ro remount
@@ -207,6 +206,7 @@
     mkdir /data/misc/wifi 0770 wifi wifi
     chmod 0660 /data/misc/wifi/wpa_supplicant.conf
     mkdir /data/local 0751 root root
+    mkdir /data/misc/media 0700 media media
 
     # For security reasons, /data/local/tmp should always be empty.
     # Do not place files or directories in /data/local/tmp
@@ -235,6 +235,16 @@
     # the following directory.
     mkdir /data/drm 0770 drm drm
 
+    # create directory for MediaDrm plug-ins - give drm the read/write access to
+    # the following directory.
+    mkdir /data/mediadrm 0770 mediadrm mediadrm
+
+    # symlink to bugreport storage location
+    symlink /data/data/com.android.shell/files/bugreports /data/bugreports
+
+    # Separate location for storing security policy files on data
+    mkdir /data/security 0711 system system
+
     # If there is no fs-post-data action in the init.<device>.rc file, you
     # must uncomment this line, otherwise encrypted filesystems
     # won't work.
@@ -281,10 +291,14 @@
 
     chown system system /sys/devices/system/cpu/cpufreq/interactive/timer_rate
     chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/timer_rate
+    chown system system /sys/devices/system/cpu/cpufreq/interactive/timer_slack
+    chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/timer_slack
     chown system system /sys/devices/system/cpu/cpufreq/interactive/min_sample_time
     chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/min_sample_time
     chown system system /sys/devices/system/cpu/cpufreq/interactive/hispeed_freq
     chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/hispeed_freq
+    chown system system /sys/devices/system/cpu/cpufreq/interactive/target_loads
+    chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/target_loads
     chown system system /sys/devices/system/cpu/cpufreq/interactive/go_hispeed_load
     chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/go_hispeed_load
     chown system system /sys/devices/system/cpu/cpufreq/interactive/above_hispeed_delay
@@ -294,6 +308,10 @@
     chown system system /sys/devices/system/cpu/cpufreq/interactive/boostpulse
     chown system system /sys/devices/system/cpu/cpufreq/interactive/input_boost
     chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/input_boost
+    chown system system /sys/devices/system/cpu/cpufreq/interactive/boostpulse_duration
+    chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/boostpulse_duration
+    chown system system /sys/devices/system/cpu/cpufreq/interactive/io_is_busy
+    chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/io_is_busy
 
     # Assume SMP uses shared cpufreq policy for all CPUs
     chown system system /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
@@ -310,12 +328,6 @@
     chown system system /sys/class/leds/red/device/grpfreq
     chown system system /sys/class/leds/red/device/grppwm
     chown system system /sys/class/leds/red/device/blink
-    chown system system /sys/class/leds/red/brightness
-    chown system system /sys/class/leds/green/brightness
-    chown system system /sys/class/leds/blue/brightness
-    chown system system /sys/class/leds/red/device/grpfreq
-    chown system system /sys/class/leds/red/device/grppwm
-    chown system system /sys/class/leds/red/device/blink
     chown system system /sys/class/timed_output/vibrator/enable
     chown system system /sys/module/sco/parameters/disable_esco
     chown system system /sys/kernel/ipv4/tcp_wmem_min
@@ -326,6 +338,10 @@
     chown system system /sys/kernel/ipv4/tcp_rmem_max
     chown root radio /proc/cmdline
 
+# Set these so we can remotely update SELinux policy
+    chown system system /sys/fs/selinux/load
+    chown system system /sys/fs/selinux/enforce
+
 # Define TCP buffer sizes for various networks
 #   ReadMin, ReadInitial, ReadMax, WriteMin, WriteInitial, WriteMax,
     setprop net.tcp.buffersize.default 4096,87380,110208,4096,16384,110208
@@ -379,10 +395,6 @@
     critical
     seclabel u:r:ueventd:s0
 
-on property:selinux.reload_policy=1
-    restart ueventd
-    restart installd
-
 service console /system/bin/sh
     class core
     console
@@ -457,7 +469,7 @@
 service media /system/bin/mediaserver
     class main
     user media
-    group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc
+    group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
     ioprio rt 4
 
 service bootanim /system/bin/bootanimation
diff --git a/run-as/Android.mk b/run-as/Android.mk
index 043cc3a..a8f2885 100644
--- a/run-as/Android.mk
+++ b/run-as/Android.mk
@@ -3,6 +3,8 @@
 
 LOCAL_SRC_FILES:= run-as.c package.c
 
+LOCAL_SHARED_LIBRARIES := libselinux
+
 LOCAL_MODULE:= run-as
 
 include $(BUILD_EXECUTABLE)
diff --git a/run-as/package.c b/run-as/package.c
index 143d647..27fc1eb 100644
--- a/run-as/package.c
+++ b/run-as/package.c
@@ -47,15 +47,18 @@
 /* Copy 'srclen' string bytes from 'src' into buffer 'dst' of size 'dstlen'
  * This function always zero-terminate the destination buffer unless
  * 'dstlen' is 0, even in case of overflow.
+ * Returns a pointer into the src string, leaving off where the copy
+ * has stopped. The copy will stop when dstlen, srclen or a null
+ * character on src has been reached.
  */
-static void
+static const char*
 string_copy(char* dst, size_t dstlen, const char* src, size_t srclen)
 {
     const char* srcend = src + srclen;
     const char* dstend = dst + dstlen;
 
     if (dstlen == 0)
-        return;
+        return src;
 
     dstend--; /* make room for terminating zero */
 
@@ -63,6 +66,7 @@
         *dst++ = *src++;
 
     *dst = '\0'; /* zero-terminate result */
+    return src;
 }
 
 /* Open 'filename' and map it into our address-space.
@@ -76,13 +80,30 @@
     struct stat  st;
     size_t  length = 0;
     void*   address = NULL;
+    gid_t   oldegid;
 
     *filesize = 0;
 
+    /*
+     * Temporarily switch effective GID to allow us to read
+     * the packages file
+     */
+
+    oldegid = getegid();
+    if (setegid(AID_SYSTEM) < 0) {
+        return NULL;
+    }
+
     /* open the file for reading */
     fd = TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
-    if (fd < 0)
+    if (fd < 0) {
         return NULL;
+    }
+
+    /* restore back to our old egid */
+    if (setegid(oldegid) < 0) {
+        goto EXIT;
+    }
 
     /* get its size */
     ret = TEMP_FAILURE_RETRY(fstat(fd, &st));
@@ -411,6 +432,7 @@
     info->uid          = 0;
     info->isDebuggable = 0;
     info->dataDir[0]   = '\0';
+    info->seinfo[0]    = '\0';
 
     buffer = map_file(PACKAGES_LIST_FILE, &buffer_len);
     if (buffer == NULL)
@@ -421,13 +443,14 @@
 
     /* expect the following format on each line of the control file:
      *
-     *  <pkgName> <uid> <debugFlag> <dataDir>
+     *  <pkgName> <uid> <debugFlag> <dataDir> <seinfo>
      *
      * where:
      *  <pkgName>    is the package's name
      *  <uid>        is the application-specific user Id (decimal)
      *  <debugFlag>  is 1 if the package is debuggable, or 0 otherwise
      *  <dataDir>    is the path to the package's data directory (e.g. /data/data/com.example.foo)
+     *  <seinfo>     is the seinfo label associated with the package
      *
      * The file is generated in com.android.server.PackageManagerService.Settings.writeLP()
      */
@@ -483,7 +506,18 @@
         if (q == p)
             goto BAD_FORMAT;
 
-        string_copy(info->dataDir, sizeof info->dataDir, p, q - p);
+        p = string_copy(info->dataDir, sizeof info->dataDir, p, q - p);
+
+        /* skip spaces */
+        if (parse_spaces(&p, end) < 0)
+            goto BAD_FORMAT;
+
+        /* fifth field is the seinfo string */
+        q = skip_non_spaces(p, end);
+        if (q == p)
+            goto BAD_FORMAT;
+
+        string_copy(info->seinfo, sizeof info->seinfo, p, q - p);
 
         /* Ignore the rest */
         result = 0;
diff --git a/run-as/package.h b/run-as/package.h
index 852af06..34603c0 100644
--- a/run-as/package.h
+++ b/run-as/package.h
@@ -30,6 +30,7 @@
     uid_t  uid;
     char   isDebuggable;
     char   dataDir[PATH_MAX];
+    char   seinfo[PATH_MAX];
 } PackageInfo;
 
 /* see documentation in package.c for these functiosn */
diff --git a/run-as/run-as.c b/run-as/run-as.c
index 20e1530..3c0ecc4 100644
--- a/run-as/run-as.c
+++ b/run-as/run-as.c
@@ -29,6 +29,7 @@
 #include <time.h>
 #include <stdarg.h>
 
+#include <selinux/android.h>
 #include <private/android_filesystem_config.h>
 #include "package.h"
 
@@ -162,6 +163,11 @@
         return 1;
     }
 
+    if (selinux_android_setcontext(uid, 0, info.seinfo, pkgname) < 0) {
+        panic("Could not set SELinux security context:  %s\n", strerror(errno));
+        return 1;
+    }
+
     /* User specified command for exec. */
     if (argc >= 3 ) {
         if (execvp(argv[2], argv+2) < 0) {
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 8d87ee9..bff6e67 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -28,6 +28,8 @@
 #include <limits.h>
 #include <ctype.h>
 #include <pthread.h>
+#include <sys/time.h>
+#include <sys/resource.h>
 
 #include <private/android_filesystem_config.h>
 
@@ -1305,6 +1307,7 @@
     gid_t gid = 0;
     int num_threads = DEFAULT_NUM_THREADS;
     int i;
+    struct rlimit rlim;
 
     for (i = 1; i < argc; i++) {
         char* arg = argv[i];
@@ -1353,6 +1356,12 @@
         return usage();
     }
 
+    rlim.rlim_cur = 8192;
+    rlim.rlim_max = 8192;
+    if (setrlimit(RLIMIT_NOFILE, &rlim)) {
+        ERROR("Error setting RLIMIT_NOFILE, errno = %d\n", errno);
+    }
+
     res = run(source_path, dest_path, uid, gid, num_threads);
     return res < 0 ? 1 : 0;
 }
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index dbbce06..c764690 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -58,6 +58,7 @@
 	lsof \
 	du \
 	md5 \
+	clear \
 	getenforce \
 	setenforce \
 	chcon \
@@ -87,6 +88,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
+	liblog \
 	libc \
 	libusbhost \
 	libselinux
diff --git a/toolbox/clear.c b/toolbox/clear.c
new file mode 100644
index 0000000..df46ad2
--- /dev/null
+++ b/toolbox/clear.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    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
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * 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
+ * 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
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+
+int clear_main(int argc, char **argv) {
+    /* This prints the clear screen and move cursor to top-left corner control
+     * characters for VT100 terminals. This means it will not work on
+     * non-VT100 compliant terminals, namely Windows' cmd.exe, but should
+     * work on anything unix-y. */
+    fputs("\x1b[2J\x1b[H", stdout);
+    return 0;
+}
diff --git a/toolbox/dd.c b/toolbox/dd.c
index 350f1d2..a8c12d2 100644
--- a/toolbox/dd.c
+++ b/toolbox/dd.c
@@ -590,8 +590,8 @@
 
 	/* If not a pipe or tape device, try to seek on it. */
 	if (!(in.flags & (ISPIPE|ISTAPE))) {
-		if (lseek(in.fd,
-		    (off_t)in.offset * (off_t)in.dbsz, SEEK_CUR) == -1) {
+		if (lseek64(in.fd,
+		    (off64_t)in.offset * (off64_t)in.dbsz, SEEK_CUR) == -1) {
 			fprintf(stderr, "%s: seek error: %s",
 				in.name, strerror(errno));
 			exit(1);
@@ -661,8 +661,8 @@
 	 * have specified the seek operand.
 	 */
 	if (!(out.flags & ISTAPE)) {
-		if (lseek(out.fd,
-		    (off_t)out.offset * (off_t)out.dbsz, SEEK_SET) == -1) {
+		if (lseek64(out.fd,
+		    (off64_t)out.offset * (off64_t)out.dbsz, SEEK_SET) == -1) {
 			fprintf(stderr, "%s: seek error: %s\n",
 				out.name, strerror(errno));
 			exit(1);
diff --git a/toolbox/dmesg.c b/toolbox/dmesg.c
index e57f607..9c73b00 100644
--- a/toolbox/dmesg.c
+++ b/toolbox/dmesg.c
@@ -5,15 +5,30 @@
 #include <sys/klog.h>
 #include <string.h>
 
-#define KLOG_BUF_SHIFT	17	/* CONFIG_LOG_BUF_SHIFT from our kernel */
-#define KLOG_BUF_LEN	(1 << KLOG_BUF_SHIFT)
+#define FALLBACK_KLOG_BUF_SHIFT	17	/* CONFIG_LOG_BUF_SHIFT from our kernel */
+#define FALLBACK_KLOG_BUF_LEN	(1 << FALLBACK_KLOG_BUF_SHIFT)
 
 int dmesg_main(int argc, char **argv)
 {
-    char buffer[KLOG_BUF_LEN + 1];
-    char *p = buffer;
+    char *buffer;
+    char *p;
     ssize_t ret;
-    int n, op;
+    int n, op, klog_buf_len;
+
+    klog_buf_len = klogctl(KLOG_SIZE_BUFFER, 0, 0);
+
+    if (klog_buf_len <= 0) {
+        klog_buf_len = FALLBACK_KLOG_BUF_LEN;
+    }
+
+    buffer = (char *)malloc(klog_buf_len + 1);
+
+    if (!buffer) {
+        perror("malloc");
+        return EXIT_FAILURE;
+    }
+
+    p = buffer;
 
     if((argc == 2) && (!strcmp(argv[1],"-c"))) {
         op = KLOG_READ_CLEAR;
@@ -21,7 +36,7 @@
         op = KLOG_READ_ALL;
     }
 
-    n = klogctl(op, buffer, KLOG_BUF_LEN);
+    n = klogctl(op, buffer, klog_buf_len);
     if (n < 0) {
         perror("klogctl");
         return EXIT_FAILURE;
diff --git a/toolbox/du.c b/toolbox/du.c
index 06374a4..fc7c943 100644
--- a/toolbox/du.c
+++ b/toolbox/du.c
@@ -62,7 +62,7 @@
 
 int	linkchk(dev_t, ino_t);
 void	prstat(const char *, int64_t);
-void	usage(void);
+static void	usage(void);
 
 long blocksize;
 
@@ -312,7 +312,7 @@
 	return 0;
 }
 
-void
+static void
 usage(void)
 {
 
diff --git a/toolbox/ls.c b/toolbox/ls.c
index e530521..5324511 100644
--- a/toolbox/ls.c
+++ b/toolbox/ls.c
@@ -28,6 +28,7 @@
 #define LIST_LONG_NUMERIC   (1 << 5)
 #define LIST_CLASSIFY       (1 << 6)
 #define LIST_MACLABEL       (1 << 7)
+#define LIST_INODE          (1 << 8)
 
 // fwd
 static int listpath(const char *name, int flags);
@@ -127,22 +128,20 @@
     return 0;
 }
 
-static int listfile_size(const char *path, const char *filename, int flags)
+static int listfile_size(const char *path, const char *filename, struct stat *s,
+                         int flags)
 {
-    struct stat s;
-
-    if (lstat(path, &s) < 0) {
-        fprintf(stderr, "lstat '%s' failed: %s\n", path, strerror(errno));
+    if(!s || !path) {
         return -1;
     }
 
     /* blocks are 512 bytes, we want output to be KB */
     if ((flags & LIST_SIZE) != 0) {
-        printf("%lld ", s.st_blocks / 2);
+        printf("%lld ", s->st_blocks / 2);
     }
 
     if ((flags & LIST_CLASSIFY) != 0) {
-        char filetype = mode2kind(s.st_mode);
+        char filetype = mode2kind(s->st_mode);
         if (filetype != 'l') {
             printf("%c ", filetype);
         } else {
@@ -161,15 +160,18 @@
     return 0;
 }
 
-static int listfile_long(const char *path, int flags)
+static int listfile_long(const char *path, struct stat *s, int flags)
 {
-    struct stat s;
     char date[32];
     char mode[16];
     char user[16];
     char group[16];
     const char *name;
 
+    if(!s || !path) {
+        return -1;
+    }
+
     /* name is anything after the final '/', or the whole path if none*/
     name = strrchr(path, '/');
     if(name == 0) {
@@ -178,36 +180,32 @@
         name++;
     }
 
-    if(lstat(path, &s) < 0) {
-        return -1;
-    }
-
-    mode2str(s.st_mode, mode);
+    mode2str(s->st_mode, mode);
     if (flags & LIST_LONG_NUMERIC) {
-        sprintf(user, "%ld", s.st_uid);
-        sprintf(group, "%ld", s.st_gid);
+        sprintf(user, "%ld", s->st_uid);
+        sprintf(group, "%ld", s->st_gid);
     } else {
-        user2str(s.st_uid, user);
-        group2str(s.st_gid, group);
+        user2str(s->st_uid, user);
+        group2str(s->st_gid, group);
     }
 
-    strftime(date, 32, "%Y-%m-%d %H:%M", localtime((const time_t*)&s.st_mtime));
+    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)
 
-    switch(s.st_mode & S_IFMT) {
+    switch(s->st_mode & S_IFMT) {
     case S_IFBLK:
     case S_IFCHR:
         printf("%s %-8s %-8s %3d, %3d %s %s\n",
                mode, user, group,
-               (int) MAJOR(s.st_rdev), (int) MINOR(s.st_rdev),
+               (int) MAJOR(s->st_rdev), (int) MINOR(s->st_rdev),
                date, name);
         break;
     case S_IFREG:
         printf("%s %-8s %-8s %8lld %s %s\n",
-               mode, user, group, s.st_size, date, name);
+               mode, user, group, s->st_size, date, name);
         break;
     case S_IFLNK: {
         char linkto[256];
@@ -237,15 +235,18 @@
     return 0;
 }
 
-static int listfile_maclabel(const char *path, int flags)
+static int listfile_maclabel(const char *path, struct stat *s, int flags)
 {
-    struct stat s;
     char mode[16];
     char user[16];
     char group[16];
     char *maclabel = NULL;
     const char *name;
 
+    if(!s || !path) {
+        return -1;
+    }
+
     /* name is anything after the final '/', or the whole path if none*/
     name = strrchr(path, '/');
     if(name == 0) {
@@ -254,20 +255,16 @@
         name++;
     }
 
-    if(lstat(path, &s) < 0) {
-        return -1;
-    }
-
     lgetfilecon(path, &maclabel);
     if (!maclabel) {
         return -1;
     }
 
-    mode2str(s.st_mode, mode);
-    user2str(s.st_uid, user);
-    group2str(s.st_gid, group);
+    mode2str(s->st_mode, mode);
+    user2str(s->st_uid, user);
+    group2str(s->st_gid, group);
 
-    switch(s.st_mode & S_IFMT) {
+    switch(s->st_mode & S_IFMT) {
     case S_IFLNK: {
         char linkto[256];
         ssize_t len;
@@ -301,7 +298,9 @@
 
 static int listfile(const char *dirname, const char *filename, int flags)
 {
-    if ((flags & (LIST_LONG | LIST_SIZE | LIST_CLASSIFY | LIST_MACLABEL)) == 0) {
+    struct stat s;
+
+    if ((flags & (LIST_LONG | LIST_SIZE | LIST_CLASSIFY | LIST_MACLABEL | LIST_INODE)) == 0) {
         printf("%s\n", filename);
         return 0;
     }
@@ -316,12 +315,20 @@
         pathname = filename;
     }
 
+    if(lstat(pathname, &s) < 0) {
+        return -1;
+    }
+
+    if(flags & LIST_INODE) {
+        printf("%8llu ", s.st_ino);
+    }
+
     if ((flags & LIST_MACLABEL) != 0) {
-        return listfile_maclabel(pathname, flags);
+        return listfile_maclabel(pathname, &s, flags);
     } else if ((flags & LIST_LONG) != 0) {
-        return listfile_long(pathname, flags);
+        return listfile_long(pathname, &s, flags);
     } else /*((flags & LIST_SIZE) != 0)*/ {
-        return listfile_size(pathname, filename, flags);
+        return listfile_size(pathname, filename, &s, flags);
     }
 }
 
@@ -456,6 +463,7 @@
                     case 'Z': flags |= LIST_MACLABEL; break;
                     case 'a': flags |= LIST_ALL; break;
                     case 'F': flags |= LIST_CLASSIFY; break;
+                    case 'i': flags |= LIST_INODE; break;
                     default:
                         fprintf(stderr, "%s: Unknown option '-%c'. Aborting.\n", "ls", arg[0]);
                         exit(1);
diff --git a/toolbox/mount.c b/toolbox/mount.c
index b7adce2..bcda2a2 100644
--- a/toolbox/mount.c
+++ b/toolbox/mount.c
@@ -19,7 +19,7 @@
 #define LOOPDEV_MAXLEN 64
 
 struct mount_opts {
-	const char str[8];
+	const char str[16];
 	unsigned long rwmask;
 	unsigned long rwset;
 	unsigned long rwnoset;
@@ -65,10 +65,11 @@
 static void add_extra_option(struct extra_opts *extra, char *s)
 {
 	int len = strlen(s);
-	int newlen = extra->used_size + len;
+	int newlen;
 
 	if (extra->str)
 	       len++;			/* +1 for ',' */
+	newlen = extra->used_size + len;
 
 	if (newlen >= extra->alloc_size) {
 		char *new;
@@ -79,7 +80,7 @@
 
 		extra->str = new;
 		extra->end = extra->str + extra->used_size;
-		extra->alloc_size = newlen;
+		extra->alloc_size = newlen + 1;
 	}
 
 	if (extra->used_size) {
diff --git a/toolbox/netstat.c b/toolbox/netstat.c
index 5768599..05dc640 100644
--- a/toolbox/netstat.c
+++ b/toolbox/netstat.c
@@ -108,7 +108,7 @@
             addr2str(AF_INET, &raddr, rport, rip);
 
             printf("%4s  %6d %6d %-22s %-22s %s\n",
-                   label, txq, rxq, lip, rip,
+                   label, rxq, txq, lip, rip,
                    state2str(state));
         }
     }
@@ -136,7 +136,7 @@
             addr2str(AF_INET6, &raddr6, rport, rip);
 
             printf("%4s  %6d %6d %-22s %-22s %s\n",
-                   label, txq, rxq, lip, rip,
+                   label, rxq, txq, lip, rip,
                    state2str(state));
         }
     }
diff --git a/toolbox/renice.c b/toolbox/renice.c
index 978b329..9dfeb51 100644
--- a/toolbox/renice.c
+++ b/toolbox/renice.c
@@ -35,11 +35,12 @@
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <sched.h>
+#include <getopt.h>
 
 static void
 usage(const char *s)
 {
-    fprintf(stderr, "USAGE: %s [[-r] priority pids ...] [-g pid]\n", s);
+    fprintf(stderr, "USAGE: %s [[-r] [-t TYPE] priority pids ...] [-g pid]\n", s);
     exit(EXIT_FAILURE);
 }
 
@@ -74,32 +75,49 @@
            sched_get_priority_min(sched), sched_get_priority_max(sched));
 }
 
+int get_sched(char *str)
+{
+    if (strcasecmp(str, "RR") == 0)
+        return SCHED_RR;
+    else if (strcasecmp(str, "FIFO") == 0)
+        return SCHED_FIFO;
+    else if (strcasecmp(str, "NORMAL") == 0)
+        return SCHED_OTHER;
+    else if (strcasecmp(str, "OTHER") == 0)
+        return SCHED_OTHER;
+    return SCHED_RR;
+}
+
 int renice_main(int argc, char *argv[])
 {
     int prio;
     int realtime = 0;
+    int opt;
+    int sched = SCHED_RR;
     char *cmd = argv[0];
 
-    // consume command name
-    argc--;
-    argv++;
-
-    if (argc < 1)
-        usage(cmd);
-
-    if(strcmp("-r", argv[0]) == 0) {
-        // do realtime priority adjustment
-        realtime = 1;
-        argc--;
-        argv++;
-    }
-
-	if(strcmp("-g", argv[0]) == 0) {
-        if (argc < 2)
+    do {
+        opt = getopt(argc, argv, "rt:g:");
+        if (opt == -1)
+            break;
+        switch (opt) {
+        case 'r':
+            // do realtime priority adjustment
+            realtime = 1;
+            break;
+        case 't':
+            sched = get_sched(optarg);
+            break;
+        case 'g':
+            print_prio(atoi(optarg));
+            return 0;
+        default:
             usage(cmd);
-        print_prio(atoi(argv[1]));
-        return 0;
-    }
+        }
+    } while (1);
+
+    argc -= optind;
+    argv += optind;
 
     if (argc < 1)
         usage(cmd);
@@ -122,7 +140,7 @@
             struct sched_param sp = { .sched_priority = prio };
             int ret;
 
-            ret = sched_setscheduler(pid, SCHED_RR, &sp);
+            ret = sched_setscheduler(pid, sched, &sp);
             if (ret) {
                 perror("sched_set_scheduler");
                 exit(EXIT_FAILURE);
@@ -137,8 +155,6 @@
             }
         }
     }
-   
+
     return 0;
 }
-
-
diff --git a/toolbox/setsebool.c b/toolbox/setsebool.c
index 4a3d87d..f79a612 100644
--- a/toolbox/setsebool.c
+++ b/toolbox/setsebool.c
@@ -9,35 +9,26 @@
 #include <errno.h>
 
 static int do_setsebool(int nargs, char **args) {
-    SELboolean *b = alloca(nargs * sizeof(SELboolean));
-    char *v;
-    int i;
+    const char *name = args[1];
+    const char *value = args[2];
+    SELboolean b;
 
     if (is_selinux_enabled() <= 0)
         return 0;
 
-    for (i = 1; i < nargs; i++) {
-        char *name = args[i];
-        v = strchr(name, '=');
-        if (!v) {
-            fprintf(stderr, "setsebool: argument %s had no =\n", name);
-            return -1;
-        }
-        *v++ = 0;
-        b[i-1].name = name;
-        if (!strcmp(v, "1") || !strcasecmp(v, "true") || !strcasecmp(v, "on"))
-            b[i-1].value = 1;
-        else if (!strcmp(v, "0") || !strcasecmp(v, "false") || !strcasecmp(v, "off"))
-            b[i-1].value = 0;
-        else {
-            fprintf(stderr, "setsebool: invalid value %s\n", v);
-            return -1;
-        }
+    b.name = name;
+    if (!strcmp(value, "1") || !strcasecmp(value, "true") || !strcasecmp(value, "on"))
+        b.value = 1;
+    else if (!strcmp(value, "0") || !strcasecmp(value, "false") || !strcasecmp(value, "off"))
+        b.value = 0;
+    else {
+        fprintf(stderr, "setsebool: invalid value %s\n", value);
+        return -1;
     }
 
-    if (security_set_boolean_list(nargs - 1, b, 0) < 0)
+    if (security_set_boolean_list(1, &b, 0) < 0)
     {
-        fprintf(stderr, "setsebool: unable to set booleans: %s", strerror(errno));
+        fprintf(stderr, "setsebool: could not set %s to %s:  %s", name, value, strerror(errno));
         return -1;
     }
 
@@ -46,8 +37,8 @@
 
 int setsebool_main(int argc, char **argv)
 {
-    if (argc < 2) {
-        fprintf(stderr, "Usage:  %s name=value...\n", argv[0]);
+    if (argc != 3) {
+        fprintf(stderr, "Usage:  %s name value\n", argv[0]);
         exit(1);
     }
 
diff --git a/toolbox/watchprops.c b/toolbox/watchprops.c
index d311992..bf82882 100644
--- a/toolbox/watchprops.c
+++ b/toolbox/watchprops.c
@@ -1,35 +1,30 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <time.h>
+#include <errno.h>
 
 #include <cutils/properties.h>
+#include <cutils/hashmap.h>
 
 #include <sys/atomics.h>
 
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
 #include <sys/_system_properties.h>
 
-
-extern prop_area *__system_property_area__;
-
-typedef struct pwatch pwatch;
-
-struct pwatch
+static int str_hash(void *key)
 {
-    const prop_info *pi;
-    unsigned serial;
-};
+    return hashmapHash(key, strlen(key));
+}
 
-static pwatch watchlist[1024];
-
-static void announce(const prop_info *pi)
+static bool str_equals(void *keyA, void *keyB)
 {
-    char name[PROP_NAME_MAX];
-    char value[PROP_VALUE_MAX];
+    return strcmp(keyA, keyB) == 0;
+}
+
+static void announce(char *name, char *value)
+{
     char *x;
     
-    __system_property_read(pi, name, value);
-
     for(x = value; *x; x++) {
         if((*x < 32) || (*x > 127)) *x = '.';
     }
@@ -37,40 +32,64 @@
     fprintf(stderr,"%10d %s = '%s'\n", (int) time(0), name, value);
 }
 
+static void add_to_watchlist(Hashmap *watchlist, const char *name,
+        const prop_info *pi)
+{
+    char *key = strdup(name);
+    unsigned *value = malloc(sizeof(unsigned));
+    if (!key || !value)
+        exit(1);
+
+    *value = __system_property_serial(pi);
+    hashmapPut(watchlist, key, value);
+}
+
+static void populate_watchlist(const prop_info *pi, void *cookie)
+{
+    Hashmap *watchlist = cookie;
+    char name[PROP_NAME_MAX];
+    char value_unused[PROP_VALUE_MAX];
+
+    __system_property_read(pi, name, value_unused);
+    add_to_watchlist(watchlist, name, pi);
+}
+
+static void update_watchlist(const prop_info *pi, void *cookie)
+{
+    Hashmap *watchlist = cookie;
+    char name[PROP_NAME_MAX];
+    char value[PROP_VALUE_MAX];
+    unsigned *serial;
+
+    __system_property_read(pi, name, value);
+    serial = hashmapGet(watchlist, name);
+    if (!serial) {
+        add_to_watchlist(watchlist, name, pi);
+        announce(name, value);
+    } else {
+        unsigned tmp = __system_property_serial(pi);
+        if (*serial != tmp) {
+            *serial = tmp;
+            announce(name, value);
+        }
+    }
+}
+
 int watchprops_main(int argc, char *argv[])
 {
-    prop_area *pa = __system_property_area__;
-    unsigned serial = pa->serial;
-    unsigned count = pa->count;
+    unsigned serial = 0;
+    unsigned count = 0;
     unsigned n;
     
-    if(count >= 1024) exit(1);
+    Hashmap *watchlist = hashmapCreate(1024, str_hash, str_equals);
+    if (!watchlist)
+        exit(1);
 
-    for(n = 0; n < count; n++) {
-        watchlist[n].pi = __system_property_find_nth(n);
-        watchlist[n].serial = watchlist[n].pi->serial;
-    }
+    __system_property_foreach(populate_watchlist, watchlist);
 
     for(;;) {
-        do {
-            __futex_wait(&pa->serial, serial, 0);
-        } while(pa->serial == serial);
-
-        while(count < pa->count){
-            watchlist[count].pi = __system_property_find_nth(count);
-            watchlist[count].serial = watchlist[n].pi->serial;
-            announce(watchlist[count].pi);
-            count++;
-            if(count == 1024) exit(1);
-        }
-
-        for(n = 0; n < count; n++){
-            unsigned tmp = watchlist[n].pi->serial;
-            if(watchlist[n].serial != tmp) {
-                announce(watchlist[n].pi);
-                watchlist[n].serial = tmp;
-            }
-        }
+        serial = __system_property_wait_any(serial);
+        __system_property_foreach(update_watchlist, watchlist);
     }
     return 0;
 }